Defining condititions

hi!

im trying to define a set of rules with ruby, however i cant find a more
ruby-like way to do so…

instead of doing something like

my_set.add(NotNamedRule(“orange”).new)
my_set.add(HasPropertyRule(“color”).new)
my_set.add(OrRule(HasPropertyRule(“size”).new,
HasPropertyRule(“weight”).new))

(i know this is a horrible example. excuse the awful ‘design’. its
justs to illustrate
what i not wanna have ; )

i wanna do something like

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

can anybody think of a nice way to do this?

thanks a lot for any feedback!

ciao!
florian

my_set.add(NotNamedRule(“orange”).new)
my_set.add(HasPropertyRule(“color”).new)
my_set.add(OrRule(HasPropertyRule(“size”).new,
HasPropertyRule(“weight”).new))

that looks a lot like prolog.

i wanna do something like

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

can anybody think of a nice way to do this?

python has a first-order logic library called pylog that lets you do this
kind of thing easily. I’m unaware of any comparable library in ruby, but I
would really like to know if one exists.

···

On Wed, 26 May 2004 00:04:45 +0900, Florian Weber wrote:

Assuming you have a specific class you created that needs to be
compared to a set of rules, here’s one way:

  • Create a class, Rule. Implement === in it, so you can compare members
    of your class to it as a test.
  • Create a class, Ruleset. It acts like a rule, compares using ===. You
    can create Ruleset instances by using the bitwise operators on Rule
    instances.

A simplistic example:

···

On May 25, 2004, at 8:04 AM, Florian Weber wrote:

hi!

im trying to define a set of rules with ruby, however i cant find a
more
ruby-like way to do so…

instead of doing something like

my_set.add(NotNamedRule(“orange”).new)
my_set.add(HasPropertyRule(“color”).new)
my_set.add(OrRule(HasPropertyRule(“size”).new,
HasPropertyRule(“weight”).new))

(i know this is a horrible example. excuse the awful ‘design’. its
justs to illustrate
what i not wanna have ; )

i wanna do something like

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

can anybody think of a nice way to do this?


file: dogrules.rb

class Dog
attr_reader :age, :breed, :name
def initialize(breed, age, name)
@breed, @age, @name = breed, age, name
end
end

class Rule
def initialize(rulename, *args)
@rulename, @args = rulename, args
end

def ===(other)
if other.kind_of? Dog
case @rulename
when :breed_is
@args[0] == other.breed
when :age_is
@args[0] == other.age
when :name_is_one_of
@args.any?{|a| a == other.name }
end
end
end

compare with or: rule1 | rule2

def |(other)
Ruleset.new(self, :or, other)
end

compare with and: rule1 & rule2

def &(other)
Ruleset.new(self, :and, other)
end

negate this rule: rule1.not

def not
Ruleset.new(self, :not)
end
end

class Ruleset < Rule
def initialize(one, op, two = nil)
@one, @op, @two = one, op, two
end

def ===(other)
case @op
when :or
@one === other or @two === other
when :and
@one === other and @two === other
when :not
not @one === other
end
end
end

dog1 = Dog.new(“black lab”, 3, “Rufus”)
dog2 = Dog.new(“beagle”, 2, “Bowser”)
dog3 = Dog.new(“black lab”, 4, “Blackie”)

rule1 = Rule.new(:breed_is, “black lab”)
rule2 = Rule.new(:name_is_one_of, “Bowser”, “Blackie”)

[dog1, dog2, dog3].map{|dog| rule1 === dog }
#=> [true, false, true]
[dog1, dog2, dog3].map{|dog| rule2 === dog }
#=> [false, true, true]
[dog1, dog2, dog3].map{|dog| (rule1 & rule2) === dog }
#=> [false, false, true]


HTH,
Mark

Kansas, written by Kirk Haines, has such a conditions system to write
SQL queries. You may want to check it out:

http://enigo.com/projects/kansas/index.html

Guillaume.

···

On Tue, 2004-05-25 at 11:04, Florian Weber wrote:

hi!

im trying to define a set of rules with ruby, however i cant find a more
ruby-like way to do so…

instead of doing something like

my_set.add(NotNamedRule(“orange”).new)
my_set.add(HasPropertyRule(“color”).new)
my_set.add(OrRule(HasPropertyRule(“size”).new,
HasPropertyRule(“weight”).new))

