Created
July 18, 2012 12:25
-
-
Save Frost/3135900 to your computer and use it in GitHub Desktop.
Implementing one-shot methods in ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# With this method, once(:method) has to be called after the method has been added | |
module Once | |
def once(method) | |
method = method.to_s | |
class_eval <<-EVAL_END | |
alias_method :#{method}_once, :#{method} | |
def #{method}(*args) | |
result = send('#{method}_once', *args) | |
self.class.send(:remove_method, '#{method}_once') | |
self.class.send(:remove_method, '#{method}') | |
return result | |
end | |
EVAL_END | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# With this method, once(:method) has to be called before the method has been added | |
module Once2 | |
def once(*methods) | |
(@once_methods ||= []) << [*methods] | |
@once_methods.flatten! | |
end | |
def method_added(method) | |
return unless (@once_methods ||= []).include?(method) | |
@once_methods.delete(method) | |
old_method = instance_method(method) | |
define_method(method) do |*args, &block| | |
result = old_method.bind(self).call(*args, &block) | |
self.class.send(:remove_method, method) | |
result | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# irb -r ./once_1.rb -r ./once_2.rb | |
class Foo | |
extend Once | |
def foo | |
"bar" | |
end | |
once :foo | |
end | |
class Foo2 | |
extend Once2 | |
once :foo, :bar | |
def foo | |
"foo method" | |
end | |
def bar | |
"bar method" | |
end | |
end | |
ruby-1.9.2-p290 :002 > x = Foo.new | |
=> #<Foo:0x007f842216f168> | |
ruby-1.9.2-p290 :003 > x.foo | |
=> "bar" | |
ruby-1.9.2-p290 :004 > x.foo | |
NoMethodError: undefined method `foo' for #<Foo:0x007f842216f168> | |
from (irb):4 | |
from /Users/development/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>' | |
ruby-1.9.2-p290 :005 > x = Foo2.new | |
=> #<Foo2:0x007f84230068c0> | |
ruby-1.9.2-p290 :006 > x.foo | |
=> "foo method" | |
ruby-1.9.2-p290 :007 > x.foo | |
NoMethodError: undefined method `foo' for #<Foo2:0x007f84230068c0> | |
from (irb):7 | |
from /Users/development/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>' | |
ruby-1.9.2-p290 :006 > x.bar | |
=> "bar method" | |
ruby-1.9.2-p290 :007 > x.bar | |
NoMethodError: undefined method `bar' for #<Foo2:0x007f84230068c0> | |
from (irb):7 | |
from /Users/development/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>' | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment