Allow escaping of JSONPath outputs; demonstrate in the formatting agent.

This commit is contained in:
Andrew Cantino 2013-08-08 09:56:22 -07:00
parent a00af51d68
commit 306237c306
4 changed files with 146 additions and 112 deletions

View file

@ -24,7 +24,7 @@ module Agents
subject: "$.data"
}
JSONPaths must be between < and > . Make sure that you dont use these symbols anywhere else.
JSONPaths must be between < and > . Make sure that you don't use these symbols anywhere else.
Events generated by this possible Event Formatting Agent will look like:
@ -35,7 +35,13 @@ module Agents
If you want to retain original contents of events and only add new keys, then set `mode` to `merge`, otherwise set it to `clean`.
By default, the output event will have `agent` and `created_at` fields as well, reflecting the original Agent type and Event creation time. You can skip these outputs by setting `skip_agent` and `skip_created_at` to `true`.
By default, the output event will have `agent` and `created_at` fields added as well, reflecting the original Agent type and Event creation time. You can skip these outputs by setting `skip_agent` and `skip_created_at` to `true`.
To CGI escape output (for example when creating a link), prefix with `escape`, like so:
{
:message => "A peak was on Twitter in <$.group_by>. Search: https://twitter.com/search?q=<escape $.group_by>"
}
MD
event_description <<-MD
@ -62,7 +68,9 @@ module Agents
end
def value_constructor(value, payload)
value.gsub(/<[^>]+>/).each {|jsonpath| Utils.values_at(payload,jsonpath[1..-2]).first.to_s }
value.gsub(/<[^>]+>/).each { |jsonpath|
Utils.values_at(payload, jsonpath[1..-2]).first.to_s
}
end
def receive(incoming_events)

View file

@ -1,4 +1,5 @@
require 'jsonpath'
require 'cgi'
module Utils
# Unindents if the indentation is 2 or more characters.
@ -22,6 +23,18 @@ module Utils
end
def self.values_at(data, path)
JsonPath.new(path, :allow_eval => false).on(data.is_a?(String) ? data : data.to_json)
if path =~ /\Aescape /
path.gsub!(/\Aescape /, '')
escape = true
else
escape = false
end
result = JsonPath.new(path, :allow_eval => false).on(data.is_a?(String) ? data : data.to_json)
if escape
result.map {|r| CGI::escape r }
else
result
end
end
end

View file

@ -24,5 +24,9 @@ describe Utils do
Utils.values_at({ :foo => [ { :bar => :baz }, { :bar => :bing } ]}, "foo[*].bar").should == %w[baz bing]
Utils.values_at({ :foo => [ { :bar => :baz }, { :bar => :bing } ]}, "foo[*].bar").should == %w[baz bing]
end
it "should allow escaping" do
Utils.values_at({ :foo => { :bar => "escape this!?" }}, "escape $.foo.bar").should == ["escape+this%21%3F"]
end
end
end

View file

@ -1,119 +1,128 @@
require 'spec_helper'
describe Agents::EventFormattingAgent do
before do
@valid_params = {
:name => "somename",
:options => {
:instructions => {
:message => "Received <$.content.text.*> from <$.content.name> .",
:subject => "Weather looks like <$.conditions>"
},
:mode => "clean",
:skip_agent => "false",
:skip_created_at => "false"
}
}
@checker = Agents::EventFormattingAgent.new(@valid_params)
@checker.user = users(:jane)
@checker.save!
@event = Event.new
@event.agent = agents(:jane_weather_agent)
@event.created_at = Time.now
@event.payload = {
:content => {
:text => "Some Lorem Ipsum",
:name => "somevalue"
before do
@valid_params = {
:name => "somename",
:options => {
:instructions => {
:message => "Received <$.content.text.*> from <$.content.name> .",
:subject => "Weather looks like <$.conditions>"
},
:conditions => "someothervalue"
:mode => "clean",
:skip_agent => "false",
:skip_created_at => "false"
}
}
@checker = Agents::EventFormattingAgent.new(@valid_params)
@checker.user = users(:jane)
@checker.save!
@event = Event.new
@event.agent = agents(:jane_weather_agent)
@event.created_at = Time.now
@event.payload = {
:content => {
:text => "Some Lorem Ipsum",
:name => "somevalue"
},
:conditions => "someothervalue"
}
end
describe "#receive" do
it "should accept clean mode" do
@checker.receive([@event])
Event.last.payload[:content].should == nil
end
describe "#receive" do
it "checks if clean mode is working fine" do
@checker.receive([@event])
Event.last.payload[:content].should == nil
end
it "checks if merge mode is working fine" do
@checker.options[:mode] = "merge"
@checker.receive([@event])
Event.last.payload[:content].should_not == nil
end
it "checks if skip_agent is working fine" do
@checker.receive([@event])
Event.last.payload[:agent].should == "WeatherAgent"
@checker.options[:skip_agent] = "true"
@checker.receive([@event])
Event.last.payload[:agent].should == nil
end
it "checks if skip_created_at is working fine" do
@checker.receive([@event])
Event.last.payload[:created_at].should_not == nil
@checker.options[:skip_created_at] = "true"
@checker.receive([@event])
Event.last.payload[:created_at].should == nil
end
it "checks if instructions are working fine" do
@checker.receive([@event])
Event.last.payload[:message].should == "Received Some Lorem Ipsum from somevalue ."
Event.last.payload[:subject].should == "Weather looks like someothervalue"
end
it "checks if it can handle multiple events" do
event1 = Event.new
event1.agent = agents(:bob_weather_agent)
event1.payload = {
:content => {
:text => "Some Lorem Ipsum",
:name => "somevalue"
},
:conditions => "someothervalue"
}
event2 = Event.new
event2.agent = agents(:bob_weather_agent)
event2.payload = {
:content => {
:text => "Some Lorem Ipsum",
:name => "somevalue"
},
:conditions => "someothervalue"
}
lambda {
@checker.receive([event2,event1])
}.should change { Event.count }.by(2)
end
it "should accept merge mode" do
@checker.options[:mode] = "merge"
@checker.receive([@event])
Event.last.payload[:content].should_not == nil
end
describe "validation" do
before do
@checker.should be_valid
end
it "should validate presence of instructions" do
@checker.options[:instructions] = ""
@checker.should_not be_valid
end
it "should validate presence of mode" do
@checker.options[:mode] = ""
@checker.should_not be_valid
end
it "should validate presence of skip_agent" do
@checker.options[:skip_agent] = ""
@checker.should_not be_valid
end
it "should validate presence of skip_created_at" do
@checker.options[:skip_created_at] = ""
@checker.should_not be_valid
end
it "should accept skip_agent" do
@checker.receive([@event])
Event.last.payload[:agent].should == "WeatherAgent"
@checker.options[:skip_agent] = "true"
@checker.receive([@event])
Event.last.payload[:agent].should == nil
end
it "should accept skip_created_at" do
@checker.receive([@event])
Event.last.payload[:created_at].should_not == nil
@checker.options[:skip_created_at] = "true"
@checker.receive([@event])
Event.last.payload[:created_at].should == nil
end
it "should handle JSONPaths in instructions" do
@checker.receive([@event])
Event.last.payload[:message].should == "Received Some Lorem Ipsum from somevalue ."
Event.last.payload[:subject].should == "Weather looks like someothervalue"
end
it "should allow escaping" do
@event.payload[:content][:name] = "escape this!?"
@event.save!
@checker.options[:instructions][:message] = "Escaped: <escape $.content.name>\nNot escaped: <$.content.name>"
@checker.save!
@checker.receive([@event])
Event.last.payload[:message].should == "Escaped: escape+this%21%3F\nNot escaped: escape this!?"
end
it "should handle multiple events" do
event1 = Event.new
event1.agent = agents(:bob_weather_agent)
event1.payload = {
:content => {
:text => "Some Lorem Ipsum",
:name => "somevalue"
},
:conditions => "someothervalue"
}
event2 = Event.new
event2.agent = agents(:bob_weather_agent)
event2.payload = {
:content => {
:text => "Some Lorem Ipsum",
:name => "somevalue"
},
:conditions => "someothervalue"
}
lambda {
@checker.receive([event2, event1])
}.should change { Event.count }.by(2)
end
end
describe "validation" do
before do
@checker.should be_valid
end
it "should validate presence of instructions" do
@checker.options[:instructions] = ""
@checker.should_not be_valid
end
it "should validate presence of mode" do
@checker.options[:mode] = ""
@checker.should_not be_valid
end
it "should validate presence of skip_agent" do
@checker.options[:skip_agent] = ""
@checker.should_not be_valid
end
it "should validate presence of skip_created_at" do
@checker.options[:skip_created_at] = ""
@checker.should_not be_valid
end
end
end