#13 ✓invalid
max

Misbehaving rule

Reported by max | December 23rd, 2008 @ 05:31 AM | in 0.5

I'm playing around with rules which pick the 'biggest' among the instances of a class. Currently I have the following:


require 'rubygems'
require 'ruleby'

include Ruleby


class Sortable
  attr_reader :index
  
  @@biggest = nil
  
  def self.Biggest=(sortable)
    puts ">> Biggest #{sortable}"
    @@biggest = sortable
  end

  def self.Biggest()
    puts ">> Current biggest is #{@@biggest}"
    @@biggest
  end
  
  def initialize(index)
    @index = index
  end  
  
  def to_s
    "Sortable #{index}"
  end
end


class SortingRulebook < Rulebook
  def rules
  

    rule :SortInit,
      [Class, :c, m.name == 'Sortable', m.Biggest(&c{|inst| inst == nil})],
      [Sortable, :s] do |vars|
        Sortable.Biggest = vars[:s]
        puts "Initialize sortable to #{vars[:s]} (#{vars[:c]})"
        modify vars[:c]
    end

    rule :Sort,
      [Class, :c, m.name == 'Sortable', m.Biggest(&c{|inst| puts "Check NON-nil"; inst != nil})],
      [Sortable, :s, m.index(&c {|index| res = (index > Sortable.Biggest.index); puts "Index #{index}:#{res}"; res })] do |vars|
        raise "Why ignore index > Sortable.Biggest.index" if Sortable.Biggest == vars[:s]
        Sortable.Biggest = vars[:s]
        puts "#{vars[:s]} is bigger (#{vars[:c]})"
        modify vars[:c]
    end
    
  end
end


i1 = Sortable.new(1)
i2 = Sortable.new(2)
i3 = Sortable.new(3)
i4 = Sortable.new(4)

Sortable.Biggest = i1

engine :engine do |e|
  SortingRulebook.new(e).rules
  
  e.assert Sortable
  e.assert i4
  e.assert i3
  e.assert i2
  e.assert i1
  
  e.match
end

When I run it, I get:


$ ruby sort_order2.rb 
>> Biggest Sortable 1
>> Current biggest is Sortable 1
>> Current biggest is Sortable 1
Check NON-nil
>> Current biggest is Sortable 1
>> Current biggest is Sortable 1
Index 4:true
>> Current biggest is Sortable 1
Index 3:true
>> Current biggest is Sortable 1
Index 2:true
>> Current biggest is Sortable 1
Index 1:false
>> Current biggest is Sortable 1
>> Biggest Sortable 2
Sortable 2 is bigger (Sortable)
>> Current biggest is Sortable 2
>> Current biggest is Sortable 2
Check NON-nil
>> Current biggest is Sortable 2
>> Current biggest is Sortable 2
sort_order2.rb:51:in `rules': Why ignore index > Sortable.Biggest.index (RuntimeError)
	from /Library/Ruby/Gems/1.8/gems/ruleby-0.4/lib/core/engine.rb:34:in `call'
	from /Library/Ruby/Gems/1.8/gems/ruleby-0.4/lib/core/engine.rb:34:in `fire'
	from /Library/Ruby/Gems/1.8/gems/ruleby-0.4/lib/core/engine.rb:60:in `fire'
	from /Library/Ruby/Gems/1.8/gems/ruleby-0.4/lib/core/engine.rb:226:in `match'
	from sort_order2.rb:77
	from /Library/Ruby/Gems/1.8/gems/ruleby-0.4/lib/ruleby.rb:19:in `engine'
	from sort_order2.rb:68

Doesn't seem to be right.

Comments and changes to this ticket

  • jpkutner (at gmail)

    jpkutner (at gmail) December 28th, 2008 @ 07:46 PM

    • Milestone set to 0.5
    • State changed from “new” to “open”
    • Assigned user set to “jpkutner (at gmail)”
  • jpkutner (at gmail)

    jpkutner (at gmail) December 28th, 2008 @ 08:23 PM

    • State changed from “open” to “invalid”

    This is not a bug. The rule is written incorrectly. There are two ways this rule could be written properly.

    1)

    
        rule :Sort,
          [Class, :c, m.name == 'Sortable', m.Biggest(&c{|inst| puts "Check NON-nil"; inst != nil})],
          [Sortable, :s, m.index(:c, &c {|index, c| res = (index > c.Biggest.index); puts "Index #{index}:#{res}"; res })] do |vars|
            raise "Why ignore index(#{vars[:s]}) > Sortable.Biggest.index" if Sortable.Biggest == vars[:s]
            puts "#{vars[:s]} is bigger (#{vars[:c].Biggest})"
            Sortable.Biggest = vars[:s]
            modify vars[:c]
        end    
    

    In this case, we create a reference to the Sortable class, because that is the fact that is being modified. The alternative is:

    2)

    
        rule :Sort,
          [Class, :c, m.name == 'Sortable', m.Biggest(&c{|inst| puts "Check NON-nil"; inst != nil})],
          [Sortable, :s, m.index(&c {|index, c| res = (index > Sortable.Biggest.index); puts "Index #{index}:#{res}"; res })] do |vars|
            raise "Why ignore index(#{vars[:s]}) > Sortable.Biggest.index" if Sortable.Biggest == vars[:s]
            puts "#{vars[:s]} is bigger (#{vars[:c].Biggest})"
            Sortable.Biggest = vars[:s]
            modify vars[:s]
        end    
    

    Here we have changed the modify call in the RHS to modify the Sortable instance rather than the class. This will cause the second pattern to be reevaluated. That was the original problem -- th engine did not recognize that the Sortable instance fact was modified, and never reevaluated any patterns related to it.

    Thanks for the submission.

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป

the Rule Engine for Ruby

People watching this ticket

Pages