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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +22 -0
  3. data/app/controllers/conduit/responses_controller.rb +14 -0
  4. data/app/models/conduit/concerns/storage.rb +41 -0
  5. data/app/models/conduit/request.rb +109 -0
  6. data/app/models/conduit/response.rb +50 -0
  7. data/app/models/conduit/subscription.rb +6 -0
  8. data/config/routes.rb +3 -0
  9. data/db/migrate/20131209223122_create_conduit_requests.rb +13 -0
  10. data/db/migrate/20131209223734_create_conduit_responses.rb +10 -0
  11. data/db/migrate/20140305202729_create_conduit_subscriptions.rb +12 -0
  12. data/lib/conduit.rb +60 -0
  13. data/lib/conduit/acts_as_conduit_subscriber.rb +41 -0
  14. data/lib/conduit/configuration.rb +43 -0
  15. data/lib/conduit/core/action.rb +136 -0
  16. data/lib/conduit/core/connection.rb +85 -0
  17. data/lib/conduit/core/driver.rb +83 -0
  18. data/lib/conduit/core/parser.rb +55 -0
  19. data/lib/conduit/core/render.rb +69 -0
  20. data/lib/conduit/drivers/keep +0 -0
  21. data/lib/conduit/engine.rb +20 -0
  22. data/lib/conduit/storage.rb +37 -0
  23. data/lib/conduit/storage/aws.rb +94 -0
  24. data/lib/conduit/storage/file.rb +74 -0
  25. data/lib/conduit/util.rb +17 -0
  26. data/lib/conduit/version.rb +3 -0
  27. data/lib/tasks/conduit_tasks.rake +4 -0
  28. data/spec/classes/acts_as_conduit_subscriber_spec.rb +61 -0
  29. data/spec/classes/core/action_spec.rb +53 -0
  30. data/spec/classes/core/driver_spec.rb +24 -0
  31. data/spec/controllers/responses_controller_spec.rb +29 -0
  32. data/spec/dummy/README.rdoc +28 -0
  33. data/spec/dummy/Rakefile +6 -0
  34. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  35. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  36. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  37. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  38. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  39. data/spec/dummy/bin/bundle +3 -0
  40. data/spec/dummy/bin/rails +4 -0
  41. data/spec/dummy/bin/rake +4 -0
  42. data/spec/dummy/config.ru +4 -0
  43. data/spec/dummy/config/application.rb +29 -0
  44. data/spec/dummy/config/boot.rb +5 -0
  45. data/spec/dummy/config/database.yml +20 -0
  46. data/spec/dummy/config/environment.rb +5 -0
  47. data/spec/dummy/config/environments/development.rb +29 -0
  48. data/spec/dummy/config/environments/production.rb +80 -0
  49. data/spec/dummy/config/environments/test.rb +36 -0
  50. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  51. data/spec/dummy/config/initializers/conduit.rb +5 -0
  52. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  53. data/spec/dummy/config/initializers/inflections.rb +16 -0
  54. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  55. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  56. data/spec/dummy/config/initializers/session_store.rb +3 -0
  57. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/spec/dummy/config/locales/en.yml +23 -0
  59. data/spec/dummy/config/routes.rb +3 -0
  60. data/spec/dummy/db/schema.rb +46 -0
  61. data/spec/dummy/lib/conduit/drivers/my_driver/actions/foo.rb +10 -0
  62. data/spec/dummy/lib/conduit/drivers/my_driver/driver.rb +7 -0
  63. data/spec/dummy/lib/conduit/drivers/my_driver/parsers/foo.rb +13 -0
  64. data/spec/dummy/lib/conduit/drivers/my_driver/views/foo.erb +5 -0
  65. data/spec/dummy/lib/conduit/drivers/my_driver/views/layout.erb +3 -0
  66. data/spec/dummy/log/development.log +0 -0
  67. data/spec/dummy/log/test.log +9707 -0
  68. data/spec/dummy/public/404.html +58 -0
  69. data/spec/dummy/public/422.html +58 -0
  70. data/spec/dummy/public/500.html +57 -0
  71. data/spec/dummy/tmp/conduit/1/my_driver/foo/1-response.xml +3 -0
  72. data/spec/dummy/tmp/conduit/1/my_driver/foo/request.xml +7 -0
  73. data/spec/models/conduit/request_spec.rb +50 -0
  74. data/spec/models/conduit/response_spec.rb +52 -0
  75. data/spec/spec_helper.rb +36 -0
  76. data/spec/support/helper.rb +15 -0
  77. data/spec/support/xml/xml_request.xml +7 -0
  78. data/spec/support/xml/xml_response.xml +3 -0
  79. 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
@@ -0,0 +1,6 @@
1
+ module Conduit
2
+ class Subscription < ActiveRecord::Base
3
+ belongs_to :subscriber, polymorphic: true
4
+ belongs_to :request, class_name: 'Conduit::Request'
5
+ end
6
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Conduit::Engine.routes.draw do
2
+ resources :responses, only: [:create]
3
+ end
@@ -0,0 +1,13 @@
1
+ class CreateConduitRequests < ActiveRecord::Migration
2
+ def change
3
+ create_table :conduit_requests do |t|
4
+ t.string :driver
5
+ t.string :action
6
+ t.text :options
7
+ t.string :file
8
+ t.string :status
9
+
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ class CreateConduitResponses < ActiveRecord::Migration
2
+ def change
3
+ create_table :conduit_responses do |t|
4
+ t.string :file
5
+ t.references :request, index: true
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -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