lib/stupidedi/versions/common/element_types/operators.rb
# frozen_string_literal: true
module Stupidedi
using Refinements
module Versions
module Common
module ElementTypes
module Operators
module Unary
def unary_operators(*ops)
file, line, = Stupidedi.caller
ops.each do |op|
class_eval(<<-RUBY, file, line.to_i - 1)
def #{op}(&block)
copy(:value => value.#{op}(&block))
end
RUBY
end
end
end
module Binary
def binary_operators(*ops)
file, line, = Stupidedi.caller
if ops.last.is_a?(Hash)
options = ops.pop
case options[:coerce]
when String, Symbol
coerce = options[:coerce]
else
raise ArgumentError,
"must pass :coerce => :method"
end
else
raise ArgumentError,
"must pass :coerce => :method"
end
# Note that we can't test respond_to?(coerce) because coerce is
# often a refinement method, like #to_d, #to_time, etc. Currently
# respond_to? returns false on refinment methods, so we just call
# the method and assume a NoMethodError is due to coerce (hopefully
# not some other missing method)
ops.each do |op|
class_eval(<<-RUBY, file, line.to_i - 1)
def #{op}(other, &block)
begin
copy(:value => value.#{op}(other.#{coerce}, &block))
rescue NoMethodError
begin
me, he = other.coerce(self)
copy(:value => me.#{op}(he, &block).#{coerce})
rescue NoMethodError
raise TypeError,
"cannot coerce \#{other.class} to \#{self.class}"
end
end
end
RUBY
end
end
end
module Relational
def relational_operators(*ops)
file, line, = Stupidedi.caller
if ops.last.is_a?(Hash)
options = ops.pop
case options[:coerce]
when String, Symbol
coerce = options[:coerce]
else
raise ArgumentError,
"must pass :coerce => :method"
end
else
raise ArgumentError,
"must pass :coerce => :method"
end
# Note that we can't test respond_to?(coerce) because coerce is
# often a refinement method, like #to_d, #to_time, etc. Currently
# respond_to? returns false on refinment methods, so we just call
# the method and assume a NoMethodError is due to coerce (hopefully
# not some other missing method)
ops.each do |op|
class_eval(<<-RUBY, file, line.to_i - 1)
def #{op}(other, &block)
begin
value.#{op}(other.#{coerce}, &block)
rescue NoMethodError
begin
me, he = other.coerce(self)
me.#{op}(he, &block)
rescue NoMethodError
raise TypeError,
"cannot coerce \#{other.class} to \#{self.class}"
end
end
end
RUBY
end
end
end
module Wrappers
def wrappers(*ops)
file, line, = Stupidedi.caller
ops.each do |op|
class_eval(<<-RUBY, file, line.to_i - 1)
def #{op}(*args, &block)
copy(:value => value.#{op}(*args, &block))
end
RUBY
end
end
end
end
end
end
end
end