Overriding to_s

All:

This is probably going to seem a bit silly, however I will ask
anyway. :slight_smile:

Is there a way to override the to_s method such that it takes a
parameter? For example, if I wanted to provide a format specifier
for a number:

class Numeric
    def to_s(optFormat)
        if !optFormat.nil?
            # format a string based on the optFormat format  
            # specifier.
            retVal = format_number(self,optFormat)
        else
            retVal = self.to_s
        end
        retVal
    end
end

payment=600   # $6.00
puts(payment.to_s('$#.##')) 

(* not a perfect specimen of a ruby script, but it gets the
idea across *)

Any help with this matter, is greatly appreciated. :slight_smile:

Regards,
Brad

Is there a way to override the to_s method such that it takes a
parameter? For example, if I wanted to provide a format specifier
for a number:

well, you have several problems

    class Numeric

#to_s is defined in Integer, Float, Bignum, ... not in Numeric

If you define it in Numeric, ruby will use the old definition in
Integer, ...

        def to_s(optFormat)

you are saying that #to_s must have a parameter, this mean that you can't
call it 12.to_s

Perhaps best to write it

           def to_s(optFormat = nil)

now Integer#to_s can take an optional argument, this mean that your new
method #to_s is not really adapted for Integer (except if format_number
take this in count)

            if !optFormat.nil?
                # format a string based on the optFormat format
                # specifier.
                retVal = format_number(self,optFormat)
            else
                retVal = self.to_s

here, you call recursively #to_s.

Perhaps best to alias #to_s before redefining it, and call the alias

            end
            retVal
        end
    end

Guy Decoux

You probably don’t want to override #to_s to take a parameter.

I recommend looking at http://rubyforge.org/projects/extensions/;
specifically #format_s as defined in
extensions/lib/extensions/numeric.rb.

I have submitted a replacement for
extensions/lib/extensions/numeric.rb that handles (simple
before/after) currency formatting. If anything more complex is
necessary, please let me know and I’ll look into it.

There are three possible further extensions to this method from my
perspective. First, this method does not ensure precision, but
instead formats exactly what is given. The :usd style provided will
format 1234.1234 as $1,234.1234. If you only want $1,234.12, it is
up to you to ensure that only the proper number of decimal places is
provided. It may be useful to provide for precision (both decimal
and general).

Second, it may be desirable to show the “+” sign in some instances.
This is not yet possible.

Finally, it may be desirable to have a parallel method, #format_a,
that returns the formatted constituent parts of the number as an
array [sign, integer-part, decimal-point, decimal-part] so that you
can format them as you wish. The simplest formatting of #format_a
would be #join, but you could do: ($1.20) instead of $(1.20). (The
currency formatting takes place after all other formatting.)
(Alternatively, one could specify a template, but that is overkill
in my opinion.)

-austin

···


austin ziegler * austin@halostatue.ca * Toronto, ON, Canada
software designer * pragmatic programmer * 2003.12.31
* 12.22.28

ts wrote:

Is there a way to override the to_s method such that it takes a
parameter? For example, if I wanted to provide a format specifier
for a number:

well, you have several problems

class Numeric

#to_s is defined in Integer, Float, Bignum, … not in Numeric

If you define it in Numeric, ruby will use the old definition in
Integer, …

    def to_s(optFormat)

you are saying that #to_s must have a parameter, this mean that you can’t
call it 12.to_s

Perhaps best to write it

       def to_s(optFormat = nil)

now Integer#to_s can take an optional argument, this mean that your new
method #to_s is not really adapted for Integer (except if format_number
take this in count)

        if !optFormat.nil?
            # format a string based on the optFormat format  
            # specifier.
            retVal = format_number(self,optFormat)
        else
            retVal = self.to_s

here, you call recursively #to_s.

Perhaps best to alias #to_s before redefining it, and call the alias

        end
        retVal
    end
end

Guy Decoux

Guy:

Thanks for the speedy response!

I guess I was being a bit naive, I thought Numeric was a base class
for Integer, Float, etc. Is there any way to redefine to_s across
the board, i.e. for Integer, Float, etc without having to duplicate
code for each numeric type?

Yeah, the code is pretty shabby :,. I didn’t put much thought into it
as it was only meant to be an illustration. Don’t get me wrong though
you’re points are very good and obviously are not part of my native
ruby thinking, otherwise the sample would have included them. Thank
you. :slight_smile:

Hopefully I don’t sound rude. :confused:

Regards,
Brad

I guess I was being a bit naive, I thought Numeric was a base class
for Integer, Float, etc. Is there any way to redefine to_s across

Well, I've seen that I've said a stupidity : this is Fixnum which redefine
#to_s and not Integer

Numeric is a base class for Fixnum and Float

svg% ruby -e 'p Fixnum.ancestors; p Float.ancestors'
[Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel]
[Float, Precision, Numeric, Comparable, Object, Kernel]
svg%

but these 2 classes re-define #to_s

svg% ruby -e 'p Fixnum.instance_methods(false).grep(/to_s$/)'
["to_s"]
svg%

svg% ruby -e 'p Float.instance_methods(false).grep(/to_s$/)'
["to_s"]
svg%

svg% ruby -e 'p Integer.instance_methods(false).grep(/to_s/)'

svg%

svg% ruby -e 'p Numeric.instance_methods(false).grep(/to_s/)'

svg%

the board, i.e. for Integer, Float, etc without having to duplicate
code for each numeric type?

wait for 2.0. I suspect that some persons will use wrapper to do this
(probably not its right use, I don't know ...)

Guy Decoux

ts wrote:

I guess I was being a bit naive, I thought Numeric was a base class
for Integer, Float, etc. Is there any way to redefine to_s across

Well, I’ve seen that I’ve said a stupidity : this is Fixnum which redefine
#to_s and not Integer

Numeric is a base class for Fixnum and Float

svg% ruby -e ‘p Fixnum.ancestors; p Float.ancestors’
[Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel]
[Float, Precision, Numeric, Comparable, Object, Kernel]
svg%

but these 2 classes re-define #to_s

svg% ruby -e ‘p Fixnum.instance_methods(false).grep(/to_s$/)’
[“to_s”]
svg%

svg% ruby -e ‘p Float.instance_methods(false).grep(/to_s$/)’
[“to_s”]
svg%

svg% ruby -e ‘p Integer.instance_methods(false).grep(/to_s/)’

svg%

svg% ruby -e ‘p Numeric.instance_methods(false).grep(/to_s/)’

svg%

the board, i.e. for Integer, Float, etc without having to duplicate
code for each numeric type?

wait for 2.0. I suspect that some persons will use wrapper to do this
(probably not its right use, I don’t know …)

Guy Decoux

Guy:

Thanks again for the reply, I defined my own to_s for Fixnum and Float
(aliasing original to_s) and this seems to be working for me.

This should hold me over until Ruby 2.0 is released. :slight_smile:

Thanks,
Brad