Class: PyrRules::Rule

Inherits:
Object
  • Object
show all
Includes:
Mongoid::Document, Mongoid::Timestamps::Short, Mongoid::Versioning, ModelEventEmitter
Defined in:
app/models/pyr_rules/rule.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ModelEventEmitter

included, model_actions, registered_classes

Class Method Details

.get_columns(klazz) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'app/models/pyr_rules/rule.rb', line 172

def self.get_columns(klazz)
  cols = {}
  if klazz.respond_to? :reflect_on_all_associations
    (klazz.reflect_on_all_associations(:has_one) +
    klazz.reflect_on_all_associations(:belongs_to)).each do |assoc| 
      cols[assoc.name] = assoc.name.to_sym
    end
  end
  if klazz.respond_to? :columns   # ActiveRecord
    klazz.columns.each{|c| cols[c.name] = c.type.to_sym }
  end
  if klazz.respond_to? :fields    # Mongoid
    fields.each{|k,v| cols[v.name] = v.options[:type].name.downcase.to_sym }
  end
  cols
end

.rule_context(rule_event, extra_fields = {}) ⇒ Object



103
104
105
# File 'app/models/pyr_rules/rule.rb', line 103

def self.rule_context(rule_event, extra_fields = {})
  PyrRules::RuleContext.new rule_event, extra_fields
end

Instance Method Details

#check_criteria(rule_event) ⇒ Object



107
108
109
110
111
112
# File 'app/models/pyr_rules/rule.rb', line 107

def check_criteria(rule_event)
  return false unless events && events.index("#{rule_event[:klazz]}::#{rule_event[:action]}")
  return true if criteria.blank?
  result = eval criteria, PyrRules::Rule.rule_context(rule_event).get_binding
  result
end

#contextObject

Determine overall Rule-scoped context via intersection all event-scoped contexts



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'app/models/pyr_rules/rule.rb', line 66

def context
  rc = {}
  return rc if events == nil || events.size == 0
  events.each_with_index do |e,i|
    ec = PyrRules::RulesConfig.event_config(e)[:context] rescue {}
    if i == 0
      rc.merge!(ec)  # start with the first event's context
    else
      rc.each do |field, |
        if ec[field] == nil
          rc.delete field     # this event did not have the field, it cannot be in our interesected context
        elsif ec[field] != rc[field]
          rc.delete field     # this event had the field, but it was a different type, it cannot be in our intersected context
        end
      end
    end
  end
  HashWithIndifferentAccess.new(rc)
end

#context_field_mapped?(field, type) ⇒ Boolean

Returns:

  • (Boolean)


86
87
88
89
90
91
92
# File 'app/models/pyr_rules/rule.rb', line 86

def context_field_mapped?(field,type)
  lookup = "#{field}:#{type}"
  actions.each do |a|
    return true if a.context_mapping.values.index lookup rescue false
  end
  false
end

#lookup_path(path, sub_context = nil) ⇒ Object

called like : lookup_path(“target”)

or : lookup_path("target.user")


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'app/models/pyr_rules/rule.rb', line 116

def lookup_path(path, sub_context = nil)
  return context if (path.blank? || path == "/") && !sub_context   # Default for retrieving root context path
  # path = "target.user"    parts[0]="target"  parts[1]="user"
  parts = path.split(".")
  if sub_context.nil?
    if parts.first == "actor"
      parts.shift
      path=parts.join(".")
      klazz = User
      return lookup_path(path, User) unless path.blank?
    elsif parts.first == "target"
      parts.shift
      path=parts.join(".")
      cols = nil
      # We need to get all the possible path values from all the input events
      events.each do |event|
        klazz = (event.split("::")[0...-1].join("::")).constantize
        puts klazz
        sub_cols = lookup_path(path, klazz)
        puts sub_cols
        cols ||= sub_cols
        # This will perform an intersection across all the event fields 
        cols.each do |k,v|
          unless sub_cols[k]==v
            puts "Removing due to intersection #{k}"
            cols.delete k
          end
        end
      end
      puts "Returning"
      puts cols
      return cols
    end
  end
  klazz ||= sub_context || self

  cols = {}
  if parts.length == 0
    cols = get_columns(klazz)
  else
    puts "DBH: What is this use case?  I can't remember why I coded it?"
    if klazz.respond_to? :reflect_on_all_associations
      (klazz.reflect_on_all_associations(:has_one) +
      klazz.reflect_on_all_associations(:belongs_to)).each do |assoc| 
        if (assoc.name.to_s == parts.first)
          parts.shift
          path=parts.join(".")
          klazz = assoc.klass
          return lookup_path(path, klazz)
        end
      end
    end
  end
  cols
end

#process_rule(event) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'app/models/pyr_rules/rule.rb', line 46

def process_rule(event)
  return unless check_criteria event
  actions.each do |action|
    begin
      action_handler = action.type
      klass = action_handler if action_handler.is_a? Class
      #Module.const_get(action_handler) doesn't work for nested classes
      #We can use String.constantize (ActiveSupport extension for string)
      #or eval works for sure.
      klass = action_handler.constantize rescue nil if action_handler.is_a? String  
      klass.new(event, action).handle if klass
    rescue Exception => e 
      puts "\nERROR: Running action #{action.type} for rule #{name}: #{e.message}\n"
      puts e.backtrace
    end
  end
end

#ready?Boolean

validates_each :events do |record, attr, event_list|

if event_list 
  event_list.each do |e|
    record.errors.add(attr, 'should be a valid event') unless PyrRules::RulesConfig.event e
  end
end

end

Returns:

  • (Boolean)


41
42
43
44
# File 'app/models/pyr_rules/rule.rb', line 41

def ready?
  return false unless actions
  ! actions.collect{|a| a.ready?}.index false rescue false
end

#set_default_mappingsObject



95
96
97
98
99
100
101
# File 'app/models/pyr_rules/rule.rb', line 95

def set_default_mappings
    puts "Setting default action mappings"
    rule_context = context   #  {:actor=>:user, :target=>:object, etc...}
    actions.each do |a|
      a.set_default_mappings(rule_context)
    end
end