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’ }
}
text, pack, padx, …, are used as commands instead of key of a hash. tk
objects allow to use a kind of ruby dialect, valid only in the context
of that object.
I would like to reproduce that technique but I don’t find how. I have
already tried some code:
It doesn’t work, the interpreter (1.8.0) saying add_some_stuff doesn’t
exist. I have also tried this:
class Dialect
def add_some_stuff(stuff) @stuff = stuff
end
def show
p @stuff
end
end
var = Dialect.new
var.instance_eval {add_some_stuff(“Hello world!”); show}
It works but it uses an explicit call of instance_eval which I don’t
want to use. I have searched how to do the job the same way as with tk,
but I can’t find! Can anyone help please?
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…
shasckaw wrote:
Thanks for the help. I’ll try this the sooner I can.
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…
In my researches on the net for a possible solution, I’ve read some
discussions with Matz about adding some kind of macro programming in
Rite, the next ruby interpreter version.