attr_writers within blocks

W

Wijnand Wiersma

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
 
B

Bertram Scharpf

Hi,

Am Dienstag, 30. Jun 2009, 03:44:48 +0900 schrieb Wijnand Wiersma:
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
 
M

Mike Sassak

[Note: parts of this message were removed to make it a legal post.]

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
 
D

David A. Black

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

--
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
 
W

Wijnand Wiersma

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

Kind regards,
Wijnand
 
B

Bertram Scharpf

Hi,

Am Dienstag, 30. Jun 2009, 04:37:55 +0900 schrieb Mike Sassak:
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
 
D

David Masover

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.
 
F

Fabian Streitel

[Note: parts of this message were removed to make it a legal post.]

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!
 
D

David A. Black

Hi --

Hi,

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

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

--
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
 
D

David A. Black

Hi --

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

Assuming your DSL depends on the lack of equal-signs :) 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

--
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
 
M

Mike Sassak

[Note: parts of this message were removed to make it a legal post.]

Hi David,

Hi --

On Tue, 30 Jun 2009, Mike Sassak wrote:



Assuming your DSL depends on the lack of equal-signs :) 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. :)

class Foo

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

def initialize(&block)

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

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
 
B

Bertram Scharpf

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
 
W

Wijnand Wiersma

Op 30 jun 2009, om 09:29 heeft Fabian Streitel het volgende geschreven:
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

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
 
D

David A. Black

Hi --

Op 30 jun 2009, om 09:29 heeft Fabian Streitel het volgende geschreven:
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

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top