Created
October 27, 2008 14:33
-
-
Save jcoglan/20107 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A possibly misguided attempt to introduce automatic operator commutativity to Ruby. Say | |
# I add a '+' method to Range so that for example: | |
# | |
# (3..7) + 12 #=> (15..19) | |
# | |
# I'd expect to be able to call '12 + (3..7)' and get the same answer. This means I need | |
# to override Fixnum#+, meaning my new addition operator is expressed in two places. This | |
# module generates methods that automatically fill in the gaps so you only need to express | |
# the semantics of an operator in a single method, in a single class. | |
# | |
# A simple example: | |
# | |
# class Range | |
# def +(num) | |
# (first + num)..(last + num) | |
# end | |
# end | |
# | |
# class Fixnum | |
# include Commutativity | |
# end | |
# | |
# 4 + (1..15) | |
# #=> (5..19) | |
# | |
# The module covers binary arithmetic, logic and comparison operators. | |
# | |
module Commutativity | |
ALL_SYMBOLS = %w(** ~ + - * / % << >> & ^ | <= < > >= <=> == === =~) | |
COMMUTATIVE = %w(+ * & ^ | == === =~) | |
NEGATED = %w(- <=>) | |
INVERTED = %w(/) | |
OPPOSITES = [%w(<< >>), %w(<= >), %w(< >=)] | |
TRANSLATIONS = { | |
COMMUTATIVE => lambda { |object, symbol, value| value.__send__(symbol, object) }, | |
NEGATED => lambda { |object, symbol, value| -value.__send__(symbol, object) }, | |
INVERTED => lambda { |object, symbol, value| 1.0 / value.__send__(symbol, object) } | |
} | |
def self.included(mod) | |
mod.module_eval do | |
TRANSLATIONS.each do |list, translation| | |
list.each do |symbol| | |
orig = instance_method(symbol) rescue nil | |
define_method(symbol) do |value| | |
begin | |
orig.bind(self).call(value) | |
rescue | |
translation.call(self, symbol, value) | |
end | |
end | |
end | |
end | |
OPPOSITES.each do |pair| | |
pair.each_with_index do |symbol, i| | |
orig = instance_method(symbol) rescue nil | |
define_method(symbol) do |value| | |
begin | |
orig.bind(self).call(value) | |
rescue | |
not value.send(pair[(i+1)%2], self) | |
end | |
end | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment