# Obj.attr(qualifier) = value -- possible?

**URL:** <https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099>\
**Category:** Ruby\
**Created:** [May 15, 2009, 9:02pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099 "2009-05-15T21:02:41Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [May 15, 2009, 9:02pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099/1 "2009-05-15T21:02:41Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [May 15, 2009, 9:11pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099/2 "2009-05-15T21:11:27Z")

</div>

On Fri, May 15, 2009 at 3:00 PM, Michael S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> end  
> …  
> end  
> end  
> 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 = qualifier, value

–  
Rick DeNatale

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

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [May 15, 2009, 9:14pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099/3 "2009-05-15T21:14:24Z")

</div>

Michael S. wrote:

> end  
> 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”

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [May 15, 2009, 9:56pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099/4 "2009-05-15T21:56:00Z")

</div>

Joel VanderWerf wrote:

> 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

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [May 15, 2009, 9:17pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099/5 "2009-05-15T21:17:58Z")

</div>

Rick Denatale wrote:

> On Fri, May 15, 2009 at 3:00 PM, Michael S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
> wrote:
> 
> > ï¿½end  
> > ï¿½ ï¿½ ï¿½…  
> > ï¿½ ï¿½end  
> > ï¿½end  
> > 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 = 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.

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [May 15, 2009, 10:13pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099/6 "2009-05-15T22:13:34Z")

</div>

On Fri, May 15, 2009 at 3:55 PM, Michael S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> validates\_presence\_of :type # actor, director, …
> 
> 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

-A

–  
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](http://anthony.mp)

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [May 15, 2009, 10:45pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099/7 "2009-05-15T22:45:49Z")

</div>

Anthony E. wrote:

> On Fri, May 15, 2009 at 3:55 PM, Michael S.  
> [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:  
> […]  
> 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

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [May 16, 2009, 3:46pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099/8 "2009-05-16T15:46:01Z")

</div>

On 15.05.2009 21:50, Michael S. wrote:

> 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

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [May 15, 2009, 10:35pm UTC](https://www.ruby-forum.com/t/obj-attr-qualifier-value-possible/168099/9 "2009-05-15T22:35:51Z")

</div>

Michael S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

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