From: Robert Klemme Date: 2013-03-14T03:04:18+09:00 Subject: Re: cannot get blocks working On Wed, Mar 13, 2013 at 2:05 PM, Josh Cheek wrote: > Change `block_given?` to `block`. The block_given? macro is checking if > method_missing received a block. Since it didn't the first time you called > x.hello, it never will (that scope was enclosed). Are you insinuating that I cannot define a method which will happily accept a block using define_method and block_given?? You cannot do it as the example shows: irb(main):001:0> class X irb(main):002:1> def self.doit irb(main):003:2> define_method :foo do |a| irb(main):004:3* b = block_given? irb(main):005:3> printf "block: %p\n", b irb(main):006:3> yield if b irb(main):007:3> end irb(main):008:2> end irb(main):009:1> end => nil irb(main):010:0> x = X.new => # irb(main):011:0> x.foo NoMethodError: undefined method `foo' for # from (irb):11 from /usr/bin/irb:12:in `
' irb(main):012:0> X.doit => # irb(main):013:0> x.foo ArgumentError: wrong number of arguments (0 for 1) from (irb):4:in `block in doit' from (irb):13 from /usr/bin/irb:12:in `
' irb(main):014:0> x.foo 1 block: false => nil irb(main):015:0> x.foo(1) { puts "block called" } block: false => nil irb(main):016:0> X.doit { puts "x" } => # irb(main):017:0> x.foo(1) { puts "block called" } block: true x => nil irb(main):018:0> x.foo(1) block: true x => nil Amazing: the block will be captured _even though it is never referenced explicitly_. Learn something new every day. :-) Thank you for that! > Also, you should move the method definition out to a helper method, because In this particular case I would not define a new method at all. Basically what happens here is that the class stores the history of tag names used as method names. I'd rather put the code of the new method in #method_missing class XmlDoc def method_missing(name, *args, &block) "<#{name}>".tap do |s| s << yield.to_s if block_given? end << "" end end irb(main):028:0> xd = XmlDoc.new => # irb(main):029:0> xd.foo { xd.bar { 123 } } => "123" Btw, I believe there exists a similar mechanism in Ruby already. http://builder.rubyforge.org/ And btw the reference to temp in the String (original solution) is useless because the variable is not yet defined at that location. Cheers robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/