saddle 0.0.12 → 0.0.14

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MGJkMTFhMzc3ZGU3YWQwZWFlOGQ3ZjdiYmM2OTk3NzRkMjg4OTRiMg==
4
+ MDE2NjI0YTFjNzExNzNhNTVjZGIxNDc0MjBmNjQ4ZWUzNzA1ODFkMA==
5
5
  data.tar.gz: !binary |-
6
- MTQxMzRjZDdmODhmMGI1ZTA5NzAyYzFhYTVjMzg2MGViMzMwYTY1Yw==
6
+ ZDkyZTUxZjgwNjMyNmFjYmEwMDc5ZWNkOTZiYTU3ZjZlYzI2NzVkZA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ZGJmMTZhZTAzOWFmMzg0ODE1Zjc5N2E0Yjk4N2M5N2U4NWNiYjc0MzA1MjJm
10
- ZmRhODc3MGYxMjZhNDlmYmNjYTA4ZTQ3ZTVmOTU0MDA5NmQ0MjAxYmEzMzAx
11
- YWIxN2NjODdlYmYzYzVlMjY3MmViY2UwM2JiOTcwMDlmMmE3M2I=
9
+ N2Y2ZDFiMmNhZjNmNmM5NzYxNzIzZWQ1YThmMGUzMTdkNTM3ZDM5YzJkNWJm
10
+ Y2Q5MGFkYzM0MGQ1NzdlNGY1ZmExMjFhN2JiZGNlZjRkMTIxZjQ0ZTUxMzNk
11
+ YWIxNWMxNTQ1YWQ4NjdkM2EzNDVjNTFkYjk3NjRiMmMxYmU5NWU=
12
12
  data.tar.gz: !binary |-
13
- MzZmOWM1M2RkM2IwNjRmNGM0OGM2NGQ3NmI5ZDAxMjBmY2U3OTEwNjE5YzEz
14
- MDA2YzQ2YWQxODY4NmZhMTM1MzQ4NzY3MDQ0YTcwNjUwMDViNGRkOTkyZjQy
15
- MzhlYWIwMzAyNWIwMTYxZjVmZTI0NWJkM2Y4MDUyODJjZjNmZGE=
13
+ Yzc0MzU4M2E5ZmQzYTQ5NTNlNjFlYzdjODJiYzgwZWNkOGRmZjg0OTYzMTU3
14
+ ZWZkZmUwZjMyMTBhZmI3OWY1YzdiNWQyYWY4NzkwNjk5Nzc3MzQ1ZDI2MTNm
15
+ NDdhYmRmZWI1YWQ0OTE3OWY5NTk1Yzg5NjRkYWQ2ZGE0MmE2YjU=
@@ -1,24 +1,18 @@
1
- module Saddle::ClientAttributes
1
+ module Saddle
2
+ module ClientAttributes
2
3
 
3
- def self.included(obj)
4
- obj.extend ClassMethods
4
+ def self.included(obj)
5
+ obj.extend ClassMethods
5
6
 
6
- # Clone the parent's additional_middlewares
7
- obj.additional_middlewares = if defined?(obj.superclass.additional_middlewares)
8
- obj.superclass.additional_middlewares.clone
9
- else
10
- []
7
+ # We know that this module is included when saddle client is inherited,
8
+ # so we're actually interested in the path of the caller two levels deep.
9
+ path, = caller[2].partition(":")
10
+ obj.implementation_root = File.dirname(path)
11
11
  end
12
12
 
13
- # We know that this module is included when saddle client is inherited,
14
- # so we're actually interested in the path of the caller two levels deep.
15
- path, = caller[2].partition(":")
16
- obj.implementation_root = File.dirname(path)
17
- end
13
+ module ClassMethods
14
+ attr_accessor :implementation_root
15
+ end
18
16
 
19
- module ClassMethods
20
- attr_accessor :implementation_root
21
- attr_accessor :additional_middlewares
22
17
  end
23
-
24
- end
18
+ end
@@ -1,7 +1,3 @@
1
-
2
-
3
-
4
-
5
1
  module Saddle
6
2
 
7
3
  # This base endpoint is what all implementation endpoints should inherit
data/lib/saddle/errors.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  module Saddle
2
+
2
3
  # The parent class of all exceptions thrown by Saddle
3
4
  class Error < StandardError; end
4
5
 
5
6
  # Thrown when a request timeout is exceeded
6
7
  class TimeoutError < Error; end
7
- end
8
+
9
+ end
@@ -10,94 +10,97 @@ require 'saddle/endpoint'
10
10
  # build the endpoint tree based upon module/class namespaces
11
11
 
12
12
 
