Where is the magic?

I’m learning Ruby and have found some interesting behaviour which I
cann’t understand myself yet.
Here’s some code and the output:
class Foo
def self.new(*args)
obj = super
yield
obj
end
end

Foo.new do
p self
end

Struct.new(“Foo”, :foo, :bar) do
p self
end

=> main
=> Struct::Foo

The first output is quite understandable because self is bounded to the
top-level class of the file and is sent to the closure.
But in the second line it seems that scope of self has been changed
somehow.
I’ve had a fast look on the source file struct.c and haven’t found
something special in the new method.
The same thing can also be found in the QtRuby bindings:
require ‘Qt4’

Qt::Application.new(ARGV) do
Qt::Widget.new do

    self.window_title = 'Hello QtRuby v1.0'
    resize(200, 100)

    button = Qt::PushButton.new('Quit') do
        connect(SIGNAL :clicked) { Qt::Application.instance.quit }
    end

    label = Qt::Label.new('<big>Hello Qt in the Ruby way!</big>')

    self.layout = Qt::VBoxLayout.new do
        add_widget(label, 0, Qt::AlignCenter)
        add_widget(button, 0, Qt::AlignRight)
    end

    show
end

exec

end

Please, could anybody explain me how does this work. Links will do too.
:slight_smile:

On 02/04/2010 11:33 AM, Ilya Lopatkin wrote:

Qt::Widget.new do
    self.layout = Qt::VBoxLayout.new do

Please, could anybody explain me how does this work. Links will do too.
:slight_smile:

Struct.new uses instance_eval internally:

irb(main):001:0> o = Object.new
=> #Object:0x9a93150
irb(main):002:0> o.instance_eval { p self }
#Object:0x9a93150
=> #Object:0x9a93150
irb(main):003:0> p self
main
=> main
irb(main):004:0>

An example more close to what Struct does:

irb(main):001:0> class Foo
irb(main):002:1> def initialize(&b)
irb(main):003:2> printf “in init: %p\n”, self
irb(main):004:2> instance_eval(&b)
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> Foo.new { printf “in block: %p\n”, self }
in init: #Foo:0x8e742e8
in block: #Foo:0x8e742e8
=> #Foo:0x8e742e8

Kind regards

robert

Robert K. wrote:

Struct.new uses instance_eval internally:

Thanks for your response. I’ve almost grasped the idea. :slight_smile:

Ilya Lopatkin wrote:

Robert K. wrote:

Struct.new uses instance_eval internally:

Thanks for your response. I’ve almost grasped the idea. :slight_smile:

Here’s an explanation is other words:

When you create a block you create a parcel that contains three things:

  • The code itself.
  • The “binding” (links to the surrounding variables).
  • The value of ‘self’ (this is how ruby knows which object to
    invoke methods on).

When you normally ‘yield’ to a block, the block uses the value of ‘self’
saved in that parcel. On the other hand, when you do
‘somebody.eval_instance()’, the ‘self’ in that parcel is set to
‘somebody’.

It is common in GUI frameworks to use eval_instance() to make the code
look like DSL (google for “DSL”).