Attr_writers within blocks

Hi all,

It seems writer methods don't work within blocks, the names are resolved to new local variable names I guess.
It is funny however the reader method does seem to work fine.
Is it possible to make it work anyway without changing the syntax within the block?

My example gist: http://gist.github.com/137741

Kind regards,
Wijnand

Hi,

It seems writer methods don't work within blocks, the names are resolved to
new local variable names I guess.
It is funny however the reader method does seem to work fine.
Is it possible to make it work anyway without changing the syntax within
the block?

My example gist: http://gist.github.com/137741

You don't even need an instance_eval. It won't work in a module
definition either:

  module M
    class <<self
      def x= val
        puts "Hi, here is C.x=(#{val.inspect})."
        @x = val
      end
    end
    @x = "X0"
    x = "X1"
    self.x = "X2"
  end

Maybe you prefer the self.-construction. I surely don't.

Bertram

···

Am Dienstag, 30. Jun 2009, 03:44:48 +0900 schrieb Wijnand Wiersma:

--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de

Hi all,

It seems writer methods don't work within blocks, the names are resolved to
new local variable names I guess.
It is funny however the reader method does seem to work fine.
Is it possible to make it work anyway without changing the syntax within
the block?

My example gist: http://gist.github.com/137741

You can override the getter method for a DSL-ish syntax:

class Foo
  attr_accessor :bar

  def initialize(&block)
    instance_eval(&block)
  end

  def bar(v=nil)
    v ? @bar = v : @bar
  end
end

f = Foo.new { bar 2 }
f.bar # => 2
f.bar 3
f.bar # => 3
f.bar = 4
f.bar # => 4

HTH
Mike

···

On Mon, Jun 29, 2009 at 2:44 PM, Wijnand Wiersma <wijnand@videre.net> wrote:

Kind regards,
Wijnand

Hi --

Hi all,

It seems writer methods don't work within blocks, the names are resolved to new local variable names I guess.
It is funny however the reader method does seem to work fine.
Is it possible to make it work anyway without changing the syntax within the block?

It's not a block thing. Writer methods always need an explicit
receiver. You always have to write:

   obj.x = y

because the parser always sees this:

   x = y

as a local variable assignment, even if there's a method around called
x=.

David

···

On Tue, 30 Jun 2009, Wijnand Wiersma wrote:

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2\)
"Ruby 1.9: What You Need To Know" Envycasts with David A. Black
http://www.envycasts.com

Thank you for your answers, I was too block focussed to see the obvious real reason.

Kind regards,
Wijnand

Hi,

···

Am Dienstag, 30. Jun 2009, 04:37:55 +0900 schrieb Mike Sassak:

On Mon, Jun 29, 2009 at 2:44 PM, Wijnand Wiersma <wijnand@videre.net> wrote:
  def bar(v=nil)
    v ? @bar = v : @bar
  end

Sorry, but I cannot leave this as it is (untested):

  def set_bar v = nil
    @bar ||= v
  end

Bertram

--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de

Well, on that note... After using metaid, I hate the class << self
construction.

module M
  meta_eval do
    def x= val
      ...
    end
  end
  ...
end

For what it's worth, attr_accessor does work inside meta_eval.

···

On Monday 29 June 2009 02:21:49 pm Bertram Scharpf wrote:

Maybe you prefer the self.-construction. I surely don't.

Hi --

Hi all,

It seems writer methods don't work within blocks, the names are resolved to
new local variable names I guess.
It is funny however the reader method does seem to work fine.
Is it possible to make it work anyway without changing the syntax within
the block?

My example gist: http://gist.github.com/137741

You can override the getter method for a DSL-ish syntax:

Assuming your DSL depends on the lack of equal-signs :slight_smile: There's
nothing inherent in the concept of a DSL that disallows =-terminated
methods or explicit receivers.

class Foo
attr_accessor :bar

No point defining #bar if you don't want it -- just use attr_writer.

def initialize(&block)
   instance_eval(&block)
end

def bar(v=nil)
   v ? @bar = v : @bar
end

That won't allow you to (re)set @bar to nil or false, though. You
might want something like:

   def bar(*v)
     unless v.empty?
       @bar, = v
     end
     @bar
   end

David

···

On Tue, 30 Jun 2009, Mike Sassak wrote:

On Mon, Jun 29, 2009 at 2:44 PM, Wijnand Wiersma <wijnand@videre.net> wrote:

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2\)
"Ruby 1.9: What You Need To Know" Envycasts with David A. Black
http://www.envycasts.com

I can only recommend this thread: http://www.ruby-forum.com/topic/190337
We had a nice discussion there on those kind of DSLish attr setters and
what would be the best way to implement them

Greetz,
k

P.S: metaid rocks!

Hi --

Hi,

  def bar(v=nil)
    v ? @bar = v : @bar
  end

Sorry, but I cannot leave this as it is (untested):

def set_bar v = nil
   @bar ||= v
end

That only sets @bar if @bar hasn't be set (to a true value) already.

class C
   attr_reader :bar
   def set_bar(v = nil)
     @bar ||= v
   end
end

c = C.new
c.set_bar(3)
puts c.bar # 3

c.set_bar(4)
puts c.bar # 3

David

···

On Tue, 30 Jun 2009, Bertram Scharpf wrote:

Am Dienstag, 30. Jun 2009, 04:37:55 +0900 schrieb Mike Sassak:

On Mon, Jun 29, 2009 at 2:44 PM, Wijnand Wiersma <wijnand@videre.net> wrote:

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2\)
"Ruby 1.9: What You Need To Know" Envycasts with David A. Black
http://www.envycasts.com

I actually like one of the proposed ways in that topic.
Using a method that is both getter and setter.
I decided to create a attr_accessor_special like this:
   def attr_accessor_special(*syms)
     syms.each do | sym |
       name=sym.to_s
       send(:define_method, name) do | *args |
         value = args[0]
         self.instance_variable_set("@#{name}", value) if value
         self.instance_variable_get("@#{name}")
       end
     end
   end

No way to make a value nil again but I don't think that will be needed in my case.

Thank you for your replies!

Kind regards,
Wijnand

···

Op 30 jun 2009, om 09:29 heeft Fabian Streitel het volgende geschreven:

I can only recommend this thread: Attr Methods and object setters - Ruby - Ruby-Forum
We had a nice discussion there on those kind of DSLish attr setters and
what would be the best way to implement them

Hi --

···

On Thu, 2 Jul 2009, Wijnand Wiersma wrote:

Op 30 jun 2009, om 09:29 heeft Fabian Streitel het volgende geschreven:

I can only recommend this thread: Attr Methods and object setters - Ruby - Ruby-Forum
We had a nice discussion there on those kind of DSLish attr setters and
what would be the best way to implement them

I actually like one of the proposed ways in that topic.
Using a method that is both getter and setter.
I decided to create a attr_accessor_special like this:
def attr_accessor_special(*syms)
  syms.each do | sym |
    name=sym.to_s
    send(:define_method, name) do | *args |
      value = args[0]
      self.instance_variable_set("@#{name}", value) if value
      self.instance_variable_get("@#{name}")
    end
  end
end

No way to make a value nil again but I don't think that will be needed in my case.

You could test to see whether args is empty (see my earlier post).

David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2\)
"Ruby 1.9: What You Need To Know" Envycasts with David A. Black
http://www.envycasts.com