Skip to content

Instantly share code, notes, and snippets.

@JackDanger
Created March 3, 2009 17:50
Show Gist options
  • Save JackDanger/73425 to your computer and use it in GitHub Desktop.
Save JackDanger/73425 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby1.9
#
# In Javascript you can add a function to an object like so:
#
# obj.perform = function(){ ... stuff to do ...}
#
# But in Ruby 1.8 there's always been a problem where a method
# defined with `define_method` won't be able to take a block.
# So you'd never be able to do something like this:
#
# "my string".do_with_words = proc do |&block|
# self.split(' ').each do |word|
# block.call(word)
# end
# end
#
# Because the "proc do |&block|" was unsupported syntax. And blocks
# never got passed automatically so block_given? would always return
# false.
#
# But Ruby 1.9 allows the "proc do |&block|" syntax so we can now make
# Ruby go full prototype.
#
module RubyPrototype
def method_missing(method_name, *arguments, &block)
return super unless method_name.to_s =~ /=$/ &&
((1 == arguments.length) | block_given?)
(class << self; self; end).send :define_method,
method_name.to_s.chomp('='),
&block || arguments[0]
end
end
Object.send :include, RubyPrototype
###
[ Object,
Object.new,
Class,
(class C; self; end),
Module,
(module M; self; end),
Object.method(:send) # Even methods can have methods now
].each do |object|
begin
# we can assign a proc to the method
object.method_that_takes_block = proc do |name, &b|
print "+"
b.call(name)
end
# or simply call the /=$/ form of the method while passing a block
object.send :more_direct= do |&b|
print "+"
b.call(self)
end
object.method_that_takes_block 'some value' do |*args|
print '+'
end
object.more_direct {|same_object| print '+'}
puts " works on #{object}"
rescue => e
puts " fails on #{object} with #{e.inspect}"
end
end
## Output (when run with ruby1.9):
#++++ works on Object
#++++ works on #<Object:0x1f0dec>
#++++ works on Class
#++++ works on C
#++++ works on Module
#++++ works on M
#++++ works on #<Method: Class(Kernel)#send>
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment