2

Given a string '123', I can create a Float or Integer:

x = Float('123.45')
y = Integer('123')

As an exercise in dynamic typing, I want to extend Numeric, the top-level number class, with a method that converts the number to a string, reverses it, and then back to its original type.

This would allow me to do this:

x = (123).reverse
// x == 321

or this:

y = (54.321).reverse
// y == 123.45

One implementation looks like this: (this works correctly)

class Numeric
  def reverse
    str = self.to_s.reverse

    if self.is_a?(Float)
      return Float(str) # or str.to_f
    elsif self.is_a?(Integer)
      return Integer(str) # or str.to_i
    end
  end
end

But I want to create the result dynamically rather than checking a list of types. I tried using Class.new():

class Numeric
  def reverse
    str = self.to_s.reverse
    self.class.new(str)
  end
end

I thought this would work since I can call Float('123.45') or Integer('123'). However, I get these errors:

irb(main):047:0> (54.321).reverse
NoMethodError: undefined method `new' for Float:Class
    from (irb):44:in `reverse'
    from (irb):47
    from /Users/aaron/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>'
irb(main):048:0> (123).reverse
NoMethodError: undefined method `new' for Fixnum:Class
    from (irb):44:in `reverse'
    from (irb):48
    from /Users/aaron/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>'

So I have two questions:

  • How does Float('123.45') or Integer('123') work if they don't implement new?
  • How can I implement Numeric.reverse() without any conditionals?

I know there are other cases where this won't work (like negative numbers), but I'm not concerned with those issues (yet).

2
  • 1
    It also doesn't work for Float::INFINITY. Also a good answer to the first question can be found here. Commented Jun 30, 2015 at 0:41
  • And since they are just methods, you can dynamically call them with Object#send. But then it still won't work for integers since they're not actually instances of Integer. Commented Jun 30, 2015 at 0:44

1 Answer 1

1
  1. How does Float('123.45') or Integer('123') work if they don't implement new?

    They call the Kernel methods Kernel::Float and Kernel::Integer respectively, more info here

  2. How can I implement Numeric.reverse() without any conditionals?

    Like this:

    class Numeric
      def reverse
        str = self.to_s.reverse
        method(self.class.to_s).call(str)
      end
    end
    

    The method method converts string or symbol to a method, which then can be called using call and passing the string you want to it.

    Example: method((123.2).class.to_s).call('321') # => 321.0

Sign up to request clarification or add additional context in comments.

10 Comments

What if the number has leading zeros...say '0112'
While casting it on Float or Integer all leading zeros will be omitted as expected
(0112).reverse NameError: undefined method 'Fixnum' for class 'Fixnum'
@VamsiKrishna that's just because 112.class == Fixnum
Thats true, Kernel doesn't have a Fixnum method, just an Integer. Not sure yet how to get around that..
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.