saddle 0.0.12 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
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