Ruby: Boolean Challenge

E

Emmanuel Oga

# Paste url: http://gist.github.com/5603
# 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 :eek:r 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
 
E

Emmanuel Oga

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"
 
P

Patrick Li

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.
 
E

Emmanuel Oga

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
 
D

David A. Black

Hi --

# Paste url: http://gist.github.com/5603
# 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

Do you mean EvenRecognizer?


David
 
A

Adam Shelly

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
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.
 
G

Gordon Thiesfeld

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


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

http://gist.github.com/5619

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.
 
E

Emmanuel Oga

Hi David
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 :)
 
E

Emmanuel Oga

http://gist.github.com/5619
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!!! :D
 
P

Patrick Li

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 :eek:r :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
 
E

Emmanuel Oga

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 :eek:r :knows
end

Patrick:

that sure works, the problem is that nil is extended with a or method
that is not very intuitive for it...
=> #<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 :)
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.
 
P

Patrick Li

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,699
Latest member
AnneRosen

Latest Threads

Top