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 |