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



109
110
111
# File 'lib/rools/rule.rb', line 109

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.



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rools/rule.rb', line 116

def call(obj)
  begin
    @consequences.each do |c|
      c.call(obj)
    end
  rescue StandardError => 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(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 }


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)


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

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



134
135
136
# File 'lib/rools/rule.rb', line 134

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

#parameters_match?(obj) ⇒ Boolean

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

Returns:

  • (Boolean)


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rools/rule.rb', line 72

def parameters_match?(obj)
  @parameters.each do |p|
    logger.debug( "#{self} match p:#{p} obj:#{obj} sym:#{Symbol}") if logger
    if p.is_a?(Symbol)
      #return false unless obj.respond_to?(p)
      return true if obj.respond_to?(p)
    else
      logger.debug( "#{self} is_a p:#{p} obj:#{obj} #{obj.is_a?(p)}") if logger
      #return false unless obj.is_a?(p)
      return true if obj.is_a?(p)
    end
  end
  
  # 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
  
  logger.debug( "no parameter match") if logger
  return false
end

#stop(message = nil) ⇒ Object

Stops the current assertion. Does not indicate failure.



129
130
131
# File 'lib/rools/rule.rb', line 129

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

#to_sObject



138
139
140
# File 'lib/rools/rule.rb', line 138

def to_s
  @name
end