From: Josh Cheek Date: 2013-03-13T22:05:52+09:00 Subject: Re: cannot get blocks working --e89a8f22bcc3abcac504d7cdf77b Content-Type: text/plain; charset=ISO-8859-1 On Wed, Mar 13, 2013 at 7:30 AM, Aashish Kiran wrote: > Hi, > Below is the piece of code. Can anyone help in getting expected output. > > > ------------------------------------------------------------ > > class XmlDoc > def method_missing(name, *args, &block) > self.class.class_eval do > define_method(name) do |*args, &block| > if block_given? > temp = "<#{name}#{temp}>" + block.call + "" > else > "<#{name}>" > end > end > end > send(name, *args, &block) > end > end > > x = XmlDoc.new > > > p '1111111111111111111' > p x.hello > #expected output "" > > p x.hello{"dolly"} > #expected output "dolly" > > ----------------------------------------------------------------------- > > Thanks, > Aashish > > -- > Posted via http://www.ruby-forum.com/. > > 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). Also, you should move the method definition out to a helper method, because the methods that this defines will capture the block sent to method_missing, which in turn capture their environments. Since they're becoming methods, they won't be garbage collected, so you run the risk of memory leaks. Moving it to a helper method will prevent capturing of the block. Also, when doing metaprogramming, it's usually best to use __send__ instead of send (to avoid potential namespace conflicts). I would probably write it like this (well, at this point in my life, I probably wouldn't write anything this dynamic, but whatever) class XmlDoc def self.define_node(name) define_method name do |*args, &block| block ||= lambda { '' } "<#{name}>" + block.call + "" end end def method_missing(name, *args, &block) self.class.define_node name __send__ name, *args, &block end end x = XmlDoc.new x.hello # => "" x.hello{"dolly"} # => "dolly" -Josh --e89a8f22bcc3abcac504d7cdf77b Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Wed, Mar 13, 2013 at 7:30 AM, Aashish Kiran <lists@ruby-forum.com> wrote:

Change `block_given?` to `block`.= The block_given? macro is checking if method_missing received a block. Sin= ce it didn't the first time you called x.hello, it never will (that sco= pe was enclosed).

Also, you should move the method definition out to a he= lper method, because the methods that this defines will capture the block s= ent to method_missing, which in turn capture their environments. Since they= 're becoming methods, they won't be garbage collected, so you run t= he risk of memory leaks. Moving it to a helper method will prevent capturin= g of the block.

Also, when doing metaprogramming, it's usually best= to use __send__ instead of send (to avoid potential namespace conflicts).<= /div>

I would probably write it like this (well, at this= point in my life, I probably wouldn't write anything this dynamic, but= whatever)


class XmlDoc
=A0 def self= .define_node(name)
=A0 =A0 define_method name do |*args, &blo= ck|
=A0 =A0 =A0 block ||=3D lambda { '' }
=A0 = =A0 =A0 "<#{name}>" + block.call + "</#{name}>&q= uot;
=A0 =A0 end
=A0 end
=A0=A0
=A0 def metho= d_missing(name, *args, &block)
=A0 =A0 self.class.define_node= name
=A0 =A0 __send__ name, *args, &block
=A0 end<= /div>
end

x =3D XmlDoc.new
x.hello =A0 =A0 =A0 =A0 =A0 = # =3D> "<hello></hello>"
x.hello{"d= olly"} =A0# =3D> "<hello>dolly</hello>"
=


-Josh
--e89a8f22bcc3abcac504d7cdf77b--