Class: Rools::Rule

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#logger, logger=

Constructor Details

#initialize(rule_set, name, priority, b) ⇒ Rule

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



13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/rools/rule.rb', line 13

def initialize(rule_set, name, priority, b)
  @rule_set     = rule_set
  @name         = name
  @priority     = priority
  @conditions   = []
  @consequences = []
  @parameters   = []
  
  begin
    instance_eval(&b) if b
  rescue Exception => e
    raise RuleCheckError.new( self, e)
  end
end

Instance Attribute Details

#conditionsObject (readonly)

Returns the value of attribute conditions.



8
9
10
# File 'lib/rools/rule.rb', line 8

def conditions
  @conditions
end

#consequencesObject (readonly)

Returns the value of attribute consequences.



8
9
10
# File 'lib/rools/rule.rb', line 8

def consequences
  @consequences
end

#nameObject (readonly)

Returns the value of attribute name.



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

def name
  @name
end

#parameters(*matches) ⇒ Object (readonly) 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



62
63
64
# File 'lib/rools/rule.rb', line 62

def parameters
  @parameters
end

#priorityObject (readonly)

Returns the value of attribute priority.



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

def priority
  @priority
end

#rule_setObject (readonly)

Returns the value of attribute rule_set.



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

def rule_set
  @rule_set
end

Instance Method Details

#assert(obj) ⇒ Object

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



123
124
125
# File 'lib/rools/rule.rb', line 123

def assert(obj)
  @rule_set.rule_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.



130
131
132
133
134
135
136
137
138
139
140
# File 'lib/rools/rule.rb', line 130

def call(obj)
  begin
    @consequences.each do |c|
      c.call(obj)
    end
  rescue Exception => e
    # discontinue the Rools::RuleSet#assert if any consequence fails
    logger.error( "rule RuleConsequenceError #{e.to_s} #{e.backtrace.join("\n")}") if logger
    raise RuleConsequenceError.new(self, 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 }


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

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)


111
112
113
114
115
116
117
118
119
120
# File 'lib/rools/rule.rb', line 111

def conditions_match?(obj)
  begin
    @conditions.each { |c| return false unless c.call(obj) }
  rescue StandardError => e
    logger.error( "conditions_match? StandardError #{e} #{e.backtrace.join("\n")}") if logger
    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! }


43
44
45
# File 'lib/rools/rule.rb', line 43

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

#fail(message = nil) ⇒ Object

Stops the current assertion and change status to :fail



148
149
150
# File 'lib/rools/rule.rb', line 148

def fail(message = nil)
  @rule_set.fail(message)
end

#get_parametersObject

returns parameters of rule



71
72
73
# File 'lib/rools/rule.rb', line 71

def get_parameters
  @parameters
end

#parameters_match?(obj) ⇒ Boolean

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

Returns:

  • (Boolean)


80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/rools/rule.rb', line 80

def parameters_match?(obj)
  # if parameters are not specified, let's assume that the rule is always relevant
  if @parameters.size == 0
    logger.debug "no parameters defined for rule: #{self}" if logger
    return true
  end
  
  @parameters.each do |params|
    match = false
    
    params.each do  |p|
      logger.debug( "#{self} match p:#{p} obj:#{obj}") if logger
    
      if p.is_a?(Symbol) 
        if obj.respond_to?(p)
          match = true
        else
          return false
        end
      elsif obj.is_a?(p)
        match = true
      end
    end
    return true if match
  end
 
  return false
end

#stop(message = nil) ⇒ Object

Stops the current assertion. Does not indicate failure.



143
144
145
# File 'lib/rools/rule.rb', line 143

def stop(message = nil)
  @rule_set.stop(message)
end

#to_sObject



152
153
154
# File 'lib/rools/rule.rb', line 152

def to_s
  @name
end