有没有办法定义一个可以强制为字符串、Fixnum或Float的对象这是在一个系统中使用的,该系统收集值并用它们计算一组受限制的简单表达式。
我试过:
class EmptyValue < Numeric
def to_s; ''; end
def to_str; ''; end
def to_i; 0; end
def to_int; 0; end
def to_f; 0.0; end
end
但这失败了
1 + e
TypeError: EmptyValue can't be coerced into Fixnum
最佳答案
这是我很久以前做的:
class NullObject
attr_reader :null_object_type, :recorded_messages
alias ρ recorded_messages
def initialize( type_of_null_object = nil )
@null_object_type = type_of_null_object
@recorded_messages = []
end
def null_object? null_type = nil
null_object_type == null_type
end
alias null? null_object?
def to_a; [] end
def to_s; "null #{null_object_type}".strip end
def to_f; 0.0 end
def to_i; 0 end
def present?; false end
def empty?; true end
def blank?; true end
def inspect
"NullObject #{null_object_type}".strip
end
def method_missing ß, *aj, &b # :nodoc:
@recorded_messages << [ ß, aj, b ]; self
end
def respond_to? ß, *aj, &b # :nodoc:
true
end
protected
def == other # :nodoc:
null_object_type == other.null_object_type
end
end # class NullObject
# Strong zero.
#
ZERO = NullObject.new
ZERO.instance_exec {
ɪ = self
singleton_class.class_exec do
define_method :zero do ɪ end
end
def * other; other.class.zero end
def / other
self unless other.zero?
raise ZeroDivisionError, "The divisor is zero! (#{other})"
end
def + other; other end
def - other; -other end
def coerce other
return other, other.class.zero
end
def zero?; true end
def to_s; "∅" end
def inspect; to_s end
def to_f; 0.0 end
def to_i; 0 end
def == other
z = begin
other.class.zero
rescue NoMethodError
return false
end
other == z
end
}
class << Numeric; def zero; 0.0 end end
class << Integer; def zero; 0 end end
class << Float; def zero; 0.0 end end
class << Rational; def zero; Rational 0, 1 end end
class << Complex; def zero; Complex 0, 0 end end
class << String; def zero; '' end end
class << Array; def zero; [] end end
class << Hash; def zero; {} end end
现在你有了
0 + ZERO #=> 0
。我称之为“强零”但这是一个黑客。我有一种直觉,认为这不是一个好的做法。