How to implement Ruby's extend module in JavaScript
This seems to work for me:
> class Test { test1(){ console.log("test1") }}
> class Other { test2() { console.log("test2") }}
> test = new Test
Test {}
> other = new Other
Other {}
> test.test1()
test1
> test["test2"] = other.test2
> test.test2()
test2
An instance is really just an array of functions (in this case). So, when you call:
other.test2
It returns the test2
element of other
which is the function test2
. And this:
> test["test2"] = other.test2
just add that function to the array of functions for test
. Which you can then call with:
> test.test2()
How is the ruby's extend syntax work?
In the first snippet you call extend
during class declaration, i. e. on Toy
object, which is apparently a class. It is the same as calling Toy.extend(Discount)
.
In the second snippet you extend
the Toy.new
, which is apparently a Toy
instance.
Include vs extend within another module
extend - adds the specified module's methods and constants to the target's metaclass (i.e. the singleton class)
e.g.
- if you call
Klazz.extend(Mod)
, now Klazz has Mod's methods (as class methods) - if you call
obj.extend(Mod)
, now obj has Mod's methods (as instance methods), but no other instance of ofobj.class
has those methods. extend
is a public method
include - By default, it mixes in the specified module's methods as instance methods in the target module/class.
e.g.
- if you call
class Klazz; include Mod; end;
, now all instances of Klazz have access to Mod's methods (as instance methods) include
is a private method, because it's intended to be called from within the container class/module.
However, modules very often override include
's behavior by monkey-patching the included
method. This is very prominent in legacy Rails code. more details from Yehuda Katz.
Further details about include
, with its default behavior, assuming you've run the following code
class Klazz
include Mod
end
- If Mod is already included in Klazz, or one of its ancestors, the include statement has no effect
- It also includes Mod's constants in Klazz, as long as they don't clash
- It gives Klazz access to Mod's module variables, e.g.
@@foo
or@@bar
- raises ArgumentError if there are cyclic includes
- Attaches the module as the caller's immediate ancestor (i.e. It adds Mod to Klazz.ancestors, but Mod is not added to the chain of Klazz.superclass.superclass.superclass. So, calling
super
in Klazz#foo will check for Mod#foo before checking to Klazz's real superclass's foo method. See the RubySpec for details.).
Of course, the ruby core documentation is always the best place to go for these things. The RubySpec project is also a fantastic resource, because they document the functionality precisely.
include RubySpec rubydoc
included RubySpec rubydoc
extend RubySpec rubydoc
extended RubySpec rubydoc
extend_object RubySpec rubydoc
append_features RubySpec rubydoc
ref: John
Extend and Include
module Foo
def self.included(base)
base.extend Foo::ClassMethods
end
module ClassMethods
def guitar
"gently weeps"
end
end
end
class Bar
include Foo
end
puts Bar.guitar
Ruby extend & include tracing code
When you extend
a module, the methods in that module become "class methods"**. So, when you extend Inventoryable
, create
becomes available as a method on the Shirt
class.
When you include
a module, the methods in that module become "instance methods"**. So, when you include Inventoryable
, create
is not available on the Shirt
class (but is available on an instance of Shirt
).
To make create
available on the Shirt
class when using include
, you can use the included
hook. That might look something like:
module Inventoryable
module ClassMethods
def create
puts "create!"
end
end
module InstanceMethods
end
def self.included(receiver)
receiver.extend ClassMethods
receiver.include InstanceMethods
end
end
Then if you do:
class Shirt
include Invetoryable
end
You can do:
> Shirt.create
create!
=> nil
** The ruby purists in the crowd will correctly point out that, in ruby, everything is an instance method and that there are no class methods. That is formally 100% correct, but we'll use the colloquial meaning of class
and instance
methods here.
How can I dynamically add/extend methods from a Class?
module ExtendRubyEdit
def self.included(base)
base.extend(ClassMethods)
end
def draw
end
def event
end
module ClassMethods
def redraw
end
end
end
class RubyEdit
include ExtendRubyEdit
end
How to extend a class within a Ruby module
module OilyPNG
class Canvas < ChunkyPNG::Canvas # You must match the superclass when opening class and adding more definitions
def your_method
puts "hello"
end
include Hola # this will "insert" the Hola module at this point in the code... not sure what Hola contains so, not sure if that works or not.
end
end
Looking at the source for OilyPNG the above should work...
Not sure why you got that error. Given this works here is why: You have to match the classes, super class when reopening it.
Based on this article: http://www.rubyinside.com/how-to-create-a-ruby-extension-in-c-in-under-5-minutes-100.html by the great Peter Cooper, I believe you should be using rb_define_method
, not rb_define_singleton_method
If you are still having trouble, start with peter's example, then adapt it to your needs.
How do I extend a Ruby class inside a module?
You're close.
module Wireshark
module File
def write_header
self.puts '/* ' + Wireshark::AUTOGEN_LABEL + ' */'
self.puts '/* ' + Wireshark::timestamp + ' */'
end
end
# Extend File with the methods in the Wireshark::File module
::File.send :include, Wireshark::File
# Read a file
def read
begin
file = ::File.read 'file'
rescue IOError
STDERR.puts 'Error reading file.'
return
end
end
end
The general idea here is that we define a Wireshark::File
module that holds the methods you want to include on the File
class, then you can just include them on File directly.
You'll also notice that in the read
method, I changed File
to ::File
. Ruby will walk up the tree to try to find the nearest matching value for a given constant, so since you are in the Wireshark
module, and there is a constant named File
in that scope, using just File
gets you Wireshark::File
. Specifying ::File
means "The File
constant at the top-level namespace".
Related Topics
Elliptic Curve Cryptography with Sjcl in Js and Openssl in Ruby
How to Disable Browser Developer Tools
How to Get the Selected Radio Button Value Using Js
Cannot Set Boolean Values in Localstorage
How to Set State Inside a Useeffect Hook
Invert Y Axis of L:Crs.Simple Map on Vue2-Leaflet
Stop a Youtube Video with Jquery
How to Use JavaScript Variables in Ruby
How Might I Extract the Property Values of a JavaScript Object into an Array
In iOS8 Using .Focus() Will Show Virtual Keyboard and Scroll Page After Touch
JavaScript Keycode VS Charcode
Implement JavaScript Alert and Confirm on Wkuidelegate Swiftui
Triggering Onclick Event Using Middle Click
Jquery Beforeunload When Closing (Not Leaving) the Page
iOS Uiwebview JavaScript - Insert Data -Receive Callbacks
Get Column from a Two Dimensional Array
How to Update Single Value Inside Specific Array Item in Redux