13
- module Saddle::MethodTreeBuilder
14
-
15
- # Build out the endpoint structure from the root of the implementation
16
- def build_tree(requester)
17
- root_node = build_root_node(requester)
18
- # If we have an 'endpoints' directory, build it out
19
- if knows_root? && Dir.exists?(endpoints_directory)
20
- Dir["#{endpoints_directory}/**/*.rb"].each { |f| load(f) }
21
- build_node_children(self.endpoints_module, root_node, requester)
13
+ module Saddle
14
+ module MethodTreeBuilder
15
+
16
+ # Build out the endpoint structure from the root of the implementation
17
+ def build_tree(requester)
18
+ root_node = build_root_node(requester)
19
+ # If we have an 'endpoints' directory, build it out
20
+ if knows_root? && Dir.exists?(endpoints_directory)
21
+ Dir["#{endpoints_directory}/**/*.rb"].each { |f| load(f) }
22
+ build_node_children(self.endpoints_module, root_node, requester)
23
+ end
24
+ root_node
22
25
  end
23
- root_node
24
- end
25
26
 
26
27
 
27
- # Build our root node here. The root node is special in that it lives below
28
- # the 'endpoints' directory, and so we need to manually check if it exists.
29
- def build_root_node(requester)
30
- if knows_root?
31
- root_endpoint_file = File.join(
32
- self.implementation_root,
33
- 'root_endpoint.rb'
34
- )
35
- if File.file?(root_endpoint_file)
36
- # Load it and create our base endpoint
37
- load(root_endpoint_file)
38
- self.implementation_module::RootEndpoint.new(requester)
28
+ # Build our root node here. The root node is special in that it lives below
29
+ # the 'endpoints' directory, and so we need to manually check if it exists.
30
+ def build_root_node(requester)
31
+ if knows_root?
32
+ root_endpoint_file = File.join(
33
+ self.implementation_root,
34
+ 'root_endpoint.rb'
35
+ )
36
+ if File.file?(root_endpoint_file)
37
+ # Load it and create our base endpoint
38
+ load(root_endpoint_file)
39
+ self.implementation_module::RootEndpoint.new(requester)
40
+ else
41
+ # 'root_endpoint.rb' doesn't exist, so create a dummy endpoint
42
+ Saddle::BaseEndpoint.new(requester)
43
+ end
39
44
  else
40
- # 'root_endpoint.rb' doesn't exist, so create a dummy endpoint
45
+ # we don't even have an implementation root, so create a dummy endpoint
41
46
  Saddle::BaseEndpoint.new(requester)
42
47
  end
43
- else
44
- # we don't even have an implementation root, so create a dummy endpoint
45
- Saddle::BaseEndpoint.new(requester)
46
48
  end
47
- end
48
49
 
49
50
 
50
- # Build out the traversal tree by module namespace
51
- def build_node_children(current_module, current_node, requester)
52
- current_module.constants.each do |const_symbol|
53
- const = current_module.const_get(const_symbol)
54
-
55
- if const.class == Module
56
- # A module means that it's a branch
57
- # Build the branch out with a base endpoint
58
- branch_node = current_node.build_and_attach_node(
59
- Saddle::BaseEndpoint,
60
- ActiveSupport::Inflector.underscore(const_symbol)
61
- )
62
- # Build out the branch's endpoints on the new branch node
63
- self.build_node_children(const, branch_node, requester)
64
- end
65
-
66
- if const < Saddle::TraversalEndpoint
67
- # A class means that it's a node
68
- # Build out this endpoint on the current node
69
- current_node.build_and_attach_node(
70
- const,
71
- ActiveSupport::Inflector.underscore(const_symbol)
72
- )
51
+ # Build out the traversal tree by module namespace
52
+ def build_node_children(current_module, current_node, requester)
53
+ current_module.constants.each do |const_symbol|
54
+ const = current_module.const_get(const_symbol)
55
+
56
+ if const.class == Module
57
+ # A module means that it's a branch
58
+ # Build the branch out with a base endpoint
59
+ branch_node = current_node.build_and_attach_node(
60
+ Saddle::BaseEndpoint,
61
+ ActiveSupport::Inflector.underscore(const_symbol)
62
+ )
63
+ # Build out the branch's endpoints on the new branch node
64
+ self.build_node_children(const, branch_node, requester)
65
+ end
66
+
67
+ if const < Saddle::TraversalEndpoint
68
+ # A class means that it's a node
69
+ # Build out this endpoint on the current node
70
+ current_node.build_and_attach_node(
71
+ const,
72
+ ActiveSupport::Inflector.underscore(const_symbol)
73
+ )
74
+ end
73
75
  end
74
76
  end
75
- end
76
77
 
77
78
 
78
- # Get the module that the client implementation belongs to. This will act
79
- # as the root namespace for endpoint traversal and construction
80
- def implementation_module
81
- ::ActiveSupport::Inflector.constantize(
82
- self.name.split('::')[0..-2].join('::')
83
- )
84
- end
79
+ # Get the module that the client implementation belongs to. This will act
80
+ # as the root namespace for endpoint traversal and construction
81
+ def implementation_module
82
+ ::ActiveSupport::Inflector.constantize(
83
+ self.name.split('::')[0..-2].join('::')
84
+ )
85
+ end
85
86
 
86
- # Get the Endpoints module that lives within this implementation's
87
- # namespace
88
- def endpoints_module
89
- implementation_module.const_get('Endpoints')
90
- end
87
+ # Get the Endpoints module that lives within this implementation's
88
+ # namespace
89
+ def endpoints_module
90
+ implementation_module.const_get('Endpoints')
91
+ end
91
92
 
