class Noteikumi::Rule

A class that represents an individual rule used by the engine

Rules are generally stored in files named something_rule.rb in a rule directory, there are several samples of these in the examples dir and in docs on the wiki at GitHub

Attributes

concurrent[R]

The concurrency safe level @api private @see {concurrency=} @return [:safe, :unsafe]

conditions[R]

Named conditions for this rule @api private @see {condition} @return [Hash]

file[RW]

The file the rule was found in @api private @return [String]

logger[RW]

The logger used by this rule @api private @return [Logger]

name[RW]

The rule name @api private @return [String,Symbol]

needs[R]

Items the rule expect on the state @api private @see {requirement} @return [Array]

priority[R]

The priority for this fule @return [Fixnum]

run_condition[R]

The run conditions for this rule @api private @see {run_when} @return [Proc]

run_count[R]

How many times this rule have been run @api private @return [Fixnum]

run_logic[R]

The logic to run @api private @see {run} @return [Proc]

state[R]

The state this rule is being evaluated against @api private @return [State,nil]

Public Class Methods

new(name) click to toggle source

Creates a new rule

@param name [String,Symbol] the name of the rule @return [Rule]

# File lib/noteikumi/rule.rb, line 71
def initialize(name)
  @name = name
  @priority = 500
  @concurrent = :unsafe
  @needs = []
  @conditions = {}
  @state = nil
  @file = "unknown file"
  @run_count = 0

  run_when { true }
  run { raise("No execution logic provided for rule") }
end

Public Instance Methods

assign_state(state) click to toggle source

Assign the provided state to the rule

@param state [State] the state to store @return [void]

# File lib/noteikumi/rule.rb, line 98
def assign_state(state)
  @state = state
end
has_condition?(condition) click to toggle source

Checks if a condition matching the name has been created on the rule

@see {#condition} @param condition [Symbol] condition name @return [Boolean]

# File lib/noteikumi/rule.rb, line 90
def has_condition?(condition)
  @conditions.include?(condition)
end
new_result() click to toggle source

Construct a result object for this rule

@return [Result]

# File lib/noteikumi/rule.rb, line 155
def new_result
  Result.new(self)
end
process(state) click to toggle source

Process a rule after first checking all the requirements are met

@param state [State] the state to use as scope @return [Result,nil] nil when the rule never ran due to state checks

# File lib/noteikumi/rule.rb, line 163
def process(state)
  result = nil

  with_state(state) do
    if state_meets_requirements?
      if satisfies_run_condition?
        logger.debug("Processing rule %s" % self)
        result = run_rule_logic
      else
        logger.debug("Skipping processing rule due to run_when block returning false on %s" % self)
      end
    else
      logger.debug("Skipping processing rule %s due to state check failing" % self)
    end
  end

  result
end
reset_counter() click to toggle source

Resets the run count for the rule to 0

@return [void]

# File lib/noteikumi/rule.rb, line 112
def reset_counter
  @run_count = 0
end
reset_state() click to toggle source

Resets the state to nil state

@return [void]

# File lib/noteikumi/rule.rb, line 105
def reset_state
  @state = nil
end
run_rule_logic() click to toggle source

Runs the rule logic

Rules are run within an instance of {RuleExecutionScope}

@return [Result]

# File lib/noteikumi/rule.rb, line 133
def run_rule_logic
  @run_count += 1

  result = new_result

  begin
    result.start_processing
    result.output = RuleExecutionScope.new(self).run
  rescue => e
    logger.error("Error during processing of rule: %s: %s: %s" % [self, e.class, e.to_s])
    logger.debug(e.backtrace.join("\n\t"))
    result.exception = e
  ensure
    result.stop_processing
  end

  result
end
satisfies_run_condition?() click to toggle source

Determines if the run_when block is satisfied

@return [Boolean]

# File lib/noteikumi/rule.rb, line 185
def satisfies_run_condition?
  validator = RuleConditionValidator.new(self)
  validator.__should_run?
end
state_meets_requirements?() click to toggle source

Checks every requirement against the state

@return [Boolean]

# File lib/noteikumi/rule.rb, line 193
def state_meets_requirements?
  @needs.each do |requirement|
    valid, reason = state.meets_requirement?(requirement)

    unless valid
      logger.debug("State does not meet the requirements %s: %s" % [self, reason])
      return false
    end
  end

  true
end
with_state(state) { || ... } click to toggle source

Assigns the state, yields to the block and resets it

@param state [State] a state to act on @return [Object] the outcome from the block

# File lib/noteikumi/rule.rb, line 120
def with_state(state)
  assign_state(state)

  yield
ensure
  reset_state
end