To_s mixin/reflection/newbie stuff

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 :wink:

Thanks

···

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

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 :wink:

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.

···

On 4/18/07, Kris Helenek <khelenek@hotmail.com> wrote:

--
gnufied

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-forum.com/.

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.

···

On 4/19/07, Kris Helenek <khelenek@hotmail.com> wrote:

--
gnufied

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

···

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.

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

···

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.

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

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

···

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

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

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.

···

--
Florian Frank

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.

···

-----Original Message-----
From: Florian Frank [mailto:flori@nixe.ping.de]
Sent: Thursday, April 19, 2007 5:14 AM
To: ruby-talk ML
Subject: Re: Using file tail with block

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.

--
Florian Frank