92
- # Get the path to the 'endpoints' directory, based upon the client
93
- # class that inherited Saddle
94
- def endpoints_directory
95
- File.join(self.implementation_root, 'endpoints')
96
- end
93
+ # Get the path to the 'endpoints' directory, based upon the client
94
+ # class that inherited Saddle
95
+ def endpoints_directory
96
+ File.join(self.implementation_root, 'endpoints')
97
+ end
98
+
99
+ # If this client was not fully constructed, it may not even have an
100
+ # implementation root. Allow that behavior and avoid firesystem searching.
101
+ def knows_root?
102
+ defined?(self.implementation_root)
103
+ end
97
104
 
98
- # If this client was not fully constructed, it may not even have an
99
- # implementation root. Allow that behavior and avoid firesystem searching.
100
- def knows_root?
101
- defined?(self.implementation_root)
102
105
  end
103
106
  end
@@ -3,33 +3,35 @@ require 'faraday'
3
3
 
4
4
 
5
5
 
6
- module Saddle::Middleware
7
- module Logging
6
+ module Saddle
7
+ module Middleware
8
+ module Logging
8
9
 
9
- # Public: Reports exceptions to Airbrake
10
- #
11
- class AirbrakeLogger < Faraday::Middleware
10
+ # Public: Reports exceptions to Airbrake
11
+ #
12
+ class AirbrakeLogger < Faraday::Middleware
12
13
 
13
- def initialize(app, airbrake_api_key=nil)
14
- super(app)
15
- @airbrake_api_key = airbrake_api_key
16
- end
14
+ def initialize(app, airbrake_api_key=nil)
15
+ super(app)
16
+ @airbrake_api_key = airbrake_api_key
17
+ end
17
18
 
18
- def call(env)
19
- begin
20
- @app.call(env)
21
- rescue => e
22
- # If we don't have an api key, use the default config
23
- if @airbrake_api_key
24
- ::Airbrake.notify(e, {:api_key => @airbrake_api_key} )
25
- else
26
- ::Airbrake.notify(e)
19
+ def call(env)
20
+ begin
21
+ @app.call(env)
22
+ rescue => e
23
+ # If we don't have an api key, use the default config
24
+ if @airbrake_api_key
25
+ ::Airbrake.notify(e, {:api_key => @airbrake_api_key} )
26
+ else
27
+ ::Airbrake.notify(e)
28
+ end
29
+ # Re-raise the error
30
+ raise
27
31
  end
28
- # Re-raise the error
29
- raise
30
32
  end
31
- end
32
33
 
34
+ end
33
35
  end
34
36
  end
35
37
  end
@@ -4,48 +4,50 @@ require 'faraday'
4
4
 
5
5
 
6
6
 
7
- module Saddle::Middleware
8
- module Logging
9
-
10
- # Public: Wraps request with statsd logging
11
- # Expects statsd_path in request options. However, if using saddle and no statsd_path is specified
12
- # will read call_chain and action and use them to construct a statsd_path
13
- class StatsdLogger < Faraday::Middleware
14
- attr_accessor :graphite_host, :graphite_port, :namespace
15
-
16
- def initialize(app, graphite_host, graphite_port=nil, namespace=nil)
17
- super(app)
18
- @graphite_host = graphite_host
19
- @graphite_port = graphite_port
20
- @namespace = namespace
21
- end
22
-
23
- def statsd
24
- @statsd ||= begin
25
- client = ::Statsd.new(@graphite_host, @graphite_port)
26
- client.namespace = @namespace if @namespace
7
+ module Saddle
8
+ module Middleware
9
+ module Logging
10
+
11
+ # Public: Wraps request with statsd logging
12
+ # Expects statsd_path in request options. However, if using saddle and no statsd_path is specified
13
+ # will read call_chain and action and use them to construct a statsd_path
14
+ class StatsdLogger < Faraday::Middleware
15
+ attr_accessor :graphite_host, :graphite_port, :namespace
16
+
17
+ def initialize(app, graphite_host, graphite_port=nil, namespace=nil)
18
+ super(app)
19
+ @graphite_host = graphite_host
20
+ @graphite_port = graphite_port
21
+ @namespace = namespace
27
22
  end
28
- end
29
23
 
30
- def call(env)
31
- # Try to build up a path for the STATSD logging
32
- statsd_path = nil
33
- if env[:request][:statsd_path]
34
- statsd_path = env[:request][:statsd_path]
35
- elsif env[:request][:saddle] && env[:request][:saddle][:call_chain] && env[:request][:saddle][:action]
36
- statsd_path = (['saddle'] + env[:request][:saddle][:call_chain] + [env[:request][:saddle][:action]]).join('.')
24
+ def statsd
25
+ @statsd ||= begin
26
+ client = ::Statsd.new(@graphite_host, @graphite_port)
27
+ client.namespace = @namespace if @namespace
28
+ end
37
29
  end
38
30
 
