Extending a Class Method in a Module

Is there a way to use class method in a module without extend it in rails?

Use Module#module_function to make a single function to be a module function:

module M
def m1; puts "m1"; end
def m2; puts "m2"; end
module_function :m2
end

or:

module M
def m1; puts "m1"; end
module_function # from now on all functions are defined as module_functions
def m2; puts "m2"; end
end

M.m1 #⇒ NoMethodError: undefined method `m1' for M:Module
M.m2 #⇒ "m2"

Extending a class method in a module

1) Cleaner/shorter

module ClassMethods
def wrap(method)
old = "_#{method}".to_sym
alias_method old, method
define_method method do |*args|
send(old, *args)
end
end
end

class Foo
extend ClassMethods

def bar(arg = 'foo')
puts arg
end

wrap :bar
end

As far as I know there is no way to achieve this without renaming. You could try to call super inside the define_method block. But first of all, a call to super from within a define_method will only succeed if you specify arguments explicitly, otherwise you receive an error. But even if you call e.g. super(*args), self in that context would be an instance of Foo. So a call to bar would go to the super classes of Foo, not be found and ultimately result in an error.

2) Yes, like so

define_method method do |def_val='foo', *rest|
send(old, def_val, *rest)
end

However, in Ruby 1.8 it is not possible to use a block in define_method, but this has been fixed for 1.9. If you are using 1.9, you could also use this

define_method method do |def_val='foo', *rest, &block|
send(old, def_val, *rest, &block)
end

3) No, unfortunately. alias_method requires the existence of the methods that it takes as input. As Ruby methods come into existence as they are parsed, the wrap call must be placed after the definition of bar otherwise alias_method would raise an exception.

Ruby: Do something when extending an instance with a module

You can define self.extended in the module:

module Mod
def self.extended(base)
raise "Cannot extend #{base}" unless base.is_a?(GoodKlass)
end

def hello
"Hello from Mod.\n"
end
end

extending class with modules containing class methods of the same name

module ModA
extend ActiveSupport::Concern

module ClassMethods
def bar
puts "this is method bar of ModA"
end

# grab UnboundMethod of ModA::ClassMethods::bar
a_bar = instance_method(:bar)

# using define_method to capture a_bar
define_method :extend_with_mod_a do
puts "extending #{self} with ModA"
# invoke ModA::ClassMethods::bar properly bound to the class being extended/included with ModA
a_bar.bind(self).call
end
end
end


Related Topics



Leave a reply



Submit