[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

to_s mixin/reflection/newbie stuff

Kris Helenek

4/18/2007 3:48:00 PM

I'm very new to ruby, coming from a long j2ee background. I hope these
questions make sense and aren't covered elsewhere (i looked, really.)

I'm creating a project in rails and i have several model objects that I
want to override the to_s method on. It looks like using a "mixin" or
module is the way to go since i don't want to write a new to_s for every
model class that i have to update every time i make a change to the db.

In java my model classes would use reflection to discover all the
instance variables and concatenate them together (the apache commons
ToStringBuilder.)

I went to accomplish that for my ruby model class but honestly could not
figure out how. I was first stumped trying to override the to_s in the
first place by putting

Class Member
def to_s
"Member[" + @first_name + ", " + @last_name + "]"
end

And that fails out on me (@first_name is nil!)

Then i switched it to
def to_s
"Member[" + first_name + ", " + last_name + "]"
end

And that worked. I don't get it, i thought instance variables always
started with the @?

So i guess my questions are, why no @ before my instance variables, and
how would i write a method that gets all instance variables (and then
concatenates them, although i can figure that out. hopefully ;)

Thanks

--
Posted via http://www.ruby-....

6 Answers

hemant

4/18/2007 4:34:00 PM

0

On 4/18/07, Kris Helenek <khelenek@hotmail.com> wrote:
> I'm very new to ruby, coming from a long j2ee background. I hope these
> questions make sense and aren't covered elsewhere (i looked, really.)
>
> I'm creating a project in rails and i have several model objects that I
> want to override the to_s method on. It looks like using a "mixin" or
> module is the way to go since i don't want to write a new to_s for every
> model class that i have to update every time i make a change to the db.
>
> In java my model classes would use reflection to discover all the
> instance variables and concatenate them together (the apache commons
> ToStringBuilder.)
>
> I went to accomplish that for my ruby model class but honestly could not
> figure out how. I was first stumped trying to override the to_s in the
> first place by putting
>
> Class Member
> def to_s
> "Member[" + @first_name + ", " + @last_name + "]"
> end
>
> And that fails out on me (@first_name is nil!)
>
> Then i switched it to
> def to_s
> "Member[" + first_name + ", " + last_name + "]"
> end
>
> And that worked. I don't get it, i thought instance variables always
> started with the @?
>
> So i guess my questions are, why no @ before my instance variables, and
> how would i write a method that gets all instance variables (and then
> concatenates them, although i can figure that out. hopefully ;)
>

Because @first_name is apparently not a instance variable in rails models:

Have a look:

>> small_user = User.find(:first)
>> small_user.methods.grep(/instance/)
=> ["copy_instance_variables_from", "instance_variables",
"instance_variable_get", "instance_variable_set", "instance_values",
"instance_exec", "instance_of?", "instance_eval"]

>> small_user.instance_variables
["@attributes"]

So, your second attempt worked, because every column is an attribute
and rails creates accessor methods for them.

If you want to override #to_s method for all your models, then an easy
solution would be

module Foobar
def to_s
#put your foobar here
end
end

And mix this module, in all your models where you want to override
behaviour of #to_s. I haven't tested this approach although.




--
gnufied

Kris Helenek

4/18/2007 8:50:00 PM

0

Thanks Hemant! I still have trouble seeing things as methods without
the parentheses(); but it makes perfect sense now. And i wrote a nice
little module to duplicate what is often done to create good debug
output in hibernate (j2ee world):

module ReflectionToString
def to_s
str = self.class.name + "["
for attribute in self.attributes
str += attribute[0].to_s + ": " + attribute[1].to_s + ", "
end
str += "]"
str
end
end

Someone could probably clean it up a bit but its just a first pass...

I have a Rails specific question (i know this is kinda the wrong forum,
but I'm already here..) Where is the appropriate place to store this
module? In the helper or model folder? lib? A new folder? Don't know the
conventions yet and I haven't seen anything about utility classes yet...
thanks again.

--
Posted via http://www.ruby-....

hemant

4/18/2007 9:37:00 PM

0

On 4/19/07, Kris Helenek <khelenek@hotmail.com> wrote:
> Thanks Hemant! I still have trouble seeing things as methods without
> the parentheses(); but it makes perfect sense now. And i wrote a nice
> little module to duplicate what is often done to create good debug
> output in hibernate (j2ee world):
>
> module ReflectionToString
> def to_s
> str = self.class.name + "["
> for attribute in self.attributes
> str += attribute[0].to_s + ": " + attribute[1].to_s + ", "
> end
> str += "]"
> str
> end
> end
>
> Someone could probably clean it up a bit but its just a first pass...

def to_s
str = "#{self.class} ["
@attributes.each {|x| str << "#{attribute[0]} : #{attribute[1]} , " }
str << "]"
end

No need to return str, because last statement evaluated is returned.

>
> I have a Rails specific question (i know this is kinda the wrong forum,
> but I'm already here..) Where is the appropriate place to store this
> module? In the helper or model folder? lib? A new folder? Don't know the
> conventions yet and I haven't seen anything about utility classes yet...
> thanks again.
>

#{RAILS_ROOT}/lib is the appropriate place, although when it grows a
little more bigger and may be reusable, its good idea to create a
plugin.


--
gnufied

hemant

4/18/2007 9:39:00 PM

0

On 4/19/07, hemant <gethemant@gmail.com> wrote:
> On 4/19/07, Kris Helenek <khelenek@hotmail.com> wrote:
> > Thanks Hemant! I still have trouble seeing things as methods without
> > the parentheses(); but it makes perfect sense now. And i wrote a nice
> > little module to duplicate what is often done to create good debug
> > output in hibernate (j2ee world):
> >
> > module ReflectionToString
> > def to_s
> > str = self.class.name + "["
> > for attribute in self.attributes
> > str += attribute[0].to_s + ": " + attribute[1].to_s + ", "
> > end
> > str += "]"
> > str
> > end
> > end
> >
> > Someone could probably clean it up a bit but its just a first pass...
>
> def to_s
> str = "#{self.class} ["
> @attributes.each {|x| str << "#{attribute[0]} : #{attribute[1]} , " }
> str << "]"
> end
>
> No need to return str, because last statement evaluated is returned.
>
> >
> > I have a Rails specific question (i know this is kinda the wrong forum,
> > but I'm already here..) Where is the appropriate place to store this
> > module? In the helper or model folder? lib? A new folder? Don't know the
> > conventions yet and I haven't seen anything about utility classes yet...
> > thanks again.
> >
>
> #{RAILS_ROOT}/lib is the appropriate place, although when it grows a
> little more bigger and may be reusable, its good idea to create a
> plugin.
>


Oops, replace "attribute" with x in the iterator, please.

hemant

4/18/2007 9:47:00 PM

0

On 4/19/07, hemant <gethemant@gmail.com> wrote:
> On 4/19/07, hemant <gethemant@gmail.com> wrote:
> > On 4/19/07, Kris Helenek <khelenek@hotmail.com> wrote:
> > > Thanks Hemant! I still have trouble seeing things as methods without
> > > the parentheses(); but it makes perfect sense now. And i wrote a nice
> > > little module to duplicate what is often done to create good debug
> > > output in hibernate (j2ee world):
> > >
> > > module ReflectionToString
> > > def to_s
> > > str = self.class.name + "["
> > > for attribute in self.attributes
> > > str += attribute[0].to_s + ": " + attribute[1].to_s + ", "
> > > end
> > > str += "]"
> > > str
> > > end
> > > end
> > >
> > > Someone could probably clean it up a bit but its just a first pass...
> >
> > def to_s
> > str = "#{self.class} ["
> > @attributes.each {|x| str << "#{attribute[0]} : #{attribute[1]} , " }
> > str << "]"
> > end
> >
> > No need to return str, because last statement evaluated is returned.
> >
> > >
> > > I have a Rails specific question (i know this is kinda the wrong forum,
> > > but I'm already here..) Where is the appropriate place to store this
> > > module? In the helper or model folder? lib? A new folder? Don't know the
> > > conventions yet and I haven't seen anything about utility classes yet...
> > > thanks again.
> > >
> >
> > #{RAILS_ROOT}/lib is the appropriate place, although when it grows a
> > little more bigger and may be reusable, its good idea to create a
> > plugin.
> >
>
>
> Oops, replace "attribute" with x in the iterator, please.
>


Also, your method is a bit buggy and hence mine is too, it value
returned by to_s will have a "," at the end.

so a better approach would be:

def to_s
str = "#{self.class} ["
str << @attributes.map {|key,value| "#{key} : #{value}"}.join(',')
str << "]"
end

Robert Dober

4/19/2007 11:19:00 AM

0

On 4/18/07, hemant <gethemant@gmail.com> wrote:
> On 4/19/07, hemant <gethemant@gmail.com> wrote:
> > On 4/19/07, hemant <gethemant@gmail.com> wrote:
> > > On 4/19/07, Kris Helenek <khelenek@hotmail.com> wrote:
> > > > Thanks Hemant! I still have trouble seeing things as methods without
> > > > the parentheses(); but it makes perfect sense now. And i wrote a nice
> > > > little module to duplicate what is often done to create good debug
> > > > output in hibernate (j2ee world):
> > > >
> > > > module ReflectionToString
> > > > def to_s
> > > > str = self.class.name + "["
> > > > for attribute in self.attributes
> > > > str += attribute[0].to_s + ": " + attribute[1].to_s + ", "
> > > > end
> > > > str += "]"
> > > > str
> > > > end
> > > > end
> > > >
> > > > Someone could probably clean it up a bit but its just a first pass...
> > >
> > > def to_s
> > > str = "#{self.class} ["
> > > @attributes.each {|x| str << "#{attribute[0]} : #{attribute[1]} , " }
> > > str << "]"
> > > end
> > >
> > > No need to return str, because last statement evaluated is returned.
> > >
> > > >
> > > > I have a Rails specific question (i know this is kinda the wrong forum,
> > > > but I'm already here..) Where is the appropriate place to store this
> > > > module? In the helper or model folder? lib? A new folder? Don't know the
> > > > conventions yet and I haven't seen anything about utility classes yet...
> > > > thanks again.
> > > >
> > >
> > > #{RAILS_ROOT}/lib is the appropriate place, although when it grows a
> > > little more bigger and may be reusable, its good idea to create a
> > > plugin.
> > >
> >
> >
> > Oops, replace "attribute" with x in the iterator, please.
> >
>
>
> Also, your method is a bit buggy and hence mine is too, it value
> returned by to_s will have a "," at the end.
>
> so a better approach would be:
>
> def to_s
> str = "#{self.class} ["
> str << @attributes.map {|key,value| "#{key} : #{value}"}.join(',')
> str << "]"
> end
>
>
Is inspect not a better choice?
Maybe the following code snippet proves helpfull:

430/6 > irb
irb(main):001:0> class A
irb(main):002:1> attr_accessor :a
irb(main):003:1> end
=> nil
irb(main):004:0> class B
irb(main):005:1> attr_accessor :b
irb(main):006:1> end
=> nil
irb(main):007:0> a = A.new
=> #<A:0xb7d786f8>
irb(main):008:0> b = B.new
=> #<B:0xb7d73310>
irb(main):009:0> b.b = 0x2a
=> 42
irb(main):010:0> a.a=b
=> #<B:0xb7d73310 @b=42>
irb(main):011:0> a.inspect
=> "#<A:0xb7d786f8 @a=#<B:0xb7d73310 @b=42>>"
irb(main):012:0>


HTH
Robert
--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw