Yield, binding

Hi,

I'm experimenting with Ruby by writing some kind of DSL.
I wonder if It is possible calling given block to a proc with different
binding
What I'm trying to achieve is something like this

class Table
  attr_accessor :name,
  def getBinding
     binding
  end
end

def table
  t = Table.new
  if block_given?
      yield # with t.getBinding
  end
  t
end

so I will be able to write (in DSL part)

table {
  name = "FirstTable"
  ...
}

instead of

table {|t|
  t.name = "FirstTable"
  ...
}

Thanks

Gokhan Ersumer

···

--
Posted via http://www.ruby-forum.com/.

the only way to do this is with eval.

def table(s = nil)
       t = Table.new
       eval(s, t.getBinding) if s
       t
end

table %q{
      name = "FirstTable"
}

···

On Apr 8, 2006, at 9:40 PM, Gokhan Ersumer wrote:

Hi,

I'm experimenting with Ruby by writing some kind of DSL.
I wonder if It is possible calling given block to a proc with different
binding
What I'm trying to achieve is something like this

class Table
  attr_accessor :name,
  def getBinding
     binding
  end
end

def table
  t = Table.new
  if block_given?
      yield # with t.getBinding
  end
  t
end

so I will be able to write (in DSL part)

table {
  name = "FirstTable"
  ...
}

instead of

table {|t|
  t.name = "FirstTable"
  ...
}

Thanks

Gokhan Ersumer

--
Posted via http://www.ruby-forum.com/\.

Gokhan Ersumer wrote:

I'm experimenting with Ruby by writing some kind of DSL.
I wonder if It is possible calling given block to a proc with different binding

I think you are looking for Object#instance_eval.

Note that in 1.8 there is no way to build-in way to execute a block in a different context and at the same time providing it with arguments.

In 1.9 it will be possible to do that with Object#instance_exec.

···

--
http://flgr.0x42.net/

You can't do 'name =', but if you don't mind a slightly different
setter syntax, you could use this:

class Table
  def name(new_name=nil)
    @name = new_name if new_name
    return @name
  end
end

def table(&blk)
  t = Table.new
  t.instance_eval(&blk) if block_given?
  return t
end

t = table{
  name "foo"
}

p t #=> #<Table:0x26210 @name="foo">

Paul.

···

On 09/04/06, Gokhan Ersumer <sky_khan@yahoo.com> wrote:

so I will be able to write (in DSL part)

table {
  name = "FirstTable"
  ...
}

instead of

table {|t|
  t.name = "FirstTable"
  ...
}

Thanks for the responses.

Now I'm able to read

table {
  name "foo"
  ...
}

syntax

···

--
Posted via http://www.ruby-forum.com/.

Hi --

···

On Sun, 9 Apr 2006, Florian GroÃ~_ wrote:

Gokhan Ersumer wrote:

I'm experimenting with Ruby by writing some kind of DSL.
I wonder if It is possible calling given block to a proc with different binding

I think you are looking for Object#instance_eval.

Note that in 1.8 there is no way to build-in way to execute a block in a different context and at the same time providing it with arguments.

In 1.9 it will be possible to do that with Object#instance_exec.

Do you know why there are going to be two methods, instead of just
adding argument capabilites to instance_eval? I'm also not sure how
'eval' vs. 'exec' expresses arguments vs. no arguments. Do you know
the reasoning behind it?

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!

dblack@wobblini.net wrote:

I think you are looking for Object#instance_eval.

Note that in 1.8 there is no way to build-in way to execute a block in a different context and at the same time providing it with arguments.

In 1.9 it will be possible to do that with Object#instance_exec.

Do you know why there are going to be two methods, instead of just
adding argument capabilites to instance_eval? I'm also not sure how
'eval' vs. 'exec' expresses arguments vs. no arguments. Do you know
the reasoning behind it?

Object#instance_eval used to pass self AFAIK. Making it pass arguments would either be an incompatible change or lead to a overly complex API.

I'm not sure about the exact reasoning about the names. I guess it is just because all eval methods don't pass arguments. And instance_exec kind of sounds related to instance_eval.

I can't think of a good name that expresses argument passing. instance_eval_with_args would work, but isn't good.

···

--
http://flgr.0x42.net/

Hi --

I think you are looking for Object#instance_eval.

Note that in 1.8 there is no way to build-in way to execute a block in a different context and at the same time providing it with arguments.

In 1.9 it will be possible to do that with Object#instance_exec.

Do you know why there are going to be two methods, instead of just
adding argument capabilites to instance_eval? I'm also not sure how
'eval' vs. 'exec' expresses arguments vs. no arguments. Do you know
the reasoning behind it?

Object#instance_eval used to pass self AFAIK. Making it pass arguments would either be an incompatible change or lead to a overly complex API.

I'm not sure about the exact reasoning about the names. I guess it is just because all eval methods don't pass arguments. And instance_exec kind of sounds related to instance_eval.

