Forum: Ruby obj.attr(qualifier) = value -- possible?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Michael S. (Guest)
on 2009-05-15 23:02
(Received via mailing list)
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
Rick D. (Guest)
on 2009-05-15 23:11
(Received via mailing list)
On Fri, May 15, 2009 at 3:00 PM, Michael S. 
<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/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
Joel VanderWerf (Guest)
on 2009-05-15 23:14
(Received via mailing list)
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"
Adam G. (Guest)
on 2009-05-15 23:17
Rick Denatale wrote:
> On Fri, May 15, 2009 at 3:00 PM, Michael S. <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.
Michael S. (Guest)
on 2009-05-15 23:56
(Received via mailing list)
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
Anthony E. (Guest)
on 2009-05-16 00:13
(Received via mailing list)
On Fri, May 15, 2009 at 3:55 PM, Michael S. 
<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
Brian A. (Guest)
on 2009-05-16 00:35
(Received via mailing list)
Michael S. <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)
Michael S. (Guest)
on 2009-05-16 00:45
(Received via mailing list)
Anthony E. wrote:

> On Fri, May 15, 2009 at 3:55 PM, Michael S.
> <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
Robert K. (Guest)
on 2009-05-16 17:46
(Received via mailing list)
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
This topic is locked and can not be replied to.