Class: Rulengine::Rule

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/rulengine/rule.rb

Constant Summary collapse

InvalidRuleSet =
Class.new StandardError

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.apply_all_rules(data, run_count = 1) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rulengine/rule.rb', line 41

def self.apply_all_rules(data, run_count=1)
  # Run twice ensures there are no deep circular conflicts
  data = data.to_set
  state_history = Set.new([data])

  # run_count = (run_twice && 2) || 1
  (1..run_count).each do |_|
    Rulengine::Rule.all.each do |rule|
      # orig_state = self #.deep_copy
      data_was = data
      data = rule.apply_to(data)
      if data_was != data
        if state_history.include? data.to_set
          raise InvalidRuleSet, [rule, state_history, ]# "Breaking input: #{state_history.first}"]
        end
        state_history.add data.to_set
      end
    end
  end

  # puts state_history
  data
end

.find_conflictsObject

Don’t pass data, generate it!



31
32
33
34
35
36
37
38
39
# File 'lib/rulengine/rule.rb', line 31

def self.find_conflicts # Don't pass data, generate it!
  list_all_combinations.each do |data|
    puts "Testing combination: #{data}"
    data = apply_all_rules(data)
    apply_all_rules(data)
  end
  # data = apply_all_rules(data)
  # apply_all_rules(data)
end

.list_all_combinationsObject



20
21
22
23
24
25
26
27
28
# File 'lib/rulengine/rule.rb', line 20

def self.list_all_combinations
  # Shortcut, can be greatly optimized
  left = Rulengine::Rule.all.pluck(:given, :unless_given).flatten.to_set
  right = Rulengine::Rule.all.pluck(:action).map(&:values).flatten.to_set
  vars = left + right - [nil]
  # For optimization, remove to_a (less readable)
  (1..vars.count).flat_map{ |size| vars.to_a.combination(size).to_a }

end

Instance Method Details

#applies?(data) ⇒ Boolean

Returns:

  • (Boolean)


89
90
91
92
93
94
95
96
97
98
# File 'lib/rulengine/rule.rb', line 89

def applies?(data)
  if unless_given
    return false if (data & unless_given).present?
  end
  if given
    return false unless given.to_set.subset? data
  end

  true
end

#apply_to(data) ⇒ Object

Not_given refers to something that MUST NOT be given



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rulengine/rule.rb', line 67

def apply_to(data)
  # data = data.data if data.is_a? State
  data = data.to_set unless data.is_a? Set
  if applies?(data)

    # Refactor action into classes with `perform`
    action.each do |k, v|
      if k.eql? 'add'
        data += (v || [])
      elsif k.eql? 'remove'
        data -= (v || [])
      else
        puts k, v
        raise NotImplementedError
      end
    end
    # self.save!
  end

  data
end