Forum: Ruby to_s mixin/reflection/newbie stuff

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.
6786a1d0bf675262c491b0b2358f7e42?d=identicon&s=25 Kris Helenek (khelenek)
on 2007-04-18 17:48
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
87e41d0d468ad56a3b07d9a6482fd6d5?d=identicon&s=25 Hemant Kumar (gnufied)
on 2007-04-18 18:34
(Received via mailing list)
On 4/18/07, Kris Helenek <khelenek@hotmail.com> wrote:
> ToStringBuilder.)
> And that fails out on me (@first_name is nil!)
> 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.
6786a1d0bf675262c491b0b2358f7e42?d=identicon&s=25 Kris Helenek (khelenek)
on 2007-04-18 22:50
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.
87e41d0d468ad56a3b07d9a6482fd6d5?d=identicon&s=25 Hemant Kumar (gnufied)
on 2007-04-18 23:38
(Received via mailing list)
On 4/19/07, Kris Helenek <khelenek@hotmail.com> wrote:
>     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.
87e41d0d468ad56a3b07d9a6482fd6d5?d=identicon&s=25 Hemant Kumar (gnufied)
on 2007-04-18 23:40
(Received via mailing list)
On 4/19/07, hemant <gethemant@gmail.com> wrote:
> >       str += attribute[0].to_s + ": " + attribute[1].to_s + ", "
>   @attributes.each {|x| str << "#{attribute[0]}  : #{attribute[1]} , " }
> > 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.
87e41d0d468ad56a3b07d9a6482fd6d5?d=identicon&s=25 Hemant Kumar (gnufied)
on 2007-04-18 23:48
(Received via mailing list)
On 4/19/07, hemant <gethemant@gmail.com> wrote:
> > >     for attribute in self.attributes
> >   str = "#{self.class} ["
> > > conventions yet and I haven't seen anything about utility classes yet...
>
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
6a8333cdf53797dd314bb66eb0797c14?d=identicon&s=25 Doan, Alex (Guest)
on 2007-04-19 00:15
(Received via mailing list)
Can someone explain to me why the following raise an error? (is this
something with File::Tail::Logfile.open not closing the file upon exit?)
require 'file/tail'
File::Tail::Logfile.open('output.txt', :backward => 10, :return_if_eof
=> true ) do |log|
  log.tail { |line| puts line}
end
File.rename('output.txt', 'output2.txt')

Output:
C:/alex/work/build_process/scripts/test.rb:19:in `rename': Permission
denied - output.txt or output2
.txt (Errno::EACCES)
        from C:/alex/work/build_process/scripts/test.rb:19


============================================
While this work:
require 'file/tail'

fh = File::Tail::Logfile.open('output.txt', :backward => 10,
:return_if_eof => true )
fh.tail { |line| puts line }
fh.close
File.rename('output.txt', 'output2.txt')
D84df7c68f790e492c4ad4ec5fe65547?d=identicon&s=25 Florian Frank (Guest)
on 2007-04-19 11:14
(Received via mailing list)
Hi,

Doan, Alex wrote:
> Can someone explain to me why the following raise an error? (is this
> something with File::Tail::Logfile.open not closing the file upon exit?)

Yes. Check out version 1.0.1 of File::Tail, where it is fixed. (Though
it may take some time to propagate the gem to the rubygems mirrors.)

BTW.: You're lucky, that I have found your email here, if one considers
that you didn't send it to me, and you reply-hijacked someone else's
thread in order to write to ruby-talk.
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-04-19 13:19
(Received via mailing list)
On 4/18/07, hemant <gethemant@gmail.com> wrote:
> > > >     str = self.class.name + "["
> > > def to_s
> > > > module? In the helper or model folder? lib? A new folder? Don't know the
> > Oops, replace "attribute" with x in the iterator, please.
>   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
6a8333cdf53797dd314bb66eb0797c14?d=identicon&s=25 Doan, Alex (Guest)
on 2007-04-19 15:36
(Received via mailing list)
Thanks Frank,
This is my time using mailing group so I'm pretty new to how thing work.
I'll create a new thread/send email to the creator next time.

Thanks Again for the reply.
This topic is locked and can not be replied to.