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? 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: ---- # 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