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,

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

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

On Mon, Jun 29, 2009 at 2:44 PM, Wijnand W. [email protected]
wrote:

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

Hi –

On Tue, 30 Jun 2009, Wijnand W. wrote:

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

Hi,

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

On Mon, Jun 29, 2009 at 2:44 PM, Wijnand W. [email protected] 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

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

Kind regards,
Wijnand

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

Greetz,
k

P.S: metaid rocks!

Hi –

On Tue, 30 Jun 2009, Bertram S. wrote:

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 Monday 29 June 2009 02:21:49 pm Bertram S. wrote:

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

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.

Hi –

On Tue, 30 Jun 2009, Mike S. wrote:

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

Hi David,

On Tue, Jun 30, 2009 at 8:01 AM, David A. Black [email protected]
wrote:

to

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.

Of course! I was thinking of ActiveRecord’s macro method syntax–not the
most apropos when the original question was about variable assignment, I
know. :slight_smile:

 @bar, = v

end
@bar
end

Ahh, yes. Thanks for pointing that out. I was really more concerned at
the
time with giving an (admittedly idiosyncratic) example of assignment
without
an explicit receiver as food for the OP’s thought. I’d never thought to
use
@bar, = v in order to grab only the first element of an array though.
Cool!

Thanks again,
Mike

Op 30 jun 2009, om 09:29 heeft Fabian S. 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.

Thank you for your replies!

Kind regards,
Wijnand

Hi –

On Thu, 2 Jul 2009, Wijnand W. wrote:

def attr_accessor_special(*syms)
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

Hi,

Am Dienstag, 30. Jun 2009, 20:48:33 +0900 schrieb David A. Black:

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

You’re right. Sorry!

Bertram