From: Joel VanderWerf Date: 2004-01-11T16:05:19+09:00 Subject: Re: How to reproduce the tk dialect? shasckaw wrote: > Hello, > when using tk, you can initialize tk objects with a block, example: > > TkLabel.new(root) { > text 'Hello, World!' > pack { padx 15 ; pady 15; side 'left' } > } Here's how Tk might do it, though I haven't studied the source. (I don't think there's any way around using #instance_eval.) class TkLabel def initialize(obj, &block) instance_eval(&block) if block end def text(str) @text = str end def pack(&block) @packing = Packer.new(&block) end attr_reader :packing class Packer def initialize(&block) instance_eval(&block) if block end def padx(x) @padx = x end def pady(y) @pady = y end def side(str) @side = str end end end root = nil label = TkLabel.new(root) { text 'Hello, World!' pack { padx 15 ; pady 15; side 'left' } } p label There are some drawbacks: - inside the block, all private methods and instance variables are accessible - you can't access from within the block attributes that are defined in the context outside the block: @x = 1 pack { padx @x # this is a different @x } instead, however, you can use local variables to "pass in" the value: temp_x = @x = 1 pack { padx temp_x } An alternative is: class Packer def initialize(&block) block.call(self) # or use yield end ... end which keeps the "self" context the same in the block, avoids exposing internal stuff, and gives you an object (passed to the block) which you can use to do the same methods (padx etc.). But it doesn't look as elegant... pack { |packer| packer.padx 15 } There are times when I wish ruby had some kind of hygienic macro... but then I think about reading/debugging code written in somebody's personal macrofied language...