 
 This page contains automated test results for code from O'Reilly's Ruby Cookbook. If this code looks interesting or useful, you might want to buy the whole book.
| Simulating a Subclass of Fixnum | ||
|---|---|---|
| Code | Expected | Actual | 
| require 'delegate'
class HexNumber < DelegateClass(Fixnum)
  # The string representations of this class are hexadecimal numbers.
  def to_s
    sign = self < 0 ? "-" : ""
    hex = abs.to_s(16)
    "#{sign}0x#{hex}"
  end
  def inspect
    to_s
  end
end
HexNumber.new(10) | 0xa | 0xa | 
| HexNumber.new(-10) | -0xa | -0xa | 
| HexNumber.new(1000000) | 0xf4240 | 0xf4240 | 
| HexNumber.new(1024 ** 10) | 0x10000000000000000000000000 | 0x10000000000000000000000000 | 
| HexNumber.new(10).succ | 11 | 11 | 
| HexNumber.new(10) * 2 | 20 | 20 | 
| 100.object_id | 201 | 201 | 
| (10 * 10).object_id | 201 | 201 | 
| Fixnum.new(100) | NoMethodError: undefined method `new' for Fixnum:Class ... | NoMethodError: undefined method `new' for Fixnum:Class from (irb):21 | 
| (10 ** 20).object_id | -606073730 | -606073880 | 
| ((10 ** 19) * 10).object_id | -606079360 | -606079510 | 
| Bignum.new(10 ** 20) | NoMethodError: undefined method `new' for Bignum:Class ... | NoMethodError: undefined method `new' for Bignum:Class from (irb):24 | 
| HexNumber.new(10) * 2 | 20 | 20 | 
| HexNumber.new(10) + HexNumber.new(200) | 210 | 210 | 
| require 'rubygems'
require 'facet/basicobject'
class BetterHexNumber < BasicObject
  def initialize(integer)
    @value = integer
  end  
  # Delegate all methods to the stored integer value. If the result is a
  # Integer, transform it into a BetterHexNumber object. If it's an
  # enumerable containing Integers, transform it into an enumerable
  # containing BetterHexNumber objects.
  def method_missing(m, *args)
    super unless @value.respond_to?(m)
    hex_args = args.collect do |arg| 
      arg.kind_of?(BetterHexNumber) ? arg.to_int : arg 
    end
    result = @value.send(m, *hex_args)
    return result if m == :coerce
    case result
    when Integer
      BetterHexNumber.new(result)
    when Array
      result.collect do |element|
        element.kind_of?(Integer) ? BetterHexNumber.new(element) : element
      end
    else
      result
    end
  end
  # We don't actually define any of the Fixnum methods in this class,
  # but from the perspective of an outside object we do respond to
  # them. What outside objects don't know won't hurt them, so we'll
  # claim that we actually implement the same methods as our delegate
  # object. Unless this method is defined, features like ranges won't
  # work.
  def respond_to?(method_name) 
    super or @value.respond_to? method_name 
  end
  # Convert the number to a hex string, ignoring any other base
  # that might have been passed in.
  def to_s(*args)
    hex = @value.abs.to_s(16)
    sign = self < 0 ? "-" : ""
    "#{sign}0x#{hex}"
  end
  def inspect
    to_s
  end
end
hundred = BetterHexNumber.new(100) | 0x64 | 0x64 | 
| hundred + 5 | 0x69 | 0x69 | 
| hundred + BetterHexNumber.new(5) | 0x69 | 0x69 | 
| hundred.succ | 0x65 | 0x65 | 
| hundred / 5 | 0x14 | 0x14 | 
| hundred * -10 | -0x3e8 | -0x3e8 | 
| hundred.divmod(3) | [0x21, 0x1] | [0x21, 0x1] | 
| (hundred...hundred+3).collect | [0x64, 0x65, 0x66] | [0x64, 0x65, 0x66] | 
| hundred.class | Fixnum | Fixnum | 
| hundred.respond_to? :succ | true | true | 
| hundred.is_a? Fixnum | false | false |