(i know this is a horrible example. excuse the awful ‘design’. its
justs to illustrate
what i not wanna have ; )

i wanna do something like

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

can anybody think of a nice way to do this?

thanks a lot for any feedback!

ciao!
florian

“Florian Weber” csshsh@structbench.com schrieb im Newsbeitrag
news:D83A07D2-AE5C-11D8-A68B-000A95BD142E@structbench.com

hi!

im trying to define a set of rules with ruby, however i cant find a more
ruby-like way to do so…

instead of doing something like

my_set.add(NotNamedRule(“orange”).new)
my_set.add(HasPropertyRule(“color”).new)
my_set.add(OrRule(HasPropertyRule(“size”).new,
HasPropertyRule(“weight”).new))

(i know this is a horrible example. excuse the awful ‘design’. its
justs to illustrate
what i not wanna have ; )

i wanna do something like

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

You won’t be able to make this work as rule creation because of short
circuit evaluation of ‘&&’ and ‘||’.

can anybody think of a nice way to do this?

You could do:

#!/#!/usr/bin/ruby

module Rule
def self.create(&b)
def b.===(obj)
call obj
end
b
end

def self.and(*rules)
def rules.===(obj)
all? {|r| r === obj}
end
rules
end

def self.or(*rules)
def rules.===(obj)
any? {|r| r === obj}
end
rules
end
end

r1 = Rule.create {|o| o.name != “orange” && o.color && (o.size ||
o.weight) }
r2 = Rule.create {|o| o.name == “orange” && o.color && (o.size ||
o.weight) }

require ‘ostruct’
obj = OpenStruct.new
obj.name = “green”
obj.color = “yellow”
obj.size = 10

p r1 === obj
p Rule.and( r1, r2 ) === obj
p Rule.or( r1, r2 ) === obj

R#!/usr/bin/ruby

module Rule
def self.create(&b)
def b.===(obj)
call obj
end
b
end

def self.and(*rules)
def rules.===(obj)
all? {|r| r === obj}
end
rules
end

def self.or(*rules)
def rules.===(obj)
any? {|r| r === obj}
end
rules
end
end

r1 = Rule.create {|o| o.name != “orange” && o.color && (o.size ||
o.weight) }
r2 = Rule.create {|o| o.name == “orange” && o.color && (o.size ||
o.weight) }

testing…

require ‘ostruct’
obj = OpenStruct.new
obj.name = “green”
obj.color = “yellow”
obj.size = 10

p r1 === obj
p Rule.and( r1, r2 ) === obj
p Rule.or( r1, r2 ) === obj

Regards

robert

Have a look at Criteria: http://mephle.org/Criteria/

···

Florian Weber (csshsh@structbench.com) wrote:

hi!

im trying to define a set of rules with ruby, however i cant find a more
ruby-like way to do so…

instead of doing something like

my_set.add(NotNamedRule(“orange”).new)
my_set.add(HasPropertyRule(“color”).new)
my_set.add(OrRule(HasPropertyRule(“size”).new,
HasPropertyRule(“weight”).new))

(i know this is a horrible example. excuse the awful ‘design’. its
justs to illustrate
what i not wanna have ; )

i wanna do something like

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

can anybody think of a nice way to do this?


Eric Hodel - drbrain@segment7.net - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

if you like dangerous code, you might try something like this:

~ > cat a.rb
class Rule
def initialize rule; @rule = rule.to_str; end

def apply? obj
  safe = $SAFE
  thread = nil
  begin
    thread =
      Thread.new(obj) do |obj|
        $SAFE = 12
        obj.instance_eval @rule
      end
    thread.join
  ensure
    $SAFE = safe
  end
  thread.value
end

class << self; alias [] new; end

module Obeyer
  def obey?(*rules)
    rules.flatten.select{|rule| not rule.apply?(self)}.empty? ? true : false
  end
end

end

class Agent
include Rule::Obeyer
attr :color
attr :size
def initialize opts = {}
@color, @size = opts.values_at ‘color’, ‘size’
end
end

agent = Agent.new ‘color’=>‘red’, ‘size’=>42

rules =
Rule[ ‘color == “red” or color == “blue”’ ],
Rule[ ‘size == 42’ ]

p(agent.obey?(rules)) # => true

rules =
Rule[ ‘color == “purple”’ ],
Rule[ ‘size == 42’ ]

p(agent.obey?(rules)) # => false

~ > ruby a.rb
true
false

-a

···

On Wed, 26 May 2004, Florian Weber wrote:

hi!

im trying to define a set of rules with ruby, however i cant find a more
ruby-like way to do so…

instead of doing something like

my_set.add(NotNamedRule(“orange”).new)
my_set.add(HasPropertyRule(“color”).new)
my_set.add(OrRule(HasPropertyRule(“size”).new,
HasPropertyRule(“weight”).new))

(i know this is a horrible example. excuse the awful ‘design’. its
justs to illustrate
what i not wanna have ; )

i wanna do something like

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

can anybody think of a nice way to do this?

thanks a lot for any feedback!

ciao!
florian

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
“640K ought to be enough for anybody.” - Bill Gates, 1981
===============================================================================

Note that while || and && cannot be overloaded, | and & can.

martin

···

Florian Weber csshsh@structbench.com wrote:

can anybody think of a nice way to do this?

thanks a lot for any feedback!

Apply the composite pattern, see
http://c2.com/cgi/wiki?CompositePattern
or
http://unicoi.kennesaw.edu/~jbamford/csis4650/uml/GoF_Patterns/composite.htm

Forget about the addComponent, removeComponent messages. You need a
different way to build composite rules. As in the pattern you need an
abstract class for all components. Call it AbstractRule and build
subclasses for composed rules and concrete rules. Implement messages
like “and”, “or”, etc. in AbstractRule, each of them should return a
composed rule. Depending on your implementation of the composed rules
you might overwrite these messages in composed rules.

Cheers
Sascha

···

Florian Weber csshsh@structbench.com wrote:

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

How about just a simple proc object?

my_set.rules = proc { !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”)) }

Then just do something like obj.instance_eval rules for whatever
object has the methods in your example.

Bill

Florian Weber csshsh@structbench.com wrote in message news:D83A07D2-AE5C-11D8-A68B-000A95BD142E@structbench.com

···

hi!

im trying to define a set of rules with ruby, however i cant find a more
ruby-like way to do so…

instead of doing something like

my_set.add(NotNamedRule(“orange”).new)
my_set.add(HasPropertyRule(“color”).new)
my_set.add(OrRule(HasPropertyRule(“size”).new,
HasPropertyRule(“weight”).new))

(i know this is a horrible example. excuse the awful ‘design’. its
justs to illustrate
what i not wanna have ; )

i wanna do something like

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

can anybody think of a nice way to do this?

thanks a lot for any feedback!

ciao!
florian

Assuming you have a specific class you created that needs to be
compared to a set of rules, here’s one way:

basically i wanna define aop pointcuts in ruby… something like

execution(“.someMe”) && (this(“SomeCl*”) && !this(“SomeClazz”))

Hi,

At Wed, 26 May 2004 06:28:44 +0900,
Ara.T.Howard wrote in [ruby-talk:101411]:

if you like dangerous code, you might try something like this:

~ > cat a.rb
class Rule
def initialize rule; @rule = rule.to_str; end

def apply? obj
  safe = $SAFE
  thread = nil
  begin
    thread =
      Thread.new(obj) do |obj|
        $SAFE = 12
        obj.instance_eval @rule
      end
    thread.join
  ensure
    $SAFE = safe
  end
  thread.value
end

You don’t need save $SAFE, which is always thread local. And,
Proc also preserves its $SAFE value. Though this was an
unofficial feature in 1.6, guaranteed from 1.8.

···


Nobu Nakada

This really isn’t particularly what you’re after, but here’s a nibble
that will evaluate an array that is assumed to be flip-flopping
between ands and ors. The simple case will be DNF or CNF.

def or_rule conditions
if conditions.is_a? Array
conditions.each do |element| return true if and_rule(element) end
false
else
true && conditions
end
end

def and_rule conditions
if conditions.is_a? Array
result = true
conditions.each do |element| result &&= or_rule(element) end
result
else
true && conditions
end
end

and_rule([true, [false, false]]) ==> (true AND (false OR false)) ==> false
and_rule([true, [true, false]]) ==> (true AND (true OR false)) ==> true
and_rule([true, [[true, false], false]]) ==> (true AND ((true AND
false) OR false)) ==> false
and_rule([true, [[true, true], false]]) ==> (true AND ((true AND true)
OR false)) ==> true

Anyway, it’s a similar topic, so I thought I would post it. The only
abnormality is that and_rule() is true, or_rule() is false, and
and_rule([]) is false.

Alex

···

On Wed, 26 May 2004 19:38:44 +0900, Sascha Doerdelmann wsdngtmp@onlinehome.de wrote:

Florian Weber csshsh@structbench.com wrote:

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

Apply the composite pattern, see
http://c2.com/cgi/wiki?CompositePattern
or
http://unicoi.kennesaw.edu/~jbamford/csis4650/uml/GoF_Patterns/composite.htm

Forget about the addComponent, removeComponent messages. You need a
different way to build composite rules. As in the pattern you need an
abstract class for all components. Call it AbstractRule and build
subclasses for composed rules and concrete rules. Implement messages
like “and”, “or”, etc. in AbstractRule, each of them should return a
composed rule. Depending on your implementation of the composed rules
you might overwrite these messages in composed rules.

Cheers
Sascha

Guillaume Marcais guslist@free.fr wrote in message news:1085504342.29598.2.camel@comp

Kansas, written by Kirk Haines, has such a conditions system to write
SQL queries. You may want to check it out:

http://enigo.com/projects/kansas/index.html

Guillaume.

Other examples to check out would include:

Probably this sort of thing is easier if you have an object that’s
explicitly the receiver of the various methods. So instead of what
you’d originally asked:

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

It might be easier to define something that looks like:

my_set.createRules { |set|
set.name(‘orange’).not & set.hasProperty(‘color’) &
( set.hasProperty(‘size’) | set.hasProperty(‘weight’)
}

Inside the block, the variable “set” is actually a special object that
pretends to be a set but really has funny methods defined to create
the various Rule primitives you’ve already defined. This is how I
implemented it in Lafcadio and it’s worked well so far.

One other note: Beyond the fact that you can’t override && and ||, you
also cannot override unary negation, so you get no control over what
!name(‘orange’) means. That’s why in the example code I wrote it calls
set.name(‘orange’).not instead … if you make it a method you can do
whatever’s necessary.

Francis

Wow. I liked that idea so much that I whipped together a script to
prove to myself it works. Damn do I love Ruby… This is of course
with just a single class, but it is easy to see the power in something
along these lines, being able to have a mixin module or parent class
which defines an interface, and children that implement different
methods for different rules.

class Test
attr_accessor :properties

def initialize default_properties=Hash.new
    @properties = default_properties
end

def has_property? key
    @properties.has_key? key
end

def property_is? key, value
    has_property?(key) && @properties[key] == value
end

def evaluate_condition(closure = nil, &block)
    return instance_eval(&closure) if closure.kind_of? Proc
    return instance_eval(&block) if block_given?
    nil
end

end

test1 = Test.new({‘color’ => ‘red’, ‘shape’ => ‘apple’, ‘taste’ =>
‘yum’, ‘fans’ => ‘none’})
test2 = Test.new({‘color’ => ‘black’, ‘shape’ => ‘car’, ‘engine’ =>
‘ass kickin’, ‘fans’ => ‘several’})
test3 = Test.new({‘color’ => ‘white’, ‘shape’ => ‘ibook’, ‘engine’ =>
‘g3’, ‘fans’ => ‘none’})
test_objects = [test1, test2, test3]

car_test = proc {has_property?(‘engine’) && property_is?(‘shape’, ‘car’)}
apple_test = proc {property_is?(‘shape’, ‘apple’)}
corporeal_test = proc {has_property?(‘shape’)}

puts ‘testing for a car…’
test_objects.each do |object| puts
object.evaluate_condition(car_test).inspect end

puts ‘testing for an apple…’
test_objects.each do |object| puts
object.evaluate_condition(apple_test).inspect end

puts ‘testing for corporeal objects…’
test_objects.each do |object| puts
object.evaluate_condition(corporeal_test).inspect end

puts ‘block test…’
test_objects.each do |object| puts (object.evaluate_condition
{has_property?(‘color’) && property_is?(‘fans’, ‘none’)}).inspect end

···

On Sun, 30 May 2004 02:08:38 +0900, Bill Atkins dejaspam@batkins.com wrote:

How about just a simple proc object?

my_set.rules = proc { !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”)) }

Then just do something like obj.instance_eval rules for whatever
object has the methods in your example.

Bill

Florian Weber csshsh@structbench.com wrote in message news:D83A07D2-AE5C-11D8-A68B-000A95BD142E@structbench.com

hi!

im trying to define a set of rules with ruby, however i cant find a more
ruby-like way to do so…

instead of doing something like

my_set.add(NotNamedRule(“orange”).new)
my_set.add(HasPropertyRule(“color”).new)
my_set.add(OrRule(HasPropertyRule(“size”).new,
HasPropertyRule(“weight”).new))

(i know this is a horrible example. excuse the awful ‘design’. its
justs to illustrate
what i not wanna have ; )

i wanna do something like

my_set.rules = !name(“orange”) && hasProperty(“color”) &&
(hasProperty(“size”) || hasProperty(“weight”))

can anybody think of a nice way to do this?

thanks a lot for any feedback!

ciao!
florian

Hm. Didn’t know that. Also, methods preserve $SAFE:

def foo; $SAFE=3; end

=> nil

$SAFE

=> 0

foo

=> 3

$SAFE

=> 0

···

nobu.nokada@softhome.net wrote:

You don’t need save $SAFE, which is always thread local. And,
Proc also preserves its $SAFE value. Though this was an
unofficial feature in 1.6, guaranteed from 1.8.

Hi,

At Wed, 26 May 2004 08:13:25 +0900,
Joel VanderWerf wrote in [ruby-talk:101419]:

You don’t need save $SAFE, which is always thread local. And,
Proc also preserves its $SAFE value. Though this was an
unofficial feature in 1.6, guaranteed from 1.8.

Hm. Didn’t know that. Also, methods preserve $SAFE:

def foo; $SAFE=3; end

=> nil

$SAFE

=> 0

foo

=> 3

$SAFE

=> 0

Do you mean Method object?

$ ruby19 -ve ‘def foo;$SAFE=3;$SAFE;end;p method(:foo).call;p $SAFE’
ruby 1.9.0 (2004-05-25) [i686-linux]
3
0

$ ruby19 -ve ‘def foo;$SAFE=3;$SAFE;end;p foo;p $SAFE’
ruby 1.9.0 (2004-05-25) [i686-linux]
3
3

$ ruby18 -ve ‘def foo;$SAFE=3;$SAFE;end;p foo;p $SAFE’
ruby 1.8.2 (2004-05-24) [i686-linux]
3
3

···


Nobu Nakada

I was confused by irb:

$ irb
irb(main):001:0> def foo; $SAFE=3; end; foo; $SAFE
=> 3
irb(main):002:0> $SAFE
=> 0
irb(main):003:0> $SAFE = 3
=> 3
irb(main):002:0> $SAFE
=> 0

So it is really irb that is saving and restoring $SAFE around each input
line. Maybe this is because irb is wrapping the input into a Proc.

···

nobu.nokada@softhome.net wrote:

Hi,

At Wed, 26 May 2004 08:13:25 +0900,
Joel VanderWerf wrote in [ruby-talk:101419]:

You don’t need save $SAFE, which is always thread local. And,
Proc also preserves its $SAFE value. Though this was an
unofficial feature in 1.6, guaranteed from 1.8.

Hm. Didn’t know that. Also, methods preserve $SAFE:

def foo; $SAFE=3; end

=> nil

$SAFE

=> 0

foo

=> 3

$SAFE

=> 0

Do you mean Method object?

$ ruby19 -ve ‘def foo;$SAFE=3;$SAFE;end;p method(:foo).call;p $SAFE’
ruby 1.9.0 (2004-05-25) [i686-linux]
3
0

$ ruby19 -ve ‘def foo;$SAFE=3;$SAFE;end;p foo;p $SAFE’
ruby 1.9.0 (2004-05-25) [i686-linux]
3
3

$ ruby18 -ve ‘def foo;$SAFE=3;$SAFE;end;p foo;p $SAFE’
ruby 1.8.2 (2004-05-24) [i686-linux]
3
3