39
- # If we have a path, wrap the ensuing app call in STATSD timing
40
- if statsd_path
41
- self.statsd.time(statsd_path) do
31
+ def call(env)
32
+ # Try to build up a path for the STATSD logging
33
+ statsd_path = nil
34
+ if env[:request][:statsd_path]
35
+ statsd_path = env[:request][:statsd_path]
36
+ elsif env[:request][:saddle] && env[:request][:saddle][:call_chain] && env[:request][:saddle][:action]
37
+ statsd_path = (['saddle'] + env[:request][:saddle][:call_chain] + [env[:request][:saddle][:action]]).join('.')
38
+ end
39
+
40
+ # If we have a path, wrap the ensuing app call in STATSD timing
41
+ if statsd_path
42
+ self.statsd.time(statsd_path) do
43
+ @app.call(env)
44
+ end
45
+ else
42
46
  @app.call(env)
43
47
  end
44
- else
45
- @app.call(env)
46
48
  end
47
49
  end
48
- end
49
50
 
51
+ end
50
52
  end
51
53
  end
@@ -2,33 +2,35 @@ require 'faraday'
2
2
 
3
3
 
4
4
 
5
- module Saddle::Middleware
6
- module Request
5
+ module Saddle
6
+ module Middleware
7
+ module Request
7
8
 
8
- # Request middleware that encodes the body as JSON.
9
- #
10
- # Make sure you set request[:request_style] = :json
11
- # for it to be activated.
9
+ # Request middleware that encodes the body as JSON.
10
+ #
11
+ # Make sure you set request[:request_style] = :json
12
+ # for it to be activated.
12
13
 
13
- class JsonEncoded < Faraday::Middleware
14
- CONTENT_TYPE = 'Content-Type'.freeze
15
- MIME_TYPE = 'application/json'.freeze
14
+ class JsonEncoded < Faraday::Middleware
15
+ CONTENT_TYPE = 'Content-Type'.freeze
16
+ MIME_TYPE = 'application/json'.freeze
16
17
 
17
- dependency do
18
- require 'json' unless defined?(::JSON)
19
- end
18
+ dependency do
19
+ require 'json' unless defined?(::JSON)
20
+ end
20
21
 
21
- def call(env)
22
- if env[:request][:request_style] == :json
23
- # Make sure we're working with a valid body that's not a String
24
- if env[:body] and !env[:body].respond_to?(:to_str)
25
- env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
26
- env[:body] = ::JSON.dump(env[:body])
22
+ def call(env)
23
+ if env[:request][:request_style] == :json
24
+ # Make sure we're working with a valid body that's not a String
25
+ if env[:body] and !env[:body].respond_to?(:to_str)
26
+ env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
27
+ env[:body] = ::JSON.dump(env[:body])
28
+ end
27
29
  end
30
+ @app.call env
28
31
  end
29
- @app.call env
30
32
  end
31
- end
32
33
 
34
+ end
33
35
  end
34
- end
36
+ end
@@ -2,54 +2,56 @@ require 'faraday'
2
2
 
3
3
 
4
4
 
5
- module Saddle::Middleware
6
- module Request
5
+ module Saddle
6
+ module Middleware
7
+ module Request
7
8
 
8
- # Catches exceptions and retries each request a limited number of times.
9
- #
10
- # By default, it retries 2 times and performs exponential backoff, starting
11
- # at 50ms
12
- class Retry < Faraday::Middleware
13
- def initialize(app, ignored_exceptions=[])
14
- super(app)
15
- @ignored_exceptions = ignored_exceptions
16
- end
9
+ # Catches exceptions and retries each request a limited number of times.
10
+ #
11
+ # By default, it retries 2 times and performs exponential backoff, starting
12
+ # at 50ms
13
+ class Retry < Faraday::Middleware
14
+ def initialize(app, ignored_exceptions=[])
15
+ super(app)
16
+ @ignored_exceptions = ignored_exceptions
17
+ end
17
18
 
18
- def call(env)
19
- retries = env[:request][:num_retries] || 2
20
- backoff = env[:request][:retry_backoff] || 0.050 # ms
21
- begin
22
- @app.call(self.class.deep_copy(env))
23
- rescue => e
24
- unless @ignored_exceptions.include?(e.class)
25
- # Retry a limited number of times
26
- if retries > 0
27
- retries -= 1
28
- sleep(backoff) if backoff > 0.0
29
- backoff *= 2
30
- retry
19
+ def call(env)
20
+ retries = env[:request][:num_retries] || 2
21
+ backoff = env[:request][:retry_backoff] || 0.050 # ms
22
+ begin
23
+ @app.call(self.class.deep_copy(env))
24
+ rescue => e
25
+ unless @ignored_exceptions.include?(e.class)
26
+ # Retry a limited number of times
27
+ if retries > 0
28
+ retries -= 1
29
+ sleep(backoff) if backoff > 0.0
30
+ backoff *= 2
31
+ retry
32
+ end
31
33
  end
34
+ # Re-raise if we're out of retries or it's not handled
35
+ raise
32
36
  end
33
- # Re-raise if we're out of retries or it's not handled
34
- raise
35
37
  end
36
- end
37
38
 
38
- def self.deep_copy(value)
39
- if value.is_a?(Hash)
40
- result = value.clone
41
- value.each{|k, v| result[k] = deep_copy(v)}
42
- result
43
- elsif value.is_a?(Array)
44
- result = value.clone
45
- result.clear
46
- value.each{|v| result << deep_copy(v)}
47
- result
48
- else
49
- value
39
+ def self.deep_copy(value)
40
+ if value.is_a?(Hash)
41
+ result = value.clone
42
+ value.each{|k, v| result[k] = deep_copy(v)}
43
+ result
44
+ elsif value.is_a?(Array)
45
+ result = value.clone
46
+ result.clear
47
+ value.each{|v| result << deep_copy(v)}
48
+ result
49
+ else
50
+ value
51
+ end
50
52
  end
51
53
  end
52
- end
53
54
 
55
+ end
54
56
  end
55
57
  end
@@ -2,85 +2,87 @@ require 'faraday'
2
2
 
3
3
 
4
4
 
5
- module Saddle::Middleware
6
- module Request
5
+ module Saddle
6
+ module Middleware
7
+ module Request
7
8
 
8
- # This magically handles converting your body from a hash
9
- # into an url-encoded (or multipart if needed) request
9
+ # This magically handles converting your body from a hash
10
+ # into an url-encoded (or multipart if needed) request
10
11
 
11
- # Make sure you set request[:request_style] = :urlencoded
12
- # for it to be activated.
12
+ # Make sure you set request[:request_style] = :urlencoded
13
+ # for it to be activated.
13
14
 
14
- class UrlEncoded < Faraday::Middleware
15
- CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
15
+ class UrlEncoded < Faraday::Middleware
16
+ CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
16
17
 
17
- URL_ENCODED_MIME_TYPE = 'application/x-www-form-urlencoded'.freeze
18
- MULTIPART_MIME_TYPE = 'multipart/form-data'.freeze
18
+ URL_ENCODED_MIME_TYPE = 'application/x-www-form-urlencoded'.freeze
19
+ MULTIPART_MIME_TYPE = 'multipart/form-data'.freeze
19
20
 
20
- VALID_MIME_TYPES = [URL_ENCODED_MIME_TYPE, MULTIPART_MIME_TYPE]
21
+ VALID_MIME_TYPES = [URL_ENCODED_MIME_TYPE, MULTIPART_MIME_TYPE]
21
22
 
22
- DEFAULT_MULTIPART_BOUNDARY = "-^---_---^-".freeze
23
+ DEFAULT_MULTIPART_BOUNDARY = "-^---_---^-".freeze
23
24
 
24
25
 
25
- def call(env)
26
- if env[:request][:request_style] == :urlencoded
27
- # Make sure we're working with a valid body that's not a String
28
- if env[:body] and !env[:body].respond_to?(:to_str)
29
- if has_multipart?(env[:body])
30
- env[:request][:boundary] ||= DEFAULT_MULTIPART_BOUNDARY
31
- env[:request_headers][CONTENT_TYPE] ||= MULTIPART_MIME_TYPE
32
- env[:request_headers][CONTENT_TYPE] += ";boundary=#{env[:request][:boundary]}"
33
- env[:body] = create_multipart(env, env[:body])
34
- else
35
- env[:request_headers][CONTENT_TYPE] ||= URL_ENCODED_MIME_TYPE
36
- env[:body] = Faraday::Utils::ParamsHash[env[:body]].to_query
26
+ def call(env)
27
+ if env[:request][:request_style] == :urlencoded
28
+ # Make sure we're working with a valid body that's not a String
29
+ if env[:body] and !env[:body].respond_to?(:to_str)
30
+ if has_multipart?(env[:body])
31
+ env[:request][:boundary] ||= DEFAULT_MULTIPART_BOUNDARY
32
+ env[:request_headers][CONTENT_TYPE] ||= MULTIPART_MIME_TYPE
33
+ env[:request_headers][CONTENT_TYPE] += ";boundary=#{env[:request][:boundary]}"
34
+ env[:body] = create_multipart(env, env[:body])
35
+ else
36
+ env[:request_headers][CONTENT_TYPE] ||= URL_ENCODED_MIME_TYPE
37
+ env[:body] = Faraday::Utils::ParamsHash[env[:body]].to_query
38
+ end
37
39
  end
38
40
  end
41
+ @app.call env
39
42
  end
40
- @app.call env
41
- end
42
43
 
43
44
 
44
- private
45
+ private
45
46
 
46
- def has_multipart?(obj)
47
- # string is an enum in 1.8, returning list of itself
48
- if obj.respond_to?(:each) && !obj.is_a?(String)
49
- (obj.respond_to?(:values) ? obj.values : obj).each do |val|
50
- return true if (val.respond_to?(:content_type) || has_multipart?(val))
47
+ def has_multipart?(obj)
48
+ # string is an enum in 1.8, returning list of itself
49
+ if obj.respond_to?(:each) && !obj.is_a?(String)
50
+ (obj.respond_to?(:values) ? obj.values : obj).each do |val|
51
+ return true if (val.respond_to?(:content_type) || has_multipart?(val))
52
+ end
51
53
  end
