Skip to content

Commit

Permalink
Merge pull request #382 from cantino/interpolated_options
Browse files Browse the repository at this point in the history
Add memoized interpolated_options and used it everywhere.
  • Loading branch information
cantino committed Jun 19, 2014
2 parents 645d33f + 073df69 commit fb0b423
Show file tree
Hide file tree
Showing 50 changed files with 250 additions and 272 deletions.
3 changes: 0 additions & 3 deletions app/concerns/email_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,4 @@ def present(payload)
def present_hash(hash, skip_key = nil)
hash.to_a.sort_by {|a| a.first.to_s }.map { |k, v| "#{k}: #{v}" unless k.to_s == skip_key.to_s }.compact
end

module ClassMethods
end
end
30 changes: 17 additions & 13 deletions app/concerns/liquid_interpolatable.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
module LiquidInterpolatable
extend ActiveSupport::Concern

def interpolate_options(options, payload)
case options.class.to_s
when 'String'
interpolate_string(options, payload)
when 'ActiveSupport::HashWithIndifferentAccess', 'Hash'
duped_options = options.dup
duped_options.each do |key, value|
duped_options[key] = interpolate_options(value, payload)
end
when 'Array'
options.collect do |value|
interpolate_options(value, payload)
end
def interpolate_options(options, payload = {})
case options
when String
interpolate_string(options, payload)
when ActiveSupport::HashWithIndifferentAccess, Hash
options.inject(ActiveSupport::HashWithIndifferentAccess.new) { |memo, (key, value)| memo[key] = interpolate_options(value, payload); memo }
when Array
options.map { |value| interpolate_options(value, payload) }
else
options
end
end

def interpolated(payload = {})
key = [options, payload]
@interpolated_cache ||= {}
@interpolated_cache[key] ||= interpolate_options(options, payload)
@interpolated_cache[key]
end

def interpolate_string(string, payload)
Liquid::Template.parse(string).render!(payload, registers: {agent: self})
end
Expand Down
1 change: 1 addition & 0 deletions app/models/agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Agent < ActiveRecord::Base
include JSONSerializedField
include RDBMSFunctions
include WorkingHelpers
include LiquidInterpolatable
include HasGuid

markdown_class_attributes :description, :event_description
Expand Down
8 changes: 4 additions & 4 deletions app/models/agents/adioso_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@ def date_to_unix_epoch(date)
end

def check
auth_options = {:basic_auth => {:username =>options[:username], :password=>options['password']}}
parse_response = HTTParty.get "http://api.adioso.com/v2/search/parse?q=#{URI.encode(options['from'])}+to+#{URI.encode(options['to'])}", auth_options
fare_request = parse_response["search_url"].gsub /(end=)(\d*)([^\d]*)(\d*)/, "\\1#{date_to_unix_epoch(options['end_date'])}\\3#{date_to_unix_epoch(options['start_date'])}"
auth_options = {:basic_auth => {:username =>interpolated[:username], :password=>interpolated['password']}}
parse_response = HTTParty.get "http://api.adioso.com/v2/search/parse?q=#{URI.encode(interpolated['from'])}+to+#{URI.encode(interpolated['to'])}", auth_options
fare_request = parse_response["search_url"].gsub /(end=)(\d*)([^\d]*)(\d*)/, "\\1#{date_to_unix_epoch(interpolated['end_date'])}\\3#{date_to_unix_epoch(interpolated['start_date'])}"
fare = HTTParty.get fare_request, auth_options

if fare["warnings"]
create_event :payload => fare["warnings"]
else
event = fare["results"].min {|a,b| a["cost"] <=> b["cost"]}
event["date"] = Time.at(event["date"]).to_date.httpdate[0..15]
event["route"] = "#{options['from']} to #{options['to']}"
event["route"] = "#{interpolated['from']} to #{interpolated['to']}"
create_event :payload => event
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/models/agents/basecamp_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ def check

private
def request_url
"https://basecamp.com/#{URI.encode(options[:user_id].to_s)}/api/v1/projects/#{URI.encode(options[:project_id].to_s)}/events.json"
"https://basecamp.com/#{URI.encode(interpolated[:user_id].to_s)}/api/v1/projects/#{URI.encode(interpolated[:project_id].to_s)}/events.json"
end

def request_options
{:basic_auth => {:username =>options[:username], :password=>options[:password]}, :headers => {"User-Agent" => "Huginn (https://github.com/cantino/huginn)"}}
{:basic_auth => {:username => interpolated[:username], :password => interpolated[:password]}, :headers => {"User-Agent" => "Huginn (https://github.com/cantino/huginn)"}}
end

def query_parameters
Expand Down
15 changes: 7 additions & 8 deletions app/models/agents/data_output_agent.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
module Agents
class DataOutputAgent < Agent
include LiquidInterpolatable

cannot_be_scheduled!

description do
Expand Down Expand Up @@ -52,6 +50,7 @@ def validate_options
unless options['secrets'].is_a?(Array) && options['secrets'].length > 0
errors.add(:base, "Please specify one or more secrets for 'authenticating' incoming feed requests")
end

unless options['expected_receive_period_in_days'].present? && options['expected_receive_period_in_days'].to_i > 0
errors.add(:base, "Please provide 'expected_receive_period_in_days' to indicate how many days can pass before this Agent is considered to be not working")
end
Expand All @@ -62,27 +61,27 @@ def validate_options
end

def events_to_show
(options['events_to_show'].presence || 40).to_i
(interpolated['events_to_show'].presence || 40).to_i
end

def feed_ttl
(options['ttl'].presence || 60).to_i
(interpolated['ttl'].presence || 60).to_i
end

def feed_title
options['template']['title'].presence || "#{name} Event Feed"
interpolated['template']['title'].presence || "#{name} Event Feed"
end

def feed_link
options['template']['link'].presence || "https://#{ENV['DOMAIN']}"
interpolated['template']['link'].presence || "https://#{ENV['DOMAIN']}"
end

def feed_description
options['template']['description'].presence || "A feed of Events received by the '#{name}' Huginn Agent"
interpolated['template']['description'].presence || "A feed of Events received by the '#{name}' Huginn Agent"
end

def receive_web_request(params, method, format)
if options['secrets'].include?(params['secret'])
if interpolated['secrets'].include?(params['secret'])
items = received_events.order('id desc').limit(events_to_show).map do |event|
interpolated = interpolate_options(options['template']['item'], event.payload)
interpolated['guid'] = event.id
Expand Down
2 changes: 1 addition & 1 deletion app/models/agents/email_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def default_options
def receive(incoming_events)
incoming_events.each do |event|
log "Sending digest mail to #{user.email} with event #{event.id}"
SystemMailer.delay.send_message(:to => user.email, :subject => options['subject'], :headline => options['headline'], :groups => [present(event.payload)])
SystemMailer.delay.send_message(:to => user.email, :subject => interpolated(event.payload)['subject'], :headline => interpolated(event.payload)['headline'], :groups => [present(event.payload)])
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/agents/email_digest_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def check
ids = self.memory['events'].join(",")
groups = self.memory['queue'].map { |payload| present(payload) }
log "Sending digest mail to #{user.email} with events [#{ids}]"
SystemMailer.delay.send_message(:to => user.email, :subject => options['subject'], :headline => options['headline'], :groups => groups)
SystemMailer.delay.send_message(:to => user.email, :subject => interpolated['subject'], :headline => interpolated['headline'], :groups => groups)
self.memory['queue'] = []
self.memory['events'] = []
end
Expand Down
12 changes: 6 additions & 6 deletions app/models/agents/event_formatting_agent.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module Agents
class EventFormattingAgent < Agent
include LiquidInterpolatable
cannot_be_scheduled!

description <<-MD
Expand Down Expand Up @@ -81,7 +80,7 @@ class EventFormattingAgent < Agent
after_save :clear_matchers

def validate_options
errors.add(:base, "instructions, mode, skip_agent, and skip_created_at all need to be present.") unless options['instructions'].present? and options['mode'].present? and options['skip_agent'].present? and options['skip_created_at'].present?
errors.add(:base, "instructions, mode, skip_agent, and skip_created_at all need to be present.") unless options['instructions'].present? && options['mode'].present? && options['skip_agent'].present? && options['skip_created_at'].present?

validate_matchers
end
Expand All @@ -105,11 +104,12 @@ def working?

def receive(incoming_events)
incoming_events.each do |event|
formatted_event = options['mode'].to_s == "merge" ? event.payload.dup : {}
payload = perform_matching(event.payload)
formatted_event.merge! interpolate_options(options['instructions'], payload)
formatted_event['agent'] = Agent.find(event.agent_id).type.slice!(8..-1) unless options['skip_agent'].to_s == "true"
formatted_event['created_at'] = event.created_at unless options['skip_created_at'].to_s == "true"
opts = interpolated(payload)
formatted_event = opts['mode'].to_s == "merge" ? event.payload.dup : {}
formatted_event.merge! opts['instructions']
formatted_event['agent'] = Agent.find(event.agent_id).type.slice!(8..-1) unless opts['skip_agent'].to_s == "true"
formatted_event['created_at'] = event.created_at unless opts['skip_created_at'].to_s == "true"
create_event :payload => formatted_event
end
end
Expand Down
8 changes: 4 additions & 4 deletions app/models/agents/ftpsite_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class FtpsiteAgent < Agent
MD

def working?
event_created_within?(options['expected_update_period_in_days']) && !recent_error_logs?
event_created_within?(interpolated['expected_update_period_in_days']) && !recent_error_logs?
end

def default_options
Expand Down Expand Up @@ -90,10 +90,10 @@ def check
end

def each_entry
patterns = options['patterns']
patterns = interpolated['patterns']

after =
if str = options['after']
if str = interpolated['after']
Time.parse(str)
else
Time.at(0)
Expand Down Expand Up @@ -174,7 +174,7 @@ def open_ftp(uri)
end

def base_uri
@base_uri ||= URI(options['url'])
@base_uri ||= URI(interpolated['url'])
end

def saving_entries
Expand Down
12 changes: 6 additions & 6 deletions app/models/agents/growl_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def default_options
end

def working?
last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
last_receive_at && last_receive_at > interpolated['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
end

def validate_options
Expand All @@ -36,13 +36,13 @@ def validate_options
end

def register_growl
@growler = Growl.new options['growl_server'], options['growl_app_name'], "GNTP"
@growler.password = options['growl_password']
@growler.add_notification options['growl_notification_name']
@growler = Growl.new interpolated['growl_server'], interpolated['growl_app_name'], "GNTP"
@growler.password = interpolated['growl_password']
@growler.add_notification interpolated['growl_notification_name']
end

def notify_growl(subject, message)
@growler.notify(options['growl_notification_name'],subject,message)
@growler.notify(interpolated['growl_notification_name'], subject, message)
end

def receive(incoming_events)
Expand All @@ -51,7 +51,7 @@ def receive(incoming_events)
message = (event.payload['message'] || event.payload['text']).to_s
subject = event.payload['subject'].to_s
if message.present? && subject.present?
log "Sending Growl notification '#{subject}': '#{message}' to #{options['growl_server']} with event #{event.id}"
log "Sending Growl notification '#{subject}': '#{message}' to #{interpolated(event.payload)['growl_server']} with event #{event.id}"
notify_growl(subject,message)
else
log "Event #{event.id} not sent, message and subject expected"
Expand Down
6 changes: 2 additions & 4 deletions app/models/agents/hipchat_agent.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
module Agents
class HipchatAgent < Agent
include LiquidInterpolatable

cannot_be_scheduled!
cannot_create_events!

Expand Down Expand Up @@ -42,9 +40,9 @@ def working?
end

def receive(incoming_events)
client = HipChat::Client.new(options[:auth_token])
client = HipChat::Client.new(interpolated[:auth_token])
incoming_events.each do |event|
mo = interpolate_options options, event.payload
mo = interpolated(event.payload)
client[mo[:room_name]].send(mo[:username], mo[:message], :notify => mo[:notify].to_s == 'true' ? 1 : 0, :color => mo[:color])
end
end
Expand Down
14 changes: 6 additions & 8 deletions app/models/agents/human_task_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

module Agents
class HumanTaskAgent < Agent
include LiquidInterpolatable

default_schedule "every_10m"

description <<-MD
Expand Down Expand Up @@ -204,20 +202,20 @@ def default_options
end

def working?
last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
last_receive_at && last_receive_at > interpolated['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
end

def check
review_hits

if options['trigger_on'] == "schedule" && (memory['last_schedule'] || 0) <= Time.now.to_i - options['submission_period'].to_i * 60 * 60
if interpolated['trigger_on'] == "schedule" && (memory['last_schedule'] || 0) <= Time.now.to_i - interpolated['submission_period'].to_i * 60 * 60
memory['last_schedule'] = Time.now.to_i
create_basic_hit
end
end

def receive(incoming_events)
if options['trigger_on'] == "event"
if interpolated['trigger_on'] == "event"
incoming_events.each do |event|
create_basic_hit event
end
Expand All @@ -227,11 +225,11 @@ def receive(incoming_events)
protected

def take_majority?
options['combination_mode'] == "take_majority" || options['take_majority'] == "true"
interpolated['combination_mode'] == "take_majority" || interpolated['take_majority'] == "true"
end

def create_poll?
options['combination_mode'] == "poll"
interpolated['combination_mode'] == "poll"
end

def event_for_hit(hit_id)
Expand Down Expand Up @@ -367,7 +365,7 @@ def review_hits
end

def all_questions_are_numeric?
options['hit']['questions'].all? do |question|
interpolated['hit']['questions'].all? do |question|
question['selections'].all? do |selection|
selection['key'] == selection['key'].to_f.to_s || selection['key'] == selection['key'].to_i.to_s
end
Expand Down
14 changes: 7 additions & 7 deletions app/models/agents/imap_folder_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class ImapFolderAgent < Agent
}

def working?
event_created_within?(options['expected_update_period_in_days']) && !recent_error_logs?
event_created_within?(interpolated['expected_update_period_in_days']) && !recent_error_logs?
end

def default_options
Expand Down Expand Up @@ -240,7 +240,7 @@ def check
matched_part = nil
matches = {}

options['conditions'].all? { |key, value|
interpolated['conditions'].all? { |key, value|
case key
when 'subject'
value.present? or next true
Expand Down Expand Up @@ -308,7 +308,7 @@ def check
notified << mail.message_id if mail.message_id
end

if options['mark_as_read']
if interpolated['mark_as_read']
log 'Marking as read'
mail.mark_as_read
end
Expand All @@ -322,14 +322,14 @@ def check
end

def each_unread_mail
host, port, ssl, username = options.values_at(:host, :port, :ssl, :username)
host, port, ssl, username = interpolated.values_at(:host, :port, :ssl, :username)

log "Connecting to #{host}#{':%d' % port if port}#{' via SSL' if ssl}"
Client.open(host, Integer(port), ssl) { |imap|
log "Logging in as #{username}"
imap.login(username, options[:password])
imap.login(username, interpolated[:password])

options['folders'].each { |folder|
interpolated['folders'].each { |folder|
log "Selecting the folder: %s" % folder

imap.select(folder)
Expand All @@ -351,7 +351,7 @@ def each_unread_mail
end

def mime_types
options['mime_types'] || %w[text/plain text/enriched text/html]
interpolated['mime_types'] || %w[text/plain text/enriched text/html]
end

private
Expand Down
Loading

0 comments on commit fb0b423

Please sign in to comment.