Related
It is possible to add methods to a class using modules. E.g.,
class Test
include Singleton
end
Is it possible to do the same with methods? E.g.,
class Test
include Singleton
def test
include Instructions_to_add_to_the_method
puts 'done'
end
end
where:
module Instructions_to_add_to_the_method
puts 'hi !'
end
When calling Test.instance.test, I want:
hi !
done
I do not wish to call another method, as it would give me issues with the scope of my variables.
It is possible to add methods to a class using modules. E.g.,
class Test
include Singleton
end
No. This does not "add methods to a class". include simply makes Singleton the superclass of Test. Nothing more. Nothing is being "added to a class". It's just inheritance.
Is it possible to do the same with methods? E.g.,
class Test
include Singleton
def test
include Instructions_to_add_to_the_method
puts 'done'
end
end
There is no method Test#include, so this will simply raise a NoMethodError.
When calling Test.instance.test, I want:
hi !
done
That's what inheritance is for:
class Test
include Singleton
def test
super
puts 'done'
end
end
module Instructions_to_add_to_the_method
def test
puts 'hi'
end
end
class Test
include Instructions_to_add_to_the_method
end
Test.instance.test
# hi
# done
Note that this way of using inheritance in Ruby is a little bit backward. If you really need something like this, you should use a language like Beta, where this is how inheritance works naturally.
A better solution would be something like the Template Method Software Design Pattern which in Ruby can be something as simple as yielding to a block:
class Test
include Singleton
def test
yield
puts 'done'
end
end
Test.instance.test { puts 'hi' }
# hi
# done
or taking a Proc as an argument:
class Test
include Singleton
def test(prc)
prc.()
puts 'done'
end
end
Test.instance.test(-> { puts 'hi' })
# hi
# done
or by calling a hook method:
class Test
include Singleton
def test
extension_hook
puts 'done'
end
def extension_hook; end
end
class HookedTest < Test
def extension_hook
puts 'hi'
end
end
HookedTest.instance.test
# hi
# done
I do not wish to call another method, as it would give me issues with the scope of my variables.
There are no variables in your code, so there can't possibly be any "issues" with them.
This is probably a terrible idea. Messing with your classes at run-time will make problems hard to debug (which version of that method was I calling there?) and your code hard to follow (oh, right, I can't call that method yet because it's not defined yet, I need to call this method first).
Given what you said at the end of your question about variable scoping, I'm almost certain that this won't solve the problem you actually have, and I'd suggest actually posting your actual problem.
That said, the question you asked can be answered by using the included and extended hooks which, unsurprisingly, fire when a module gets included and extended:
module FooModule
def self.included(base)
puts 'FooModule included'
end
def self.extended(base)
puts 'FooModule extended'
end
def new_method
puts 'new method called'
end
end
class Extender
def test_extend
self.extend FooModule
puts 'done'
end
end
class Includer
def test_include
self.class.include FooModule
puts 'done'
end
end
t1 = Extender.new
t2 = Extender.new
t1.test_extend # Prints out "FooModule extended" followed by "done"
t1.new_method # Prints out "new method called"
t2.new_method rescue puts 'error' # Prints out "error" - extend only modifies the instance that calls it
t1 = Includer.new
t2 = Includer.new
t1.test_include # Prints out "FooModule included" followed by "done"
t1.new_method # Prints out "new method called"
t2.new_method # Prints out "new method called" - all past and future instances of Includer have been modified
I have to add methods to Class in execution time.
class ExtendableClass
end
The methods to add are declared in independent Classes.
module ExtensionClassOne
def method_one
end
end
module ExtensionClassTwo
def method_two
end
end
I'm looking for an (elegant) mechanism to add all the extension class methods into the ExtendableClass.
Approach 1
I'm thinking in explicily include the extension classes like:
ExtendableClass.send( :include, ExtensionClassOne )
ExtendableClass.send( :include, ExtensionClassTwo )
but it looks a little forced to have to call this private method every time I define a new extension class.
Approach 2
So I was looking for an automatic way to include this methods into my ExtendableClass class.
I'm thinking in declare an specific ancestor for this extension classes:
class ExtensionClassOne < Extension
def method_one
end
end
and then I'd need a mechanism to know all the childs of a class... something like the oposite of ancestors.
Once I have this list I can easily ExtendableClass.include all the list of classes. Even if I have to call to the private method here.
Approach 3
Also inheriting from the Extension class and detect in declaration time when this class is used as ancestor. In the way that the ActiveSupport.included method works, like an event binding. Then make the include there.
Any solution for implement approach 2 or approach 3? Do you recommend approach 1? New approachs?
#fguillen, you are right that the "explicit way is the cleanest approach". Since that is so, why don't you use the most "explicit" code which could be imagined:
class Extendable
end
class Extendable
def method_one
puts "method one"
end
end
class Extendable
def method_two
puts "method two"
end
end
...In other words, if you are defining a module which will be automatically included in a class as soon as it is defined, why bother with the module at all? Just add your "extension" methods directly to the class!
Approach 4 would be to define a macro on class level in Object
class Object
def self.enable_extension
include InstanceExtension
extend ClassExtension
end
end
and calling this macro in all your classes you want to be extended.
class Bacon
enable_extension
end
Car.enable_extension
This way,
you don't have to use #send to circumvent encapsulation (Approach 1)
you can inherit from any Class you want, because everything inherits from Object anyway (except 1.9's BasicObject)
the usage of your extension is declarative and not hidden in some hook
Downside: you monkeypatch build-in Classes and may break the world. Choose long and decriptive names.
Edit: Given your answer to my comment on the question I suppose this is not what you wanted. I see no problem with your "Approach 1" in this case; it's what I'd do. Alternatively, instead of using send to bypass the private method, just re-open the class:
class ExtendableClass
include ExtensionOne
end
Assuming I understand what you want, I'd do this:
module DelayedExtension
def later_include( *modules )
(#later_include||=[]).concat( modules )
end
def later_extend( *modules )
(#later_extend||=[]).concat( modules )
end
def realize_extensions # better name needed
include *#later_include unless !#later_include || #later_include.empty?
extend *#later_extend unless !#later_extend || #later_extend.empty?
end
end
module ExtensionOne
end
module ExtensionTwo
def self.included(klass)
klass.extend ClassMethods
end
module ClassMethods
def class_can_do_it!; end
end
end
class ExtendableClass
extend DelayedExtension
later_include ExtensionOne, ExtensionTwo
end
original_methods = ExtendableClass.methods
p ExtendableClass.ancestors
#=> [ExtendableClass, Object, Kernel, BasicObject]
ExtendableClass.realize_extensions
p ExtendableClass.ancestors
#=> [ExtendableClass, ExtensionOne, ExtensionTwo, Object, Kernel, BasicObject]
p ExtendableClass.methods - original_methods
#=> [:class_can_do_it!]
The included method is actually a hook. It is called whenever you are inherited from:
module Extensions
def someFunctionality()
puts "Doing work..."
end
end
class Foo
def self.inherited(klass)
klass.send(:include, Extensions) #Replace self with a different module if you want
end
end
class Bar < Foo
end
Bar.new.someFunctionality #=> "Doing work..."
There is also the included hook, which is called when you are included:
module Baz
def self.included(klass)
puts "Baz was included into #{klass}"
end
end
class Bork
include Baz
end
Output:
Baz was included into Bork
A very tricky solution, I think too much over-engineering, would be to take the inherited hook that #Linux_iOS.rb.cpp.c.lisp.m.sh has commented and keep all and every child class in a Set and combined it with the #Mikey Hogarth proposition of method_missing to look for all this child class methods every time I call a method in the Extendable class. Something like this:
# code simplified and no tested
# extendable.rb
class Extendable
##delegators = []
def self.inherited( klass )
##delegators << klass
end
def self.method_missing
# ... searching in all ##delegators methods
end
end
# extensions/extension_one.rb
class ExtensionOne < Extendable
def method_one
end
end
But the logic of the method_missing (and respond_to?) is gonna be very complicate and dirty.
I don't like this solution, just let it here to study it like a possibility.
After a very interesting propositions you have done I have realized that the explicit way is the cleanest approach. If we add a few recommendations taking from your answers I think I'm gonna go for this:
# extendable.rb
class Extendable
def self.plug( _module )
include( _module )
end
end
# extensions/extension_one.rb
module ExtensionOne
def method_one
puts "method one"
end
end
Extendable.plug( ExtensionOne )
# extensions/extension_two.rb
module ExtensionTwo
def method_two
puts "method two"
end
end
Extendable.plug( ExtensionTwo )
# result
Extendable.new.method_one # => "method one"
Extendable.new.method_two # => "method two"
How can I force a subclass to implement a method in Ruby. There doesn't seem to be an abstract keyword in Ruby, which is the approach I would take in Java. Is there another more Ruby-like way to enforce abstract?
Abstract methods are supposed to be less useful in Ruby because it's not strongly statically typed.
However, this is what I do:
class AbstractThing
MESS = "SYSTEM ERROR: method missing"
def method_one; raise MESS; end
def method_two; raise MESS; end
end
class ConcreteThing < AbstractThing
def method_one
puts "hi"
end
end
a = ConcreteThing.new
a.method_two # -> raises error.
It rarely seems to be necessary, however.
I like the answer by pvandenberk, but I would improve it as follows:
module Canine # in Ruby, abstract classes are known as modules
def bark
fail NotImplementedError, "A canine class must be able to #bark!"
end
end
Now if you make a class belonging to Canine "abstract class" (ie. a class that has Canine module in its ancestors), it will complain if it is found that #bark method is not implemented:
class Dog
include Canine # make dog belong to Canine "abstract class"
end
Dog.new.bark # complains about #bark not being implemented
class Dog
def bark; "Bow wow!" end
end
# Now it's OK:
Dog.new.bark #=> "Bow wow!"
Note that since Ruby classes are not static, but always open to changes, Dog class itself cannot enforce existence of #bark methods, since it doesn't know when is it supposed to be finished. If you as a programmer do, it is up to you to test it at such time.
My preferred approach is similar but slightly different... I prefer it as follows, because it makes the code self-documenting, giving you something very similar to Smalltalk:
class AbstractThing
def method_one; raise "SubclassResponsibility" ; end
def method_two; raise "SubclassResponsibility" ; end
def non_abstract_method; method_one || method_two ; end
end
Some people will complain that this is less DRY, and insist on creating an exception subclass and/or put the "SubclassResponsibility" string in a constant, but IMHO you can dry things up to the point of being chafed, and that is not usually a good thing. E.g. if you have multiple abstract classes across your code base, where would you define the MESS string constant?!?
I like the use of a gem like abstract_method which gives a dsl rails style syntax abstract methods:
class AbstractClass
abstract_method :foo
end
class AbstractModule
abstract_method :bar
end
class ConcreteClass < AbstractClass
def foo
42
end
end
This code will not let you load the class if the methods 'foo', 'bar' and 'mate' are not defined in the inherited class.
It does not account for classes being defined across many files, but lets get honest do many of us actually define class methods across many files? I mean if you don't count mix-ins. (which this does account for)
def self.abstract(*methods_array)
##must_abstract ||= []
##must_abstract = Array(methods_array)
end
def self.inherited(child)
trace = TracePoint.new(:end) do |tp|
if tp.self == child #modules also trace end we only care about the class end
trace.disable
missing = ( Array(##must_abstract) - child.instance_methods(false) )
raise NotImplementedError, "#{child} must implement the following method(s) #{missing}" if missing.present?
end
end
trace.enable
end
abstract :foo
abstract :bar, :mate
If you want to have an error thrown when you create an instance of the class you could do the following
class AbstractClass
def self.new(args)
instance = allocate # make memory space for a new object
instance.send(:default_initialize, args)
instance.send(:initialize, args)
instance
end
#This is called whenever object created, regardless of whether 'initialize' is overridden
def default_initialize(args)
self.abstract_method #This will raise error upon object creation
end
private :default_initialize
def initialize(args)
# This can be overridden by new class
end
end
class NewClass < AbstractClass
end
NewClass.new #Throw error
Because the question is (focus on) "How can I force a subclass to implement a method in Ruby", so i think we can use TDD :D, for example: rspec shared example
shared_examples "MUST implement abstract method" do |method_sym|
it { is_expected.to respond_to(method_sym) }
end
describe Stack do
it_behaves_like "MUST implement abstract method", :push
it_behaves_like "MUST implement abstract method", :pop
end
Maybe Tests are better than Abstract :D , reference: http://morningcoffee.io/interfaces-in-ruby.html
EDIT: I slightly changed the spec, to better match what I imagined this to do.
Well, I don't really want to fake C# attributes, I want to one-up-them and support AOP as well.
Given the program:
class Object
def Object.profile
# magic code here
end
end
class Foo
# This is the fake attribute, it profiles a single method.
profile
def bar(b)
puts b
end
def barbar(b)
puts(b)
end
comment("this really should be fixed")
def snafu(b)
end
end
Foo.new.bar("test")
Foo.new.barbar("test")
puts Foo.get_comment(:snafu)
Desired output:
Foo.bar was called with param: b = "test"
test
Foo.bar call finished, duration was 1ms
test
This really should be fixed
Is there any way to achieve this?
I have a somewhat different approach:
class Object
def self.profile(method_name)
return_value = nil
time = Benchmark.measure do
return_value = yield
end
puts "#{method_name} finished in #{time.real}"
return_value
end
end
require "benchmark"
module Profiler
def method_added(name)
profile_method(name) if #method_profiled
super
end
def profile_method(method_name)
#method_profiled = nil
alias_method "unprofiled_#{method_name}", method_name
class_eval <<-ruby_eval
def #{method_name}(*args, &blk)
name = "\#{self.class}##{method_name}"
msg = "\#{name} was called with \#{args.inspect}"
msg << " and a block" if block_given?
puts msg
Object.profile(name) { unprofiled_#{method_name}(*args, &blk) }
end
ruby_eval
end
def profile
#method_profiled = true
end
end
module Comment
def method_added(name)
comment_method(name) if #method_commented
super
end
def comment_method(method_name)
comment = #method_commented
#method_commented = nil
alias_method "uncommented_#{method_name}", method_name
class_eval <<-ruby_eval
def #{method_name}(*args, &blk)
puts #{comment.inspect}
uncommented_#{method_name}(*args, &blk)
end
ruby_eval
end
def comment(text)
#method_commented = text
end
end
class Foo
extend Profiler
extend Comment
# This is the fake attribute, it profiles a single method.
profile
def bar(b)
puts b
end
def barbar(b)
puts(b)
end
comment("this really should be fixed")
def snafu(b)
end
end
A few points about this solution:
I provided the additional methods via modules which could be extended into new classes as needed. This avoids polluting the global namespace for all modules.
I avoided using alias_method, since module includes allow AOP-style extensions (in this case, for method_added) without the need for aliasing.
I chose to use class_eval rather than define_method to define the new method in order to be able to support methods that take blocks. This also necessitated the use of alias_method.
Because I chose to support blocks, I also added a bit of text to the output in case the method takes a block.
There are ways to get the actual parameter names, which would be closer to your original output, but they don't really fit in a response here. You can check out merb-action-args, where we wrote some code that required getting the actual parameter names. It works in JRuby, Ruby 1.8.x, Ruby 1.9.1 (with a gem), and Ruby 1.9 trunk (natively).
The basic technique here is to store a class instance variable when profile or comment is called, which is then applied when a method is added. As in the previous solution, the method_added hook is used to track when the new method is added, but instead of removing the hook each time, the hook checks for an instance variable. The instance variable is removed after the AOP is applied, so it only applies once. If this same technique was used multiple time, it could be further abstracted.
In general, I tried to stick as close to your "spec" as possible, which is why I included the Object.profile snippet instead of implementing it inline.
Great question. This is my quick attempt at an implementation (I did not try to optimise the code). I took the liberty of adding the profile method to the
Module class. In this way it will be available in every class and module definition. It would be even better
to extract it into a module and mix it into the class Module whenever you need it.
I also didn't know if the point was to make the profile method behave like Ruby's public/protected/private keywords,
but I implemented it like that anyway. All methods defined after calling profile are profiled, until noprofile is called.
class Module
def profile
require "benchmark"
#profiled_methods ||= []
class << self
# Save any original method_added callback.
alias_method :__unprofiling_method_added, :method_added
# Create new callback.
def method_added(method)
# Possible infinite loop if we do not check if we already replaced this method.
unless #profiled_methods.include?(method)
#profiled_methods << method
unbound_method = instance_method(method)
define_method(method) do |*args|
puts "#{self.class}##{method} was called with params #{args.join(", ")}"
bench = Benchmark.measure do
unbound_method.bind(self).call(*args)
end
puts "#{self.class}##{method} finished in %.5fs" % bench.real
end
# Call the original callback too.
__unprofiling_method_added(method)
end
end
end
end
def noprofile # What's the opposite of profile?
class << self
# Remove profiling callback and restore previous one.
alias_method :method_added, :__unprofiling_method_added
end
end
end
You can now use it as follows:
class Foo
def self.method_added(method) # This still works.
puts "Method '#{method}' has been added to '#{self}'."
end
profile
def foo(arg1, arg2, arg3 = nil)
puts "> body of foo"
sleep 1
end
def bar(arg)
puts "> body of bar"
end
noprofile
def baz(arg)
puts "> body of baz"
end
end
Call the methods as you would normally:
foo = Foo.new
foo.foo(1, 2, 3)
foo.bar(2)
foo.baz(3)
And get benchmarked output (and the result of the original method_added callback just to show that it still works):
Method 'foo' has been added to 'Foo'.
Method 'bar' has been added to 'Foo'.
Method 'baz' has been added to 'Foo'.
Foo#foo was called with params 1, 2, 3
> body of foo
Foo#foo finished in 1.00018s
Foo#bar was called with params 2
> body of bar
Foo#bar finished in 0.00016s
> body of baz
One thing to note is that it is impossible to dynamically get the name of the arguments with Ruby meta-programming.
You'd have to parse the original Ruby file, which is certainly possible but a little more complex. See the parse_tree and ruby_parser
gems for details.
A fun improvement would be to be able to define this kind of behaviour with a class method in the Module class. It would be cool to be able to do something like:
class Module
method_wrapper :profile do |*arguments|
# Do something before calling method.
yield *arguments # Call original method.
# Do something afterwards.
end
end
I'll leave this meta-meta-programming exercise for another time. :-)
Background:
I have a module which declares a number of instance methods
module UsefulThings
def get_file; ...
def delete_file; ...
def format_text(x); ...
end
And I want to call some of these methods from within a class. How you normally do this in ruby is like this:
class UsefulWorker
include UsefulThings
def do_work
format_text("abc")
...
end
end
Problem
include UsefulThings brings in all of the methods from UsefulThings. In this case I only want format_text and explicitly do not want get_file and delete_file.
I can see several possible solutions to this:
Somehow invoke the method directly on the module without including it anywhere
I don't know how/if this can be done. (Hence this question)
Somehow include Usefulthings and only bring in some of it's methods
I also don't know how/if this can be done
Create a proxy class, include UsefulThings in that, then delegate format_text to that proxy instance
This would work, but anonymous proxy classes are a hack. Yuck.
Split up the module into 2 or more smaller modules
This would also work, and is probably the best solution I can think of, but I'd prefer to avoid it as I'd end up with a proliferation of dozens and dozens of modules - managing this would be burdensome
Why are there lots of unrelated functions in a single module? It's ApplicationHelper from a rails app, which our team has de-facto decided on as the dumping ground for anything not specific enough to belong anywhere else. Mostly standalone utility methods that get used everywhere. I could break it up into seperate helpers, but there'd be 30 of them, all with 1 method each... this seems unproductive
I think the shortest way to do just throw-away single call (without altering existing modules or creating new ones) would be as follows:
Class.new.extend(UsefulThings).get_file
If a method on a module is turned into a module function you can simply call it off of Mods as if it had been declared as
module Mods
def self.foo
puts "Mods.foo(self)"
end
end
The module_function approach below will avoid breaking any classes which include all of Mods.
module Mods
def foo
puts "Mods.foo"
end
end
class Includer
include Mods
end
Includer.new.foo
Mods.module_eval do
module_function(:foo)
public :foo
end
Includer.new.foo # this would break without public :foo above
class Thing
def bar
Mods.foo
end
end
Thing.new.bar
However, I'm curious why a set of unrelated functions are all contained within the same module in the first place?
Edited to show that includes still work if public :foo is called after module_function :foo
Another way to do it if you "own" the module is to use module_function.
module UsefulThings
def a
puts "aaay"
end
module_function :a
def b
puts "beee"
end
end
def test
UsefulThings.a
UsefulThings.b # Fails! Not a module method
end
test
If you want to call these methods without including module in another class then you need to define them as module methods:
module UsefulThings
def self.get_file; ...
def self.delete_file; ...
def self.format_text(x); ...
end
and then you can call them with
UsefulThings.format_text("xxx")
or
UsefulThings::format_text("xxx")
But anyway I would recommend that you put just related methods in one module or in one class. If you have problem that you want to include just one method from module then it sounds like a bad code smell and it is not good Ruby style to put unrelated methods together.
To invoke a module instance method without including the module (and without creating intermediary objects):
class UsefulWorker
def do_work
UsefulThings.instance_method(:format_text).bind(self).call("abc")
...
end
end
Not sure if someone still needs it after 10 years but I solved it using eigenclass.
module UsefulThings
def useful_thing_1
"thing_1"
end
class << self
include UsefulThings
end
end
class A
include UsefulThings
end
class B
extend UsefulThings
end
UsefulThings.useful_thing_1 # => "thing_1"
A.new.useful_thing_1 # => "thing_1"
B.useful_thing_1 # => "thing_1"
Firstly, I'd recommend breaking the module up into the useful things you need. But you can always create a class extending that for your invocation:
module UsefulThings
def a
puts "aaay"
end
def b
puts "beee"
end
end
def test
ob = Class.new.send(:include, UsefulThings).new
ob.a
end
test
A. In case you, always want to call them in a "qualified", standalone way (UsefulThings.get_file), then just make them static as others pointed out,
module UsefulThings
def self.get_file; ...
def self.delete_file; ...
def self.format_text(x); ...
# Or.. make all of the "static"
class << self
def write_file; ...
def commit_file; ...
end
end
B. If you still want to keep the mixin approach in same cases, as well the one-off standalone invocation, you can have a one-liner module that extends itself with the mixin:
module UsefulThingsMixin
def get_file; ...
def delete_file; ...
def format_text(x); ...
end
module UsefulThings
extend UsefulThingsMixin
end
So both works then:
UsefulThings.get_file() # one off
class MyUser
include UsefulThingsMixin
def f
format_text # all useful things available directly
end
end
IMHO it's cleaner than module_function for every single method - in case want all of them.
As I understand the question, you want to mix some of a module's instance methods into a class.
Let's begin by considering how Module#include works. Suppose we have a module UsefulThings that contains two instance methods:
module UsefulThings
def add1
self + 1
end
def add3
self + 3
end
end
UsefulThings.instance_methods
#=> [:add1, :add3]
and Fixnum includes that module:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
We see that:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
Were you expecting UsefulThings#add3 to override Fixnum#add3, so that 1.add3 would return 4? Consider this:
Fixnum.ancestors
#=> [Fixnum, UsefulThings, Integer, Numeric, Comparable,
# Object, Kernel, BasicObject]
When the class includes the module, the module becomes the class' superclass. So, because of how inheritance works, sending add3 to an instance of Fixnum will cause Fixnum#add3 to be invoked, returning dog.
Now let's add a method :add2 to UsefulThings:
module UsefulThings
def add1
self + 1
end
def add2
self + 2
end
def add3
self + 3
end
end
We now wish Fixnum to include only the methods add1 and add3. Is so doing, we expect to get the same results as above.
Suppose, as above, we execute:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
What is the result? The unwanted method :add2 is added to Fixnum, :add1 is added and, for reasons I explained above, :add3 is not added. So all we have to do is undef :add2. We can do that with a simple helper method:
module Helpers
def self.include_some(mod, klass, *args)
klass.send(:include, mod)
(mod.instance_methods - args - klass.instance_methods).each do |m|
klass.send(:undef_method, m)
end
end
end
which we invoke like this:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
Helpers.include_some(UsefulThings, self, :add1, :add3)
end
Then:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
which is the result we want.
After almost 9 years here's a generic solution:
module CreateModuleFunctions
def self.included(base)
base.instance_methods.each do |method|
base.module_eval do
module_function(method)
public(method)
end
end
end
end
RSpec.describe CreateModuleFunctions do
context "when included into a Module" do
it "makes the Module's methods invokable via the Module" do
module ModuleIncluded
def instance_method_1;end
def instance_method_2;end
include CreateModuleFunctions
end
expect { ModuleIncluded.instance_method_1 }.to_not raise_error
end
end
end
The unfortunate trick you need to apply is to include the module after the methods have been defined. Alternatively you may also include it after the context is defined as ModuleIncluded.send(:include, CreateModuleFunctions).
Or you can use it via the reflection_utils gem.
spec.add_dependency "reflection_utils", ">= 0.3.0"
require 'reflection_utils'
include ReflectionUtils::CreateModuleFunctions
This old question comes to me today when I am studing Ruby and found interesting so I want to answer with my new knowlege.
Assume that you have the module
module MyModule
def say
'I say'
end
def cheer
'I cheer'
end
end
then with the class so call Animal I can take cheer method from MyModule as following
class Animal
define_method(:happy, MyModule.method(:cheer))
end
This is so called unbound method, so you can take a callable object and bind it to another place(s).
From this point, you can use the method as usual, such as
my_dog = Animal.new
my_dog.happy # => "I cheer"
Hope this help as I also learned something new today.
To learn further, you can use irb and take a look at Method object.