Ruby: Boolean Challenge

Paste url: 5603’s gists · GitHub

Gist Paste Clone URL: git://gist.github.com/5603.git

[Impossible?] CHALLENGE: See pending spec at the bottom

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 something like this:

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

require ‘rubygems’
require ‘spec’

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
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).true?.should be_false
end

it “should return true for 1 or 3 or 6” do
@recognizer.mknows?(1).or?(3).or?(6).true?.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?(5).should be_true
end
end
end

Errata:

Instead of:

puts (OddRecognizer.new.knows?(1) or OddRecognizer.new.knows?(3)) ?
“there are odds” : “there is no odd”

First example should be

recognizer = OddRecognizer.new
puts (recognizer.knows?(1) or recognizer.knows?(3)) ? “there are odds”
: “there is no odd”

That needs to be changed to:

puts OddRecognizer.new.knows?(1).or?(3) ? “there are odds” : “there is
no odd”

heh…
this will work… but i wouldn’t suggest using it for anything other
than intellectual enjoyment.

class FalseOddRecognizer < NilClass
//#same methods as TrueOddRecognizer
end

class TrueOddRecognizer
//#same methods as before
end

Now, in knows(), return a FalseOddRecognizer when false and a
TrueOddRecognizer on true.

The trick is that Ruby evaluates all subclasses of NilClass to false.

The trick is that Ruby evaluates all subclasses of NilClass to false.

The problem is that, if I extend NilClass, I wont be able to use new
anymore

class Test < NilClass; end;

Test.new # NoMethodError: undefined method `new’ for Test:Class

On 8/15/08, Emmanuel O. [email protected] wrote:

@recognizer.knows?(3).should be_false
end
end

Maybe I’m dense, but if the recognizer knows 2 but not 3 … doesn’t
that make it an EvenRecognizer?

I know this doesn’t effect the fundamental problem, but the examples
might be easier to understand if the names were consistent.

On Fri, Aug 15, 2008 at 1:04 PM, Emmanuel O.
[email protected] wrote:


Posted via http://www.ruby-forum.com/.

I’m not sure I understand what you’re looking for, but this passes your
specs.

Actually, I think there was a typo on line 94.

  • @recognizer.mknows?(1).or?(3).or?(5).should be_true
  • @recognizer.mknows?(1).or?(3).or?(6).should be_true

After I fixed that, it passes the specs.

Hi –

On Sat, 16 Aug 2008, Emmanuel O. wrote:

With something like this:

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

Do you mean EvenRecognizer?

David

Hi David

class OddRecognizer
def knows?(value)
(value % 2) == 0
end
end

Do you mean EvenRecognizer?

True, I confused the two terms (even, odd). I tend to make that mistake,
I also then to confuse the words Tuesday and Thursday :slight_smile:

Hey,
Sorry for the late reply: I was out to lunch:

I didn’t know you can’t instantiate NilClass.
Anyway here’s a workaround involving singletons:

class OddRecognizer
def knows(num)
return self if num%2==0

o = nil
class << o
  def or(num)
    return self if num%2==1
    return OddRecognizer.new
  end
end
return o

end

alias :or :knows
end

It was an interesting question from a intellectual standpoint.
But I wouldn’t touch this code with a ten foot pole. lol

-Patrick

class OddRecognizer
def knows(num)
return self if num%2==0
class << nil
def or(num)
return self if num%2==1
return OddRecognizer.new
end
end
nil
end

alias :or :knows
end

Patrick:

that sure works, the problem is that nil is extended with a or method
that is not very intuitive for it…

nil.or(2)
=> #OddRecognizer:0xb7a626bc what the ·$%!$%!$%@!!!

Code pollution at is maximum expression hahaha

I thought of doing something like that with false instead of nil, but
is the same problem. And you can’t dup nil true nor false obviously :slight_smile:

It was an interesting question from a intellectual standpoint.
But I wouldn’t touch this code with a ten foot pole. lol

Hahaha I agree.

Lol. Mmm i honestly didn’t see that one coming.
I guess nil and false are true singletons.
Perhaps there’s a hack out there that lets us instantialize a NilClass
object.

Anyway. Thanks for the question. That was interesting.

5619’s gists · GitHub

Actually, I think there was a typo on line 94.

  • @recognizer.mknows?(1).or?(3).or?(5).should be_true
  • @recognizer.mknows?(1).or?(3).or?(6).should be_true

After I fixed that, it passes the specs.

Yes I had a couple of typos, I think I have fixed them now. I’m not sure
about your change though, but I think the last edit I made makes more
clear what I’m needing:

it “should return false for 1 or 3 or 5 without having to call true at
the end” do
pending “Impossible in ruby?” do
lambda do
# needed functionality is to remove last true? and make it work
anyway.
raise if @recognizer.mknows?(1).or?(3).or?(5)#.true?
end.should_not raise_error
end
end

P.S.: GIST RULES!!! :smiley: