Class: Rools::Rule

Inherits:
Object
  • Object
show all
Defined in:
lib/rools/rule.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rule_set, name, b) ⇒ Rule

A Rule requires a Rools::RuleSet, a name, and an associated block which will be executed at initialization



10
11
12
13
14
15
16
17
18
19
# File 'lib/rools/rule.rb', line 10

def initialize(rule_set, name, b)
  @rule_set = rule_set
  @name = name
  
  @conditions = []
  @consequences = []
  @parameters = []
  
  instance_eval(&b)
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



6
7
8
# File 'lib/rools/rule.rb', line 6

def name
  @name
end

Instance Method Details

#assert(obj) ⇒ Object

Calls Rools::RuleSet#assert in the bound working-set



89
90
91
# File 'lib/rools/rule.rb', line 89

def assert(obj)
  @rule_set.assert(obj)
end

#call(obj) ⇒ Object

Execute each consequence. Any StandardErrors are caught and wrapped in Rools::RuleConsequenceError, then raised to break out of the current assertion.



96
97
98
99
100
101
102
103
104
105
# File 'lib/rools/rule.rb', line 96

def call(obj)
  begin
    @consequences.each do |c|
      c.call(obj)
    end
  rescue StandardError => e
    # discontinue the Rools::RuleSet#assert if any consequence fails
    raise RuleConsequenceError.new(rule, e)
  end
end

#condition(&b) ⇒ Object

Adds a condition to the Rule. For readability, it might be preferrable to use a new condition for every evaluation when possible.

Example

condition { person.name == 'Fred' }
condition { person.age > 18 }

As opposed to:

condition { person.name == 'Fred' && person.age > 18 }


29
30
31
# File 'lib/rools/rule.rb', line 29

def condition(&b)
  @conditions << DefaultParameterProc.new(self, b)
end

#conditions_match?(obj) ⇒ Boolean

Checks to see if this Rule’s conditions match the asserted object Any StandardErrors are caught and wrapped in RuleCheckErrors, then raised.

Returns:

  • (Boolean)


78
79
80
81
82
83
84
85
86
# File 'lib/rools/rule.rb', line 78

def conditions_match?(obj)
  begin
    @conditions.each { |c| return false unless c.call(obj) }
  rescue StandardError => e
    raise RuleCheckError.new(self, e)
  end
  
  return true
end

#consequence(&b) ⇒ Object

Adds a consequence to the Rule

Example

consequence { user.failed_logins += 1; user.save! }


36
37
38
# File 'lib/rools/rule.rb', line 36

def consequence(&b)
  @consequences << DefaultParameterProc.new(self, b)
end

#parameters(*matches) ⇒ Object Also known as: parameter

Sets the parameters of the Rule

Example

parameters Person, :name, :occupation

The arguments passed are evaluated with :is_a? for each constant-name passed, and :responds_to? for each symbol. So the above example would be the same as:

obj.is_a?(Person) &&
  obj.responds_to?(:name) &&
  obj.responds_to?(:occupation)

You can pass any combination of symbols or constants. You might want to refrain from referencing constants to aid in “duck-typing”, or you might want to use parameters such as:

parameters Person, Employee, :department

To verify that the asserted object is an Employee, that inherits from Person, and responds to :department



55
56
57
# File 'lib/rools/rule.rb', line 55

def parameters(*matches)
  @parameters += matches
end

#parameters_match?(obj) ⇒ Boolean

Checks to see if this Rule’s parameters match the asserted object

Returns:

  • (Boolean)


64
65
66
67
68
69
70
71
72
73
74
# File 'lib/rools/rule.rb', line 64

def parameters_match?(obj)
  @parameters.each do |p|
    if p.is_a?(Symbol)
      return false unless obj.respond_to?(p)
    else
      return false unless obj.is_a?(p)
    end
  end
  
  return true
end