Browse Source

Merge branch 'fix-issue-1222'

Akinori MUSHA 9 years ago
parent
commit
4fb7ca3316

+ 44 - 45
app/models/agents/event_formatting_agent.rb

@@ -95,8 +95,6 @@ module Agents
       ]
     end
 
-    after_save :clear_matchers
-
     def validate_options
       errors.add(:base, "instructions and mode need to be present.") unless options['instructions'].present? && options['mode'].present?
 
@@ -120,12 +118,15 @@ module Agents
     end
 
     def receive(incoming_events)
+      matchers = compiled_matchers
+
       incoming_events.each do |event|
         interpolate_with(event) do
-          interpolation_context.merge(perform_matching(event.payload))
-          formatted_event = interpolated['mode'].to_s == "merge" ? event.payload.dup : {}
-          formatted_event.merge! interpolated['instructions']
-          create_event :payload => formatted_event
+          apply_compiled_matchers(matchers, event) do
+            formatted_event = interpolated['mode'].to_s == "merge" ? event.payload.dup : {}
+            formatted_event.merge! interpolated['instructions']
+            create_event payload: formatted_event
+          end
         end
       end
     end
@@ -164,49 +165,47 @@ module Agents
       end
     end
 
-    def perform_matching(payload)
-      matchers.inject(payload.dup) { |hash, matcher|
-        matcher[hash]
-      }
+    def compiled_matchers
+      if matchers = options['matchers']
+        matchers.map { |matcher|
+          regexp, path, to = matcher.values_at(*%w[regexp path to])
+          [Regexp.new(regexp), path, to]
+        }
+      end
     end
 
-    def matchers
-      @matchers ||=
-        if matchers = options['matchers']
-          matchers.map { |matcher|
-            regexp, path, to = matcher.values_at(*%w[regexp path to])
-            re = Regexp.new(regexp)
-            proc { |hash|
-              mhash = {}
-              value = interpolate_string(path, hash)
-              if value.is_a?(String) && (m = re.match(value))
-                m.to_a.each_with_index { |s, i|
-                  mhash[i.to_s] = s
-                }
-                m.names.each do |name|
-                  mhash[name] = m[name]
-                end if m.respond_to?(:names)
-              end
-              if to
-                case value = hash[to]
-                when Hash
-                  value.update(mhash)
-                else
-                  hash[to] = mhash
-                end
-              else
-                hash.update(mhash)
-              end
-              hash
-            }
-          }
-        else
-          []
+    def apply_compiled_matchers(matchers, event, &block)
+      return yield if matchers.nil?
+
+      # event.payload.dup does not work; HashWithIndifferentAccess is
+      # a source of trouble here.
+      hash = {}.update(event.payload)
+
+      matchers.each do |re, path, to|
+        m = re.match(interpolate_string(path, hash)) or next
+
+        mhash =
+          if to
+            case value = hash[to]
+            when Hash
+              value
+            else
+              hash[to] = {}
+            end
+          else
+            hash
+          end
+
+        m.size.times do |i|
+          mhash[i.to_s] = m[i]
         end
-    end
 
-    def clear_matchers
-      @matchers = nil
+        m.names.each do |name|
+          mhash[name] = m[name]
+        end
+      end
+
+      interpolate_with(hash, &block)
     end
   end
 end

+ 45 - 2
spec/models/agents/event_formatting_agent_spec.rb

@@ -8,6 +8,7 @@ describe Agents::EventFormattingAgent do
             :instructions => {
                 :message => "Received {{content.text}} from {{content.name}} .",
                 :subject => "Weather looks like {{conditions}} according to the forecast at {{pretty_date.time}}",
+                :timezone => "{{timezone}}",
                 :agent => "{{agent.type}}",
                 :created_at => "{{created_at}}",
                 :created_at_iso => "{{created_at | date:'%FT%T%:z'}}",
@@ -19,6 +20,10 @@ describe Agents::EventFormattingAgent do
                     :regexp => "\\A(?<time>\\d\\d:\\d\\d [AP]M [A-Z]+)",
                     :to => "pretty_date",
                 },
+                {
+                    :path => "{{pretty_date.time}}",
+                    :regexp => "(?<timezone>[A-Z]+)\\z",
+                },
             ],
         }
     }
@@ -40,6 +45,21 @@ describe Agents::EventFormattingAgent do
         },
         :conditions => "someothervalue"
     }
+
+    @event2 = Event.new
+    @event2.agent = agents(:jane_weather_agent)
+    @event2.created_at = Time.now
+    @event2.payload = {
+        :content => {
+            :text => "Some Lorem Ipsum 2",
+            :name => "somevalue2",
+        },
+        :date => {
+            :epoch => "1366372800",
+            :pretty => "08:00 AM EDT on April 19, 2013"
+        },
+        :conditions => "someothervalue2"
+    }
   end
 
   describe "#receive" do
@@ -63,8 +83,31 @@ describe Agents::EventFormattingAgent do
     end
 
     it "should handle matchers and Liquid templating in instructions" do
-      @checker.receive([@event])
-      expect(Event.last.payload[:subject]).to eq("Weather looks like someothervalue according to the forecast at 10:00 PM EST")
+      expect {
+        @checker.receive([@event, @event2])
+      }.to change { Event.count }.by(2)
+
+      formatted_event1, formatted_event2 = Event.last(2)
+
+      expect(formatted_event1.payload[:subject]).to eq("Weather looks like someothervalue according to the forecast at 10:00 PM EST")
+      expect(formatted_event1.payload[:timezone]).to eq("EST")
+      expect(formatted_event2.payload[:subject]).to eq("Weather looks like someothervalue2 according to the forecast at 08:00 AM EDT")
+      expect(formatted_event2.payload[:timezone]).to eq("EDT")
+    end
+
+    it "should not fail if no matchers are defined" do
+      @checker.options.delete(:matchers)
+
+      expect {
+        @checker.receive([@event, @event2])
+      }.to change { Event.count }.by(2)
+
+      formatted_event1, formatted_event2 = Event.last(2)
+
+      expect(formatted_event1.payload[:subject]).to eq("Weather looks like someothervalue according to the forecast at ")
+      expect(formatted_event1.payload[:timezone]).to eq("")
+      expect(formatted_event2.payload[:subject]).to eq("Weather looks like someothervalue2 according to the forecast at ")
+      expect(formatted_event2.payload[:timezone]).to eq("")
     end
 
     it "should allow escaping" do