54
+ false
52
55
  end
53
- false
54
- end
55
56
 
56
- def create_multipart(env, params)
57
- boundary = env[:request][:boundary]
58
- parts = process_params(params) do |key, value|
59
- Faraday::Parts::Part.new(boundary, key, value)
60
- end
61
- parts << Faraday::Parts::EpiloguePart.new(boundary)
57
+ def create_multipart(env, params)
58
+ boundary = env[:request][:boundary]
59
+ parts = process_params(params) do |key, value|
60
+ Faraday::Parts::Part.new(boundary, key, value)
61
+ end
62
+ parts << Faraday::Parts::EpiloguePart.new(boundary)
62
63
 
63
- body = Faraday::CompositeReadIO.new(parts)
64
- env[:request_headers][Faraday::Env::ContentLength] = body.length.to_s
65
- body
66
- end
64
+ body = Faraday::CompositeReadIO.new(parts)
65
+ env[:request_headers][Faraday::Env::ContentLength] = body.length.to_s
66
+ body
67
+ end
67
68
 
68
- def process_params(params, prefix = nil, pieces = nil, &block)
69
- params.inject(pieces || []) do |all, (key, value)|
70
- key = "#{prefix}[#{key}]" if prefix
71
-
72
- case value
73
- when Array
74
- values = value.inject([]) { |a,v| a << [nil, v] }
75
- process_params(values, key, all, &block)
76
- when Hash
77
- process_params(value, key, all, &block)
78
- else
79
- all << block.call(key, value)
69
+ def process_params(params, prefix = nil, pieces = nil, &block)
70
+ params.inject(pieces || []) do |all, (key, value)|
71
+ key = "#{prefix}[#{key}]" if prefix
72
+
73
+ case value
74
+ when Array
75
+ values = value.inject([]) { |a,v| a << [nil, v] }
76
+ process_params(values, key, all, &block)
77
+ when Hash
78
+ process_params(value, key, all, &block)
79
+ else
80
+ all << block.call(key, value)
81
+ end
80
82
  end
81
83
  end
82
84
  end
83
- end
84
85
 
86
+ end
85
87
  end
86
88
  end
@@ -1,24 +1,27 @@
1
1
  require 'faraday'
2
2
 
3
3
 
4
- module Saddle::Middleware
5
- module Response
6
4
 
7
- # Public: Returns a default response in the case of an exception
8
- # Expects default_response to be defined in the request of connection options, otherwise rethrows exception
9
- class DefaultResponse < Faraday::Middleware
10
- def call(env)
11
- begin
12
- @app.call(env)
13
- rescue Faraday::Error
14
- if res = env[:request][:default_response]
15
- return ::Faraday::Response.new(:body => res)
16
- else
17
- raise
5
+ module Saddle
6
+ module Middleware
7
+ module Response
8
+
9
+ # Public: Returns a default response in the case of an exception
10
+ # Expects default_response to be defined in the request of connection options, otherwise rethrows exception
11
+ class DefaultResponse < Faraday::Middleware
12
+ def call(env)
13
+ begin
14
+ @app.call(env)
15
+ rescue Faraday::Error
16
+ if res = env[:request][:default_response]
17
+ return ::Faraday::Response.new(:body => res)
18
+ else
19
+ raise
20
+ end
18
21
  end
19
22
  end
20
23
  end
21
- end
22
24
 
25
+ end
23
26
  end
24
27
  end
@@ -2,45 +2,47 @@ require 'faraday'
2
2
 
3
3
 
4
4
 
5
- module Saddle::Middleware
6
- module Response
5
+ module Saddle
6
+ module Middleware
7
+ module Response
7
8
 
8
- # Public: Parse response bodies as JSON.
9
- class ParseJson < Faraday::Middleware
10
- CONTENT_TYPE = 'Content-Type'.freeze
11
- MIME_TYPE = 'application/json'.freeze
9
+ # Public: Parse response bodies as JSON.
10
+ class ParseJson < Faraday::Middleware
11
+ CONTENT_TYPE = 'Content-Type'.freeze
12
+ MIME_TYPE = 'application/json'.freeze
12
13
 
13
- dependency do
14
- require 'json' unless defined?(::JSON)
15
- end
14
+ dependency do
15
+ require 'json' unless defined?(::JSON)
16
+ end
16
17
 
17
- def call(env)
18
- result = @app.call env
19
- if parse_response?(env)
20
- # Make sure we're working with a valid body that's not a String
21
- if env[:body] && env[:body].respond_to?(:to_str)
22
- env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
23
- env[:body] = ::JSON.parse env[:body]
18
+ def call(env)
19
+ result = @app.call env
20
+ if parse_response?(env)
21
+ # Make sure we're working with a valid body that's not a String
22
+ if env[:body] && env[:body].respond_to?(:to_str)
23
+ env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
24
+ env[:body] = ::JSON.parse env[:body]
25
+ end
24
26
  end
27
+ result
25
28
  end
26
- result
27
- end
28
29
 
29
- def parse_response?(env)
30
- has_body?(env) and (response_type(env) == MIME_TYPE)
31
- end
30
+ def parse_response?(env)
31
+ has_body?(env) and (response_type(env) == MIME_TYPE)
32
+ end
32
33
 
