define_method multiple times with the same name - ruby

I've written a little wrapper over method_missing like this:
module Util
def method_missing_for(regex, &blk1)
define_method(:method_missing) do |name, *args, &blk2|
match = name.to_s.scan(regex).flatten[0]
if match
blk1.call(match, *args, &blk2)
else
super(name, *args, &blk2)
end
end
end
end
Then using it:
class Foo
extend Util
method_missing_for(/^say_(.+)$/){ |word| puts word }
end
Foo.new.say_hello
# => "hello"
The problem is that I cannot call this multiple times for a class. The method_missing I add with define_method just gets overridden. What alternative do I have? Conceptually I know I can refactor method_missing_for to take multiple regex => block mappings and then call it once instead of multiple times. At its core it would be a big case statement which tests all the regex. But I would rather be able to take advantage of super.
class Foo
extend Util
method_missing_for(/^say_(.+)$/) { |word| puts word }
method_missing_for(/foobar/) {}
end
Foo.new.say_hello # => NoMethodError

The problem is that I cannot call this multiple times for a class. The method_missing I add with define_method just gets overridden.
No, it doesn't. It gets overwritten.
You already have the solution in that sentence: you need to override it instead:
module Util
def method_missing_for(regex, &blk1)
prepend(Module.new do
##################### this is the only change compared to your code
define_method(:method_missing) do |name, *args, &blk2|
match = name.to_s.scan(regex).flatten[0]
if match
blk1.(match, *args, &blk2)
else
super(name, *args, &blk2)
end
end
end)
####
end
end
class Foo
extend Util
method_missing_for(/^say_(.+)$/) { |word| puts word }
method_missing_for(/foobar/) {}
end
Foo.new.say_hello
# hello
Note: it may or may not be beneficial to name the module, so that it shows up with a sensible name in the ancestors chain, which improves the debugging experience:
Foo.ancestors
#=> [#<Module:0x007fa5fd800f98>, #<Module:0x007fa5fd801df8>, Foo, Object, Kernel, BasicObject]
See also When monkey patching a method, can you call the overridden method from the new implementation? for a more comprehensive treatment.

My idea is to register the definition when declaring, and define those methods when all the declaration is done. The usage will be a little bit different, but I think is still acceptable
class Foo
extend Util
phantom_methods do
method_missing_for(/^say_(.+)$/){ |word| puts word }
method_missing_for(/^foo_(.+)$/){ |word| puts word }
end
end
The implementation of Util will be
module Util
def phantom_methods
# Initialize the registration table
#_phantom_methods = {}
# Allow declaring methods
yield
# Consume the registration table and define a single `method_missing`
define_method(:method_missing) do |name, *args, &blk|
pair = self.class.instance_variable_get(:#_phantom_methods).find {|regexp, prc| name =~ regexp}
pair ? pair[1].call($1) : super(name, *args, &blk)
end
# Good practice to also define `respond_to_missing?`
define_method(:respond_to_missing?) do |name, include_private = false|
self.class.instance_variable_get(:#_phantom_methods).any? {|regexp, _| name =~ regexp}
end
end
# Declare a phantom method
def method_missing_for(regexp, &blk)
# Register the definition
#_phantom_methods[regexp] = blk
end
end
By the way, I borrowed the phrase phantom method from this book.

Related

How could I implement something like Rails' before_initialize/before_new in plain Ruby?

In Rails we can define a class like:
class Test < ActiveRecord::Base
before_initialize :method
end
and when calling Test.new, method() will be called on the instance. I'm trying to learn more about Ruby and class methods like this, but I'm having trouble trying to implement this in plain Ruby.
Here's what I have so far:
class LameAR
def self.before_initialize(*args, &block)
# somehow store the symbols or block to be called on init
end
def new(*args)
## Call methods/blocks here
super(*args)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end
I'm trying to figure out where to store the blocks in self.before_initialize. I originally tried an instance variable like #before_init_methods, but that instance variable wouldn't exist in memory at that point, so I couldn't store or retrieve from it. I'm not sure how/where could I store these blocks/procs/symbols during the class definition, to later be called inside of new.
How could I implement this? (Either having before_initialize take a block/proc/list of symbols, I don't mind at this point, just trying to understand the concept)
For a comprehensive description, you can always check the Rails source; it is itself implemented in 'plain Ruby', after all. (But it handles lots of edge cases, so it's not great for getting a quick overview.)
The quick version is:
module MyCallbacks
def self.included(klass)
klass.extend(ClassMethods) # we don't have ActiveSupport::Concern either
end
module ClassMethods
def initialize_callbacks
#callbacks ||= []
end
def before_initialize(&block)
initialize_callbacks << block
end
end
def initialize(*)
self.class.initialize_callbacks.each do |callback|
instance_eval(&callback)
end
super
end
end
class Tester
include MyCallbacks
before_initialize { puts "hello world" }
end
Tester.new
Left to the reader:
arguments
calling methods by name
inheritance
callbacks aborting a call and supplying the return value
"around" callbacks that wrap the original invocation
conditional callbacks (:if / :unless)
subclasses selectively overriding/skipping callbacks
inserting new callbacks elsewhere in the sequence
... but eliding all of those is what [hopefully] makes this implementation more approachable.
One way would be by overriding Class#new:
class LameAR
def self.before_initialize(*symbols_or_callables, &block)
#before_init_methods ||= []
#before_init_methods.concat(symbols_or_callables)
#before_init_methods << block if block
nil
end
def self.new(*args, &block)
obj = allocate
#before_init_methods.each do |symbol_or_callable|
if symbol_or_callable.is_a?(Symbol)
obj.public_send(symbol_or_callable)
else
symbol_or_callable.(obj)
end
end
obj.__send__(:initialize, *args, &block)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end

How to define an original name scope in module/class with Ruby

How to define an original name scope in module/class with Ruby
I want to implement class like the following:
module SomeModule
extend OriginalNameScope
scope(:some) do
def method1
puts 1
end
def method2
puts 2
end
end
end
class SomeClass
include SomeModule
end
c = SomeClass.new
# I want to call methods like the following:
c.some_method1
c.some_method2
How to implement the OriginalNameScope module? I found out to get the method definitions in this method, but I don't know how to redefine methods with a prefix scope.
module OriginalNameScope
def scope(name, &method_definition)
puts method_definition.class
# => Proc
end
end
This is actually just a combination of some simple standard Ruby metaprogramming patterns and idioms:
module OriginalNameScope
def scope(name)
singleton_class.prepend(Module.new do
define_method(:method_added) do |meth|
if name && !#__recursion_guard__
#__recursion_guard__ = meth
method = instance_method(meth)
undef_method(meth)
define_method(:"#{name}_#{meth}") do |*args, &block|
method.bind(self).(*args, &block)
end
end
#__recursion_guard__ = nil
super(meth)
end
end)
yield
end
end
I just slapped this together, there's probably a lot that can be improved (e.g. use Refinements) and simplified.

Ruby: automatically wrapping methods in event triggers

Heres what I have/want:
module Observable
def observers; #observers; end
def trigger(event, *args)
good = true
return good unless (#observers ||= {})[event]
#obersvers[event].each { |e| good = false and break unless e.call(self, args) }
good
end
def on(event, &block)
#obersvers ||= {}
#obersvers[event] ||= []
#observers[event] << block
end
end
class Item < Thing
include Observable
def pickup(pickuper)
return unless trigger(:before_pick_up, pickuper)
pickuper.add_to_pocket self
trigger(:after_pick_up, pickuper)
end
def drop(droper)
return unless trigger(:before_drop, droper)
droper.remove_from_pocket self
trigger(:after_drop, droper)
end
# Lots of other methods
end
# How it all should work
Item.new.on(:before_pickup) do |item, pickuper|
puts "Hey #{pickuper} thats my #{item}"
return false # The pickuper never picks up the object
end
While starting on trying to create a game in Ruby, I thought it would be great if it could be based all around Observers and Events. The problem is have to write all of these triggers seems to be a waste, as it seems like a lot of duplicated code. I feel there must be some meta programming method out there to wrap methods with functionality.
Ideal Sceanrio:
class CustomBaseObject
class << self
### Replace with correct meta magic
def public_method_called(name, *args, &block)
return unless trigger(:before_+name.to_sym, args)
yield block
trigger(:after_+name.to_sym, args)
end
###
end
end
And then I have all of my object inherit from this Class.
I'm still new to Ruby's more advanced meta programming subjects, so any knowledge about this type of thing would be awesome.
There are a several ways to do it with the help of metaprogramming magic. For example, you can define a method like this:
def override_public_methods(c)
c.instance_methods(false).each do |m|
m = m.to_sym
c.class_eval %Q{
alias #{m}_original #{m}
def #{m}(*args, &block)
puts "Foo"
result = #{m}_original(*args, &block)
puts "Bar"
result
end
}
end
end
class CustomBaseObject
def test(a, &block)
puts "Test: #{a}"
yield
end
end
override_public_methods(CustomBaseObject)
foo = CustomBaseObject.new
foo.test(2) { puts 'Block!' }
# => Foo
Test: 2
Block!
Bar
In this case, you figure out all the required methods defined in the class by using instance_methods and then override them.
Another way is to use so-called 'hook' methods:
module Overrideable
def self.included(c)
c.instance_methods(false).each do |m|
m = m.to_sym
c.class_eval %Q{
alias #{m}_original #{m}
def #{m}(*args, &block)
puts "Foo"
result = #{m}_original(*args, &block)
puts "Bar"
result
end
}
end
end
end
class CustomBaseObject
def test(a, &block)
puts "Test: #{a}"
yield
end
include Overrideable
end
The included hook, defined in this module, is called when you include that module. This requires that you include the module at the end of the class definition, because included should know about all the already defined methods. I think it's rather ugly :)

Ruby call method on all following def calls?

I've seen some code that makes a class method such that you can write
class_method :instance_method,
to alias instance_method and call it from in a wrapper method every time it is called. Is there a way to be able to call class_method and have it apply to all the following definition calls (like how private works)?
I don't quite understand your question. In the future, please provide a specification of what it is exactly that you are trying to do, preferably in the form of an executable testsuite, so that we can check for ourselves whether our answers really answer your question.
Are you perhaps talking about something like this?
module MethodHook
private
def class_method(m=nil)
return if #__recursing__ # prevent infinite recursion
return #__class_method__ = true unless m
#__recursing__ = true
old_m = instance_method(m)
define_method(m) do |*args, &block|
puts "before #{m}(#{args.join(', ')})" # wrap wrap wrap
old_m.bind(self).(*args, &block)
puts "after #{m}" # more wrapping
end
#__recursing__ = nil
end
def method_added(m)
class_method(m) if #__class_method__
super
end
end
Use like this:
class Foo
extend MethodHook
def unwrapped
puts __method__
end
class_method
def wrapped
puts __method__
end
end
f = Foo.new
f.unwrapped
# unwrapped
f.wrapped
# before wrapped()
# wrapped
# after wrapped
class Foo
class_method(:unwrapped)
end
f.unwrapped
# before unwrapped()
# wrapped
# after unwrapped

calling another method in super class in ruby

class A
def a
puts 'in #a'
end
end
class B < A
def a
b()
end
def b
# here i want to call A#a.
end
end
class B < A
alias :super_a :a
def a
b()
end
def b
super_a()
end
end
There's no nice way to do it, but you can do A.instance_method(:a).bind(self).call, which will work, but is ugly.
You could even define your own method in Object to act like super in java:
class SuperProxy
def initialize(obj)
#obj = obj
end
def method_missing(meth, *args, &blk)
#obj.class.superclass.instance_method(meth).bind(#obj).call(*args, &blk)
end
end
class Object
private
def sup
SuperProxy.new(self)
end
end
class A
def a
puts "In A#a"
end
end
class B<A
def a
end
def b
sup.a
end
end
B.new.b # Prints in A#a
If you don't explicitly need to call A#a from B#b, but rather need to call A#a from B#a, which is effectively what you're doing by way of B#b (unless you're example isn't complete enough to demonstrate why you're calling from B#b, you can just call super from within B#a, just like is sometimes done in initialize methods. I know this is kind of obvious, I just wanted to clarify for any Ruby new-comers that you don't have to alias (specifically this is sometimes called an "around alias") in every case.
class A
def a
# do stuff for A
end
end
class B < A
def a
# do some stuff specific to B
super
# or use super() if you don't want super to pass on any args that method a might have had
# super/super() can also be called first
# it should be noted that some design patterns call for avoiding this construct
# as it creates a tight coupling between the classes. If you control both
# classes, it's not as big a deal, but if the superclass is outside your control
# it could change, w/o you knowing. This is pretty much composition vs inheritance
end
end

Resources