obj.attr(qualifier) = value -- possible?

M

Michael Schuerig

I want to write a method that can be called like this

obj.attr(qualifier) = value

So far, I don't see how to achieve this. I've tried

class C
def attr=(qualifier, value)
...
end
end

as well as

class D
def attr(qualifier)
Proxy.new(self, qualifier)
end
class Proxy
def =(value)
...
end
end
end

Neither is valid Ruby, apparently. Is there another, working way?

Michael
 
R

Rick DeNatale

I want to write a method that can be called like this

=A0obj.attr(qualifier) =3D value

So far, I don't see how to achieve this. I've tried

class C
=A0def attr=3D(qualifier, value)
=A0 =A0...
=A0end
end

as well as

class D
=A0def attr(qualifier)
=A0 =A0Proxy.new(self, qualifier)
=A0end
=A0class Proxy
=A0 =A0def =3D(value)
=A0 =A0 =A0...
=A0 =A0end
=A0end
end

Neither is valid Ruby, apparently. Is there another, working way?

I don't think you can get the calling syntax you want. The best you
can do I think is

obj.attr =3D qualifier, value


--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 
J

Joel VanderWerf

Michael said:
I want to write a method that can be called like this

obj.attr(qualifier) = value

So far, I don't see how to achieve this. I've tried

class C
def attr=(qualifier, value)
...
end
end

as well as

class D
def attr(qualifier)
Proxy.new(self, qualifier)
end
class Proxy
def =(value)
...
end
end
end

Neither is valid Ruby, apparently. Is there another, working way?

Michael

I'm pretty sure that's impossible -- there is no #() method, or #()=.
But there is #[]=, and you can adapt your Proxy approach to use it:

class D
def attr
Proxy.new(self)
end
def handle qualifier, value
puts "handling #{qualifier.inspect}, #{value.inspect}"
end

class Proxy
def initialize obj
@obj = obj
end
def []=(qualifier, value)
@obj.send:)handle, qualifier, value)
end
end
end

d = D.new
d.attr["some qualifier"] = "some value"
 
A

Adam Gardner

Rick said:
I don't think you can get the calling syntax you want. The best you
can do I think is

obj.attr = qualifier, value

Well, you could always go with obj.attr[qualifier] = value

irb(main):004:0> class Ooo
irb(main):005:1> attr_reader :attr
irb(main):006:1> def initialize
irb(main):007:2> @attr = {}
irb(main):008:2> end
irb(main):009:1> end
=> nil
irb(main):010:0> obj = Ooo.new
=> #<Ooo:0x6fe6b8 @attr={}>
irb(main):011:0> obj.attr[:happy] = :sad
=> :sad
irb(main):012:0> obj.attr
=> {:happy=>:sad}
irb(main):013:0> obj.attr[:happy]
=> :sad
irb(main):014:0>

This example used a hash because it's easy, buy could make @attr be any
class that accepts the []= method, including a class of your own.
 
M

Michael Schuerig

Joel said:
I'm pretty sure that's impossible -- there is no #() method, or #()=.
But there is #[]=, and you can adapt your Proxy approach to use it:

That's a good suggestion, but unfortunately, it doesn't fit in my case.
I'm trying to do this stuff in an extension module for a Rails has_many
:through association. It looks roughly like this

class Role < ActiveRecord::Base
validates_presence_of :type # actor, director, ...
end

class Movie < ActiveRecord::Base
has_many :roles
has_many :participants, :through => :roles do
def as(role)
self.scoped(...) # joins and conditions omitted
end
end
end

This allows me to write code like

movie.participants.as('actor')

On top of that, I'd like to be able to write

movie.participants.as('actor') = params[:movie][:actors]

and that's where I'm stuck.

Michael
 
A

Anthony Eden

Joel said:
I'm pretty sure that's impossible -- there is no #() method, or #()=3D.
But there is #[]=3D, and you can adapt your Proxy approach to use it:

That's a good suggestion, but unfortunately, it doesn't fit in my case.
I'm trying to do this stuff in an extension module for a Rails has_many
:through association. It looks roughly like this

class Role < ActiveRecord::Base
=A0validates_presence_of :type # actor, director, ...
end

class Movie < ActiveRecord::Base
=A0has_many :roles
=A0has_many :participants, :through =3D> :roles do
=A0 =A0def as(role)
=A0 =A0 =A0self.scoped(...) # joins and conditions omitted
=A0 =A0end
=A0end
end

This allows me to write code like

movie.participants.as('actor')

On top of that, I'd like to be able to write

movie.participants.as('actor') =3D params[:movie][:actors]

and that's where I'm stuck.

If you're willing to use a block you could do

movie.participants.as('actor') { params[:movie][:actors] }

and then:

def as(role, &block)
value =3D yield
end


-A


--=20
GMU/IT d- s: a32 C++(++++)$ UL@ P--- L+(++) !E W+++$ !N o? K? w--- !O
M++ V PS+ PE Y PGP t+ !5 X- R tv b++ DI+ D++ G- e++ h---- r+++ y++++**

http://anthony.mp
 
B

Brian Adkins

Michael Schuerig said:
I want to write a method that can be called like this

obj.attr(qualifier) = value

So far, I don't see how to achieve this.

Me neither. And the following:

obj = Foo.new
obj.attr(qualifier).assign(value)

seems inferior to:

obj.attr_assign(qualifier, value)
 
M

Michael Schuerig

Anthony said:
On Fri, May 15, 2009 at 3:55 PM, Michael Schuerig
This allows me to write code like

movie.participants.as('actor')

On top of that, I'd like to be able to write

movie.participants.as('actor') = params[:movie][:actors]

and that's where I'm stuck.

If you're willing to use a block you could do

movie.participants.as('actor') { params[:movie][:actors] }

and then:

def as(role, &block)
value = yield
end

Another interesting suggestion. But I think I use

def replace(role, value)
...
end

as there's a precedent in the Rails association methods for #replace and
the generated #replace is not useful in this case anyway.

Michael
 
R

Robert Klemme

This allows me to write code like

movie.participants.as('actor')

On top of that, I'd like to be able to write

movie.participants.as('actor') = params[:movie][:actors]

and that's where I'm stuck.

The *only* way to modify behavior of the assignment operator in Ruby is
the route through []= AFAIK. If you want to use "=" you will have to do
down that route. But I see you have got your working solution already.
Just wanted to make sure expectations are not unrealistic. :)

Kind regards

robert
 

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

Forum statistics

Threads
474,173
Messages
2,570,937
Members
47,481
Latest member
ElviraDoug

Latest Threads

Top