33
- def has_body?(env)
34
- body = env[:body] and !(body.respond_to?(:to_str) and body.empty?)
35
- end
34
+ def has_body?(env)
35
+ body = env[:body] and !(body.respond_to?(:to_str) and body.empty?)
36
+ end
36
37
 
37
- def response_type(env)
38
- return nil unless env[:response_headers]
39
- type = env[:response_headers][CONTENT_TYPE].to_s
40
- type = type.split(';', 2).first if type.index(';')
41
- type
38
+ def response_type(env)
39
+ return nil unless env[:response_headers]
40
+ type = env[:response_headers][CONTENT_TYPE].to_s
41
+ type = type.split(';', 2).first if type.index(';')
42
+ type
43
+ end
42
44
  end
43
- end
44
45
 
46
+ end
45
47
  end
46
48
  end
@@ -1,24 +1,29 @@
1
1
  require 'faraday'
2
2
 
3
+ require 'saddle/errors'
3
4
 
4
- module Saddle::Middleware
5
5
 
6
- # Public: Enforces a ruby timeout on the request and throws one consistent
7
- # exception for all classes of timeout, internal or from faraday.
8
- # :timeout must be present in the request or client options
9
- class RubyTimeout < Faraday::Middleware
10
6
 
11
- def call(env)
12
- timeout = env[:request][:timeout] # nil or 0 means no timeout
13
- Timeout.timeout(timeout, Saddle::TimeoutError) do
14
- @app.call(env)
7
+ module Saddle
8
+ module Middleware
9
+
10
+ # Public: Enforces a ruby timeout on the request and throws one consistent
11
+ # exception for all classes of timeout, internal or from faraday.
12
+ # :timeout must be present in the request or client options
13
+ class RubyTimeout < Faraday::Middleware
14
+
15
+ def call(env)
16
+ timeout = env[:request][:timeout] # nil or 0 means no timeout
17
+ Timeout.timeout(timeout, Saddle::TimeoutError) do
18
+ @app.call(env)
19
+ end
20
+ # It is possible that faraday will catch the timeout first and throw
21
+ # this exception, rethrow as a class derived from standard error.
22
+ rescue Faraday::Error::TimeoutError
23
+ raise Saddle::TimeoutError
15
24
  end
16
- # It is possible that faraday will catch the timeout first and throw
17
- # this exception, rethrow as a class derived from standard error.
18
- rescue Faraday::Error::TimeoutError
19
- raise Saddle::TimeoutError
25
+
20
26
  end
21
27
 
22
28
  end
23
-
24
29
  end
@@ -1,73 +1,71 @@
1
-
2
-
3
-
4
1
  # Default options for a client. Override whatever you need to for
5
2
  # your specific implementation
6
3
 
4
+ module Saddle
5
+ module Options
7
6
 
8
- module Saddle::Options
7
+ # Construct our default options, based upon the class methods
8
+ def default_options
9
+ {
10
+ :host => host,
11
+ :port => port,
12
+ :use_ssl => use_ssl,
13
+ :request_style => request_style,
14
+ :num_retries => num_retries,
15
+ :timeout => timeout,
16
+ :additional_middlewares => self.additional_middlewares,
17
+ :stubs => stubs,
18
+ }
19
+ end
9
20
 
10
- # Construct our default options, based upon the class methods
11
- def default_options
12
- {
13
- :host => host,
14
- :port => port,
15
- :use_ssl => use_ssl,
16
- :request_style => request_style,
17
- :num_retries => num_retries,
18
- :timeout => timeout,
19
- :additional_middlewares => self.additional_middlewares,
20
- :stubs => stubs,
21
- }
22
- end
21
+ # The default host for this client
22
+ def host
23
+ 'localhost'
24
+ end
23
25
 
24
- # The default host for this client
25
- def host
26
- 'localhost'
27
- end
26
+ # The default port for this client
27
+ def port
28
+ 80
29
+ end
28
30
 
29
- # The default port for this client
30
- def port
31
- 80
32
- end
31
+ # Should this client use SSL by default?
32
+ def use_ssl
33
+ false
34
+ end
33
35
 
34
- # Should this client use SSL by default?
35
- def use_ssl
36
- false
37
- end
36
+ # The POST/PUT style for this client
37
+ # options are [:json, :urlencoded]
38
+ def request_style
39
+ :json
40
+ end
38
41
 
39
- # The POST/PUT style for this client
40
- # options are [:json, :urlencoded]
41
- def request_style
42
- :json
43
- end
42
+ # Default number of retries per request
43
+ def num_retries
44
+ 3
45
+ end
44
46
 
45
- # Default number of retries per request
46
- def num_retries
47
- 3
48
- end
47
+ # Default timeout per request (in seconds)
48
+ def timeout
49
+ 30
50
+ end
49
51
 
