Skip to content

Instantly share code, notes, and snippets.

@Frost
Created July 18, 2012 12:25
Show Gist options
  • Save Frost/3135900 to your computer and use it in GitHub Desktop.
Save Frost/3135900 to your computer and use it in GitHub Desktop.
Implementing one-shot methods in ruby
# 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
# 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
# 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