Yeah, "kind of"... :slight_smile:

I can't think of a good name that expresses argument passing. instance_eval_with_args would work, but isn't good.

I'm hoping there won't be too many of these "you just have to know it"
things in 2.0. Yes, Matz, I trust you! But there's been talk, at
least, of send vs. funcall, and instance_eval vs. instance_exec, both
being pairs of methods that do similar things but whose names don't
tell you which is which. It's easy for experienced Rubyists to
remember that "the new one is the one that does new stuff", but I
think that even a little of this could make learning Ruby a lot
harder.

Then again, I can't think of any perfect names (well, I liked send and
send! but Matz didn't :slight_smile: so I should shut up.

David

···

On Sun, 9 Apr 2006, Florian Groß wrote:

dblack@wobblini.net wrote:

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!

remember that "the new one is the one that does new stuff", but I

You want to say "the new one is the one that does old stuff", no ? :slight_smile:

moulon% /usr/bin/ruby -ve 'class A; def a() end; private :a end; A.new.send(:a)'
ruby 1.8.4 (2005-12-24) [i486-linux]
moulon%

moulon% ruby -ve 'class A; def a() end; private :a end; A.new.send(:a)'
ruby 1.9.0 (2006-03-15) [i686-linux]
-e:1:in `Kernel#send': private method `a' called for #<A:0xb7e3873c> (NoMethodError)
  from -e:1
moulon%

moulon% ruby -ve 'class A; def a() end; private :a end; A.new.funcall(:a)'
ruby 1.9.0 (2006-03-15) [i686-linux]
moulon%

Guy Decoux

dblack@wobblini.net wrote:

I'm hoping there won't be too many of these "you just have to know it"
things in 2.0. Yes, Matz, I trust you! But there's been talk, at
least, of send vs. funcall, and instance_eval vs. instance_exec, both
being pairs of methods that do similar things but whose names don't
tell you which is which. It's easy for experienced Rubyists to
remember that "the new one is the one that does new stuff", but I
think that even a little of this could make learning Ruby a lot
harder.

Then again, I can't think of any perfect names (well, I liked send and
send! but Matz didn't :slight_smile: so I should shut up.

Agreed, I also think changing the semantics of send() should be avoided. I'd have preferred introducing a version that has the access checks.

I do not even really like the name funcall().

Hm, perhaps redispatch()? forward()?

Perhaps send() could be able to call private methods if it isn't called with a receiver. That would allow for obj.instance_eval { send(:foo) }. Sounds somewhat obscure, though.

Sometimes I wonder if it would be better to just start using argument distinction a lot more.

lambda(:semantics => :block) { ... }
# Though I still prefer having a lambda(arg, *args) { } syntax for
# method semantics
lambda(:semantics => :method) { ... }

obj.send(:private, :function, ...)
obj.send(:public, :function, ...)
# OTOH mod.send(:private, :private, ...) is *very* odd

If Object#method would return a wrapper in case method_missing() is used one could do obj.method(:foo).call for calling private methods.

I do not really have a better suggestion for how to do this. I just wonder if send() being able to call private methods is really a problem.

I agree with you that differences you just have to know are a very bad thing. I like to distinguish different things with clear names.

Being a language designer isn't an easy job at all, I guess. Always needing to balance between the past and the future will make things very complex. And there's a lot more you need to keep balanced as well.

···

--
http://flgr.0x42.net/

Hi --

···

On Sun, 9 Apr 2006, ts wrote:

> remember that "the new one is the one that does new stuff", but I

You want to say "the new one is the one that does old stuff", no ? :slight_smile:

moulon% /usr/bin/ruby -ve 'class A; def a() end; private :a end; A.new.send(:a)'
ruby 1.8.4 (2005-12-24) [i486-linux]
moulon%

moulon% ruby -ve 'class A; def a() end; private :a end; A.new.send(:a)'
ruby 1.9.0 (2006-03-15) [i686-linux]
-e:1:in `Kernel#send': private method `a' called for #<A:0xb7e3873c> (NoMethodError)
  from -e:1
moulon%

moulon% ruby -ve 'class A; def a() end; private :a end; A.new.funcall(:a)'
ruby 1.9.0 (2006-03-15) [i686-linux]
moulon%

OK, then I take it back: it will be hard for new users AND old users
:slight_smile:

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!

Quoting florgro@gmail.com, on Sun, Apr 09, 2006 at 11:14:23PM +0900:

I do not really have a better suggestion for how to do this. I just
wonder if send() being able to call private methods is really a problem.

Me, too. ruby is pretty open, generally. You can specify your intentions
with a class design by using private, but there will always be a way
around it. I liked the old way, where explicit method calls couldn't
access private methods, but you could with send(), two levels of
distinction seemed good enough. 3 seems too many.

Cheers,
Sam