50
- # Default timeout per request (in seconds)
51
- def timeout
52
- 30
53
- end
52
+ # Use this to add additional middleware to the request stack
53
+ # ex:
54
+ # add_middleware({
55
+ # :klass => MyMiddleware,
56
+ # :args => [arg1, arg2],
57
+ # })
58
+ # end
59
+ #
60
+ ###
61
+ def add_middleware m
62
+ self.additional_middlewares << m
63
+ end
54
64
 
55
- # Use this to add additional middleware to the request stack
56
- # ex:
57
- # add_middleware({
58
- # :klass => MyMiddleware,
59
- # :args => [arg1, arg2],
60
- # })
61
- # end
62
- #
63
- ###
64
- def add_middleware m
65
- self.additional_middlewares << m
66
- end
65
+ # If the Typhoeus adapter is being used, pass stubs to it for testing.
66
+ def stubs
67
+ nil
68
+ end
67
69
 
68
- # If the Typhoeus adapter is being used, pass stubs to it for testing.
69
- def stubs
70
- nil
71
70
  end
72
-
73
71
  end
@@ -15,7 +15,6 @@ require 'saddle/middleware/ruby_timeout'
15
15
 
16
16
 
17
17
  module Saddle
18
-
19
18
  class Requester
20
19
 
21
20
  VALID_BODY_STYLES = [:json, :urlencoded]
@@ -149,5 +148,4 @@ module Saddle
149
148
  end
150
149
 
151
150
  end
152
-
153
151
  end
@@ -1,3 +1,3 @@
1
1
  module Saddle
2
- VERSION = '0.0.12'
2
+ VERSION = '0.0.14'
3
3
  end
data/lib/saddle.rb CHANGED
@@ -15,6 +15,10 @@ module Saddle
15
15
  extend MethodTreeBuilder
16
16
  extend Options
17
17
 
18
+ class << self
19
+ attr_accessor :additional_middlewares
20
+ end
21
+
18
22
  # Once your implementation is written, this is the magic you need to
19
23
  # create a client instance.
20
24
  def self.create(opt={})
@@ -26,6 +30,13 @@ module Saddle
26
30
  end
27
31
 
28
32
  def self.inherited(obj)
33
+ # Clone the parent's additional_middlewares
34
+ obj.additional_middlewares = if defined?(obj.superclass.additional_middlewares)
35
+ (obj.superclass.additional_middlewares || []).clone
36
+ else
37
+ []
38
+ end
39
+ # Add additional client attributes
29
40
  obj.send(:include, Saddle::ClientAttributes)
30
41
  end
31
42
 
@@ -0,0 +1,73 @@
1
+ require 'faraday'
2
+ require 'saddle'
3
+
4
+
5
+
6
+ ### Make sure that multiple implementations of Saddle clients don't conflict with each other's middlewar.
7
+
8
+ describe Saddle::Client do
9
+
10
+ context "multiple implementations" do
11
+ context "using different middleware" do
12
+
13
+ before :each do
14
+ # Middlewares
15
+ class Middleware1 < Faraday::Middleware
16
+ # Hook for catching calls
17
+ def subcall
18
+ end
19
+
20
+ def call(env)
21
+ self.subcall
22
+ @app.call(env)
23
+ end
24
+ end
25
+
26
+ class Middleware2 < Faraday::Middleware
27
+ # Hook for catching calls
28
+ def subcall
29
+ end
30
+
31
+ def call(env)
32
+ self.subcall
33
+ @app.call(env)
34
+ end
35
+ end
36
+
37
+
38
+ # Clients
39
+ class Client1 < Saddle::Client
40
+ add_middleware({:klass => Middleware1})
41
+ end
42
+ class Client2 < Saddle::Client
43
+ add_middleware({:klass => Middleware2})
44
+ end
45
+ end
46
+
47
+ it "should not overlap" do
48
+ # Set up our stubs
49
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
50
+ stub.get('/') {
51
+ [
52
+ 200,
53
+ {},
54
+ 'Party on!',
55
+ ]
56
+ }
57
+ end
58
+
59
+ # Set up our clients
60
+ client1 = Client1.create(:stubs => stubs)
61
+ client2 = Client2.create(:stubs => stubs)
62
+
63
+ # Make sure client2's middleware isn't called
64
+ Middleware1.any_instance.should_receive(:subcall)
65
+ Middleware2.any_instance.should_not_receive(:subcall)
66
+
67
+ # Make the call
68
+ client1.requester.get('/')
69
+ end
70
+
71
+ end
72
+ end
73
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saddle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Lewis
@@ -82,6 +82,7 @@ files:
82
82
  - lib/saddle/version.rb
83
83
  - saddle.gemspec
84
84
  - spec/requester/get_spec.rb
85
+ - spec/requester/multiple_spec.rb
85
86
  - spec/requester/post_spec.rb
86
87
  - spec/requester/retry_spec.rb
87
88
  homepage: https://github.com/mLewisLogic/saddle
@@ -111,5 +112,6 @@ summary: A full-featured, generic consumer layer for you to build API client imp
111
112
  with.
112
113
  test_files:
113
114
  - spec/requester/get_spec.rb
115
+ - spec/requester/multiple_spec.rb
114
116
  - spec/requester/post_spec.rb
115
117
  - spec/requester/retry_spec.rb