Created
August 15, 2008 18:19
-
-
Save vertiginous/5619 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
require 'rubygems' | |
require 'spec' | |
# Here is the problem, I want to replace statements like this: | |
# | |
# puts (OddRecognizer.new.knows?(1) or OddRecognizer.new.knows?(3)) ? "there are odds" : "there is no odd" | |
# | |
# With this syntax: | |
# puts OddRecognizer.new.knows?(1).or?(3) ? "there are odds" : "there is no odd" | |
# | |
# OddRecognizer is just a trivial class just to prove my concept: | |
class OddRecognizer | |
def knows?(value) | |
(value % 2) == 0 | |
end | |
end | |
describe OddRecognizer do | |
before :each do | |
@recognizer = OddRecognizer.new | |
end | |
it "should recognize 2" do | |
@recognizer.knows?(2).should be_true | |
end | |
it "should not recognize 3" do | |
@recognizer.knows?(3).should be_false | |
end | |
end | |
# Here's the implementation | |
class BooleanEvaluator | |
Operation = Struct.new :name, :arguments | |
def initialize(target, method, *args) | |
@target, @method = target, method | |
@arguments = Array.new << Operation.new(:first, args) | |
end | |
def or?(*args) | |
@arguments << Operation.new(:or, args) | |
self | |
end | |
def and?(*args) | |
@arguments << Operation.new(:and, args) | |
self | |
end | |
def true? | |
@arguments.inject(false) do |result, operation| | |
case operation.name | |
when :or then result or @target.send(@method, *operation.arguments) | |
when :and then result and @target.send(@method, *operation.arguments) | |
else @target.send(@method, *operation.arguments) | |
end | |
end | |
end | |
def ==(bool) | |
!!true?.equal?(bool) | |
end | |
end | |
# For now let's add a new method that will behave like I want. | |
class OddRecognizer | |
def mknows?(*args) | |
BooleanEvaluator.new(self, :knows?, *args) | |
end | |
end | |
# Let's test it. | |
describe OddRecognizer do | |
before :each do | |
@recognizer = OddRecognizer.new | |
end | |
it "should return false for 1 or 3 or 5" do | |
@recognizer.mknows?(1).or?(3).or?(5).should be_false | |
end | |
it "should return true for 1 or 3 or 6" do | |
@recognizer.mknows?(1).or?(3).or?(6).should be_true | |
end | |
# Here lies the problem: in ruby, everything that is not nil nor false evaluates | |
# as true in conditional expressions.... Is there any way to modify BooleanEvaluator | |
# (or implement it in a different way) to make this work? I don't think so, | |
# but maybe there is a way to implement something more close to the thing I want. | |
it "should return true for 1 or 3 or 6 without having to call true at the end" do | |
# pending "Impossible in ruby?" do | |
@recognizer.mknows?(1).or?(3).or?(6).should be_true | |
# end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment