Skip to content

Instantly share code, notes, and snippets.

@KenYN
Last active January 3, 2016 22:59
Show Gist options
  • Save KenYN/8532462 to your computer and use it in GitHub Desktop.
Save KenYN/8532462 to your computer and use it in GitHub Desktop.
This is a rough outline of how a Scenario for https://github.com/cantino/huginn might be implemented. Note that the Schedule class is left as an exercise to the reader.
class Scenario < ActiveRecord::Base
has_many :agents, :dependent => :destroy, :inverse_of => :scenario
belongs_to :schedule, :inverse_of => :scenarios
belongs_to :user
attr_accessible :description, :name, :scenario
# XML description of scenario - not in DB!
attr_accessor :scenario
# Create a set of rules from the passed in parameters.
# @param current_user the current user
# @param params POST parameters - note that params[:scenario] defines the current scenario
def self.create(current_user, params)
new_scenario = Scenario.new(params[:scenario])
new_scenario.schedule_id = params[:schedule_id]
new_scenario.create_scenario(current_user)
end
# Create a set of rules for the current user and the stored :scenario.
# @param current_user the current user
def create_scenario(current_user)
# Load up the XML description
scenario_file = Nokogiri::XML(scenario)
# Create all agents for each <agent>
agent_list = Hash.new()
scenario_file.xpath('/scenario/agent').each do |agent_node|
new_agent = create_agent(current_user, agent_node)
new_agent.scenario = self
# Add in the default options, unless they overwrite explicitly-set options
new_agent.options.reverse_merge!(new_agent.default_options)
# Final initialization chance
new_agent.after_xml_creation
agent_list[agent_node.attr('id')] = new_agent
end
ActiveRecord::Base.transaction do
# Save agents - must do this here to generate agent_ids for links
agent_list.each_value &:save!
# Create all links for each <link>
link_list = Hash.new()
scenario_file.xpath('/scenario/link').each do |link_node|
link_list[link_node.attr('id')] = create_link(agent_list, link_node)
end
# Save links
link_list.each_value &:save!
# Finally save myself
self.user = current_user
save!
return self
end
end
# Create an agent
# @param current_user the current user
# @param agent_node XML node describing the agent to create
# @return new Agent object
def create_agent(current_user, agent_node)
# Create the Agent
new_agent = agent_node.attr("agent").to_s.constantize.new
# Add a name
new_agent.name = agent_node.attr("name").to_s
# Add a schedule, if present
schedule = agent_node.attr("schedule")
new_agent.schedule = schedule.to_s if schedule.present?
# Set the owner
new_agent.user = current_user
# Add the arguments
Array(agent_node.xpath("./agent_setting")).each {|tag| new_agent.options[tag.attr("option")] = tag.attr("value") unless tag.attr("option").nil? }
# And return the new agent
return new_agent
end
# Create a link
# @param current_agents the agents created earlier
# @param link_node XML node describing the link to create
# @return new Link object
def create_link(current_agents, link_node)
# Create the link
new_link = Link.new(:source_id => current_agents[link_node.attr("source")].id,
:receiver_id => current_agents[link_node.attr("sink")].id)
# And return the new link
return new_link
end
end
# encoding: UTF-8
class ScenariosController < ApplicationController
def new
@scenario = Scenario.new()
@scenario.name = "My first scenario"
@scenario.description = "My first scenario description"
@scenario.scenario = <<SAMPLE_XML
<scenario name="#{@scenario.name}" description="#{@scenario.description}">
<agent id="one" name="Weather trigger agent" agent="Agents::WeatherAgent">
<agent_setting option="api_key" value="abcd"/>
<agent_setting option="location" value="94103"/>
</agent>
<agent id="two" name="Adioso trigger agent" agent="Agents::AdiosoAgent">
<agent_setting option="from" value="New York"/>
<agent_setting option="to" value="Chicago"/>
</agent>
<agent id="three" name="Sendmail agent" agent="Agents::SendEmailAgent">
<agent_setting option="to" value="foo@example.com"/>
<agent_setting option="subject" value="Nice weather for a trip"/>
</agent>
<agent id="four" name="Twitter action" agent="Agents::TwitterPublishAgent">
<agent_setting option="message_path" value="Off to #Chicago"/>
<agent_setting option="username" value="me"/>
</agent>
<link id="one" source="one" sink="four"/>
<link id="two" source="two" sink="three"/>
<link id="three" source="one" sink="three"/>
</scenario>
SAMPLE_XML
@schedule = current_user.schedules.find(params[:schedule_id])
end
# Create a new scenario
def create
# Create the scenario
# Note: current_user comes from Devise, and is only available in Controllers and Views,
# not models, so that's why we have to pass it in here
new_scenario = Scenario.create(current_user, params)
# And bung us back up to the top page
respond_to do |format|
format.html do
redirect_to schedule_scenarios_path(params[:schedule_id])
end
format.js do
render json: new_scenario
end
end
end
# Destroy a scenario
def destroy
@scenario = current_user.scenarios.find(params[:id])
@scenario.destroy
respond_to do |format|
format.html { redirect_to schedule_scenarios_path(params[:schedule_id]) }
format.json { head :no_content }
end
end
# View a list of scenarios
def index
@schedule_id = params[:schedule_id]
if @schedule_id.present? && @schedule_id != -1
@schedule = current_user.schedules.find(@schedule_id)
@scenarios = @schedule.scenarios.page(params[:page])
else
@scenarios = current_user.scenarios.page(params[:page])
end
respond_to do |format|
format.html
format.json { render json: @scenarios }
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment