conduit 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Rakefile +22 -0
- data/app/controllers/conduit/responses_controller.rb +14 -0
- data/app/models/conduit/concerns/storage.rb +41 -0
- data/app/models/conduit/request.rb +109 -0
- data/app/models/conduit/response.rb +50 -0
- data/app/models/conduit/subscription.rb +6 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20131209223122_create_conduit_requests.rb +13 -0
- data/db/migrate/20131209223734_create_conduit_responses.rb +10 -0
- data/db/migrate/20140305202729_create_conduit_subscriptions.rb +12 -0
- data/lib/conduit.rb +60 -0
- data/lib/conduit/acts_as_conduit_subscriber.rb +41 -0
- data/lib/conduit/configuration.rb +43 -0
- data/lib/conduit/core/action.rb +136 -0
- data/lib/conduit/core/connection.rb +85 -0
- data/lib/conduit/core/driver.rb +83 -0
- data/lib/conduit/core/parser.rb +55 -0
- data/lib/conduit/core/render.rb +69 -0
- data/lib/conduit/drivers/keep +0 -0
- data/lib/conduit/engine.rb +20 -0
- data/lib/conduit/storage.rb +37 -0
- data/lib/conduit/storage/aws.rb +94 -0
- data/lib/conduit/storage/file.rb +74 -0
- data/lib/conduit/util.rb +17 -0
- data/lib/conduit/version.rb +3 -0
- data/lib/tasks/conduit_tasks.rake +4 -0
- data/spec/classes/acts_as_conduit_subscriber_spec.rb +61 -0
- data/spec/classes/core/action_spec.rb +53 -0
- data/spec/classes/core/driver_spec.rb +24 -0
- data/spec/controllers/responses_controller_spec.rb +29 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +29 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +20 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/conduit.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/schema.rb +46 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/actions/foo.rb +10 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/driver.rb +7 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/parsers/foo.rb +13 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/views/foo.erb +5 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/views/layout.erb +3 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +9707 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/tmp/conduit/1/my_driver/foo/1-response.xml +3 -0
- data/spec/dummy/tmp/conduit/1/my_driver/foo/request.xml +7 -0
- data/spec/models/conduit/request_spec.rb +50 -0
- data/spec/models/conduit/response_spec.rb +52 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/support/helper.rb +15 -0
- data/spec/support/xml/xml_request.xml +7 -0
- data/spec/support/xml/xml_response.xml +3 -0
- metadata +311 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 38426d4ed06704aedc33d972b93160383581e319
|
4
|
+
data.tar.gz: b89d9ef6cc7c13c1ee9fcf492b4c1e2520ddaeab
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2c8516d726d6e17db237a920e31353e592d6542553d9277eae4f74cf79618dbaac09dd79c98fef70400f924d3b1e51c5ab110f8a23e1441a79a953d30343f4f0
|
7
|
+
data.tar.gz: 5d24fe0a44c971cce8571e5ce217e0f6438c118645a8d7408a4aa43298805703eca0607984531f2fcf6515f9fa4ac090ee7114d9296582687eb9550f26f20fb7
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Foo'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Conduit
|
2
|
+
class ResponsesController < ActionController::Base
|
3
|
+
|
4
|
+
# TODO: Determine the actual param the posted content
|
5
|
+
# will be stored in, and modify the code below
|
6
|
+
#
|
7
|
+
def create
|
8
|
+
request = Conduit::Request.find(params[:request_id])
|
9
|
+
request.responses.create(content: params[:content])
|
10
|
+
render nothing: true
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Conduit
|
2
|
+
module Concerns
|
3
|
+
module Storage
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_writer :content
|
8
|
+
|
9
|
+
after_create :add_to_storage, if: :generate_storage_path
|
10
|
+
after_destroy :remove_from_storage, if: :file
|
11
|
+
end
|
12
|
+
|
13
|
+
# Read the content from the storage location
|
14
|
+
#
|
15
|
+
def content
|
16
|
+
@content ||= Conduit::Storage.read(file)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Generate a unique storage key
|
22
|
+
#
|
23
|
+
def generate_storage_path
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
# Remove the file from remote storage
|
28
|
+
#
|
29
|
+
def remove_from_storage
|
30
|
+
Conduit::Storage.delete(file)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Write the content to the storage location
|
34
|
+
#
|
35
|
+
def add_to_storage
|
36
|
+
Conduit::Storage.write(file, content)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Conduit
|
2
|
+
class Request < ActiveRecord::Base
|
3
|
+
include Conduit::Concerns::Storage
|
4
|
+
|
5
|
+
serialize :options, Hash
|
6
|
+
|
7
|
+
# Associations
|
8
|
+
|
9
|
+
has_many :responses, dependent: :destroy
|
10
|
+
has_many :subscriptions, autosave: true
|
11
|
+
|
12
|
+
# Validations
|
13
|
+
|
14
|
+
validates :driver, presence: true
|
15
|
+
validates :action, presence: true
|
16
|
+
|
17
|
+
# Hooks
|
18
|
+
|
19
|
+
after_initialize :set_defaults
|
20
|
+
after_update :notify_subscribers
|
21
|
+
|
22
|
+
# Scopes
|
23
|
+
|
24
|
+
scope :by_action, -> (actions) { where(action: actions) }
|
25
|
+
scope :by_driver, -> (drivers) { where(driver: drivers) }
|
26
|
+
scope :by_status, -> (status) { where(status: status) }
|
27
|
+
|
28
|
+
# Methods
|
29
|
+
|
30
|
+
# Overriding this method fixes an issue
|
31
|
+
# where content isn't set until after
|
32
|
+
# the raw action is instantiated
|
33
|
+
#
|
34
|
+
def content
|
35
|
+
raw.view || super
|
36
|
+
end
|
37
|
+
|
38
|
+
# Perform the requested action
|
39
|
+
# for the specified driver
|
40
|
+
#
|
41
|
+
def perform_request
|
42
|
+
if response = raw.perform
|
43
|
+
responses.create(content: response.body)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Allow creation of subscriptions through the
|
48
|
+
# subscribers virtual attribute.
|
49
|
+
#
|
50
|
+
# NOTE: This is usually possible by default with a
|
51
|
+
# has_many :through, but with polymorphic
|
52
|
+
# association it gets more complicated.
|
53
|
+
#
|
54
|
+
def subscribers=(args)
|
55
|
+
args.map do |arg|
|
56
|
+
next unless arg.class < ActiveRecord::Base
|
57
|
+
subscriptions.build(subscriber: arg)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Fetch a list of subscribers through
|
62
|
+
# the subscriptions association
|
63
|
+
#
|
64
|
+
# NOTE: This is usually possible by default with a
|
65
|
+
# has_many :through, but with polymorphic
|
66
|
+
# association it gets more complicated.
|
67
|
+
#
|
68
|
+
def subscribers
|
69
|
+
subscriptions.map(&:subscriber)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Set some default values
|
75
|
+
#
|
76
|
+
def set_defaults
|
77
|
+
self.status ||= "open"
|
78
|
+
end
|
79
|
+
|
80
|
+
# Generate a unique storage key
|
81
|
+
# TODO: Dynamic File Format
|
82
|
+
#
|
83
|
+
def generate_storage_path
|
84
|
+
update_column(:file, File.join("#{id}".reverse!,
|
85
|
+
driver.to_s, action.to_s, "request.xml"))
|
86
|
+
end
|
87
|
+
|
88
|
+
# Notify the requestable that our status
|
89
|
+
# has changed. This is done by calling
|
90
|
+
# a predefined method name on the
|
91
|
+
# requestable instance
|
92
|
+
#
|
93
|
+
def notify_subscribers
|
94
|
+
last_response = responses.last
|
95
|
+
subscribers.each do |subscriber|
|
96
|
+
subscriber.after_conduit_update(action,
|
97
|
+
last_response.parsed_content)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Raw access to the action instance
|
102
|
+
#
|
103
|
+
def raw
|
104
|
+
@raw ||= Conduit::Util.find_driver(driver,
|
105
|
+
action).new(options.symbolize_keys!)
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Conduit
|
2
|
+
class Response < ActiveRecord::Base
|
3
|
+
include Conduit::Concerns::Storage
|
4
|
+
|
5
|
+
# Associations
|
6
|
+
|
7
|
+
belongs_to :request
|
8
|
+
|
9
|
+
# Validations
|
10
|
+
|
11
|
+
validates :request, presence: true
|
12
|
+
|
13
|
+
# Hooks
|
14
|
+
|
15
|
+
after_create :report_response_status
|
16
|
+
|
17
|
+
# Methods
|
18
|
+
|
19
|
+
delegate :driver, :action, to: :request
|
20
|
+
|
21
|
+
# Raw access to the parser instance
|
22
|
+
#
|
23
|
+
def parsed_content
|
24
|
+
@parsed_content ||= Conduit::Util.find_driver(driver, action, 'parser').new(content)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Generate a storage key based on parent request
|
30
|
+
# TODO: Dynamic File Format
|
31
|
+
#
|
32
|
+
def generate_storage_path
|
33
|
+
update_column(:file, File.join(File.dirname(
|
34
|
+
request.file), "#{id}-response.xml"))
|
35
|
+
end
|
36
|
+
|
37
|
+
# Check for the 'response_status' attribute
|
38
|
+
# from the parsed data, and return that to
|
39
|
+
# the request.
|
40
|
+
#
|
41
|
+
# NOTE: These should be one of the following:
|
42
|
+
# pending/success/failure
|
43
|
+
#
|
44
|
+
def report_response_status
|
45
|
+
status = parsed_content.response_status
|
46
|
+
request.update_attributes(status: status)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateConduitSubscriptions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :conduit_subscriptions do |t|
|
4
|
+
t.references :request, index: true
|
5
|
+
t.integer :subscriber_id
|
6
|
+
t.string :subscriber_type
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
add_index :conduit_subscriptions, [:subscriber_type, :subscriber_id]
|
11
|
+
end
|
12
|
+
end
|
data/lib/conduit.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'conduit/engine'
|
2
|
+
require 'conduit/acts_as_conduit_subscriber'
|
3
|
+
|
4
|
+
module Conduit
|
5
|
+
|
6
|
+
mattr_accessor :app_root
|
7
|
+
|
8
|
+
# Autoload the Conduit base classes
|
9
|
+
# NOTE: Autoloading should be
|
10
|
+
# concurrency-safe
|
11
|
+
#
|
12
|
+
autoload :Configuration, 'conduit/configuration'
|
13
|
+
autoload :Storage, 'conduit/storage'
|
14
|
+
autoload :Util, 'conduit/util'
|
15
|
+
|
16
|
+
module Core
|
17
|
+
|
18
|
+
# Autoload the Conduit::Core base classes
|
19
|
+
# NOTE: Autoloading should be
|
20
|
+
# concurrency-safe
|
21
|
+
#
|
22
|
+
autoload :Connection, 'conduit/core/connection'
|
23
|
+
autoload :Render, 'conduit/core/render'
|
24
|
+
autoload :Action, 'conduit/core/action'
|
25
|
+
autoload :Parser, 'conduit/core/parser'
|
26
|
+
autoload :Driver, 'conduit/core/driver'
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
module Driver
|
31
|
+
|
32
|
+
class << self
|
33
|
+
# Store a list of available drivers
|
34
|
+
#
|
35
|
+
# e.g.
|
36
|
+
# Conduit::Driver.index
|
37
|
+
# => [:foo, :bar, :baz]
|
38
|
+
#
|
39
|
+
def index
|
40
|
+
@index ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
# Load the drivers automatically, but only when they're needed
|
44
|
+
#
|
45
|
+
def load_drivers
|
46
|
+
Conduit::Configuration.driver_paths.each do |dir|
|
47
|
+
raise "Directory not found: #{dir}" unless File.exists?(dir)
|
48
|
+
Dir["#{dir}/**/driver.rb"].each do |file|
|
49
|
+
raise "File not found: #{file}" unless File.exists?(file)
|
50
|
+
name = File.dirname(file).split(File::SEPARATOR).last.classify.to_sym
|
51
|
+
index << name.downcase
|
52
|
+
autoload name, file
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Conduit
|
2
|
+
module ActsAsConduitSubscriber
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
# Define a method that can be used to inject
|
8
|
+
# methods into an ActiveRecord Model
|
9
|
+
#
|
10
|
+
def acts_as_conduit_subscriber
|
11
|
+
include Conduit::ActsAsConduitSubscriber::LocalInstanceMethods
|
12
|
+
|
13
|
+
has_many :conduit_subscriptions, as: :subscriber, class_name: 'Conduit::Subscription'
|
14
|
+
has_many :conduit_requests, through: :conduit_subscriptions, source: :request
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
# These methods are included when acts_as_conduit_request
|
20
|
+
# is called on an ActiveRecord Model
|
21
|
+
#
|
22
|
+
module LocalInstanceMethods
|
23
|
+
|
24
|
+
# Fire this method after the last conduit
|
25
|
+
# request has been updated
|
26
|
+
#
|
27
|
+
# NOTE: This could probably be better
|
28
|
+
# handled by observers, or a
|
29
|
+
# custom callback.
|
30
|
+
#
|
31
|
+
def after_conduit_update(action, parsed_response)
|
32
|
+
# This method should be overriden
|
33
|
+
# on the requestable object
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
ActiveRecord::Base.send :include, Conduit::ActsAsConduitSubscriber
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# The job of this class is to provide common
|
3
|
+
# configuration options to conduit
|
4
|
+
#
|
5
|
+
|
6
|
+
module Conduit
|
7
|
+
module Configuration
|
8
|
+
class << self
|
9
|
+
|
10
|
+
#
|
11
|
+
# Storage
|
12
|
+
#
|
13
|
+
# Define the storage configuration. This could
|
14
|
+
# include anything from file paths, to
|
15
|
+
# service credentials, and provider
|
16
|
+
#
|
17
|
+
mattr_accessor :storage_config
|
18
|
+
self.storage_config = {
|
19
|
+
provider: :file,
|
20
|
+
file_path: Conduit.app_root.join('tmp', 'conduit')
|
21
|
+
}
|
22
|
+
|
23
|
+
#
|
24
|
+
# Drivers
|
25
|
+
#
|
26
|
+
# Define the driver load path
|
27
|
+
# Define an array of drivers to load
|
28
|
+
#
|
29
|
+
mattr_accessor :driver_paths
|
30
|
+
self.driver_paths = ["#{File.dirname(__FILE__)}/drivers"]
|
31
|
+
|
32
|
+
#
|
33
|
+
# Methods
|
34
|
+
#
|
35
|
+
# Read in the configuration
|
36
|
+
#
|
37
|
+
def configure(&block)
|
38
|
+
yield self
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|