saddle 0.0.53 → 0.2.0

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 (43) hide show
  1. checksums.yaml +5 -13
  2. data/.github/workflows/ci.yml +55 -0
  3. data/.gitignore +1 -0
  4. data/Appraisals +39 -0
  5. data/CHANGELOG.md +3 -0
  6. data/Gemfile +2 -2
  7. data/README.md +48 -10
  8. data/bin/template/lib/saddle-client/middleware/exception_raiser.rb +1 -1
  9. data/gemfiles/activesupport_3.2.gemfile +20 -0
  10. data/gemfiles/activesupport_4.0.gemfile +20 -0
  11. data/gemfiles/activesupport_4.1.gemfile +20 -0
  12. data/gemfiles/activesupport_4.2.gemfile +20 -0
  13. data/gemfiles/activesupport_5.0.gemfile +20 -0
  14. data/gemfiles/activesupport_5.1.gemfile +20 -0
  15. data/gemfiles/activesupport_5.2.gemfile +20 -0
  16. data/gemfiles/activesupport_6.0.gemfile +20 -0
  17. data/gemfiles/activesupport_6.1.gemfile +20 -0
  18. data/gemfiles/activesupport_7.0.gemfile +20 -0
  19. data/lib/saddle/endpoint.rb +6 -9
  20. data/lib/saddle/faraday/rack_builder.rb +15 -0
  21. data/lib/saddle/faraday/request.rb +4 -0
  22. data/lib/saddle/middleware/authentication/oauth1.rb +6 -6
  23. data/lib/saddle/middleware/authentication/oauth2.rb +2 -2
  24. data/lib/saddle/middleware/extra_env.rb +2 -2
  25. data/lib/saddle/middleware/logging/rails.rb +1 -1
  26. data/lib/saddle/middleware/logging/statsd.rb +7 -7
  27. data/lib/saddle/middleware/request/encode_json.rb +1 -7
  28. data/lib/saddle/middleware/request/path_prefix.rb +2 -2
  29. data/lib/saddle/middleware/request/retry.rb +8 -4
  30. data/lib/saddle/middleware/request/url_encoded.rb +1 -1
  31. data/lib/saddle/middleware/request/user_agent.rb +1 -1
  32. data/lib/saddle/middleware/response/default_response.rb +1 -1
  33. data/lib/saddle/middleware/response/parse_json.rb +0 -6
  34. data/lib/saddle/middleware/response/raise_error.rb +2 -2
  35. data/lib/saddle/middleware/ruby_timeout.rb +2 -2
  36. data/lib/saddle/requester.rb +27 -28
  37. data/lib/saddle/version.rb +1 -1
  38. data/saddle.gemspec +6 -8
  39. data/spec/endpoint/base_endpoint_spec.rb +2 -2
  40. data/spec/middleware/instrumentation_spec.rb +1 -1
  41. data/spec/middleware/request/retry_spec.rb +1 -1
  42. data/spec/requester/get_spec.rb +1 -1
  43. metadata +37 -24
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ODQ4YmI4OGJiZDRjMjBhNmFkOWI1NGEzZWIyNDA0NWM3NGJjZTdlMQ==
5
- data.tar.gz: !binary |-
6
- NGI3MWM5MDgzZWIyYjVkM2RhYzk1YmRjMGY5YjU3MmE2N2MxNGYyMQ==
2
+ SHA256:
3
+ metadata.gz: c6cbc5f3bed08d163ba1f6bb948acb555c16b9034ff6adac036a0f1f4252f872
4
+ data.tar.gz: 6b509a1bdb969e7b54c3c6fd93d742ef3cfd7144de2e8c36014f8a5fdc32484a
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- M2JkMWY0YTljNmFmOGI3MjA0NjY0MDRkZmU0ODc4MDNlYmYzMTNmNjVkMmJl
10
- YmI4ZjBkMzhiOWJhMmFlYjg1MGE1YTJjZDg4MmY5Mjc0N2RmNDBkZjFjZmMy
11
- ZjYxZWVjYzZiZjI1MzMwYWJmMjdiYWY3NDJmODNmMDk5ZGY0M2I=
12
- data.tar.gz: !binary |-
13
- M2Q3NWU4ODRkZGRkOWI5MDY2NmFkZWY3NDViNmZmYjE2NWJlMjEyYTBhY2Qx
14
- ZGY3M2VmYzIwMmFkMjc2M2VlZTRhNTQwZjU1Yjg1MGRlNzMyMTQ0Mzg0NDRj
15
- NGViYjZjY2EwMWIwN2VkYzgzNGU0MGI2NjJiODVkNGY5M2ZjZDU=
6
+ metadata.gz: c22f775da62289da5111c42fc64373aec52b3c831b828a0b40f9fda5d354d569da0481e8d789422965cd802ea23855816c4d53224ec3507a5a8dd977f7209c0c
7
+ data.tar.gz: 392ebba3e48907a68867ba54125fdccbc26df04659fd84db2aa053823af414da24093eca48bf3b460efaf43bfcbc1792c813b25e04c6a521b221f815ef89503d
@@ -0,0 +1,55 @@
1
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
2
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
3
+
4
+ name: Ruby
5
+
6
+ on: [pull_request, push]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ ruby-version: [2.6, 2.7, '3.0', 3.1]
17
+ gemfile:
18
+ - activesupport_3.2
19
+ - activesupport_4.0
20
+ - activesupport_4.1
21
+ - activesupport_4.2
22
+ - activesupport_5.0
23
+ - activesupport_5.1
24
+ - activesupport_5.2
25
+ - activesupport_6.0
26
+ - activesupport_6.1
27
+ - activesupport_7.0
28
+ exclude:
29
+ - ruby-version: 2.6
30
+ gemfile: activesupport_7.0
31
+ - ruby-version: '3.0'
32
+ gemfile: activesupport_4.1
33
+ - ruby-version: 3.1
34
+ gemfile: activesupport_4.1
35
+ steps:
36
+ - uses: actions/checkout@v3
37
+
38
+ - name: Set up Ruby
39
+ uses: ruby/setup-ruby@v1
40
+ with:
41
+ ruby-version: ${{ matrix.ruby-version }}
42
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
43
+
44
+ - name: Generate Appraisal gemfiles
45
+ run: bundle exec appraisal generate
46
+
47
+ - name: Install dependencies
48
+ env:
49
+ BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
50
+ run: bundle install
51
+
52
+ - name: Run rspec
53
+ env:
54
+ BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
55
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -12,6 +12,7 @@
12
12
  # Gems
13
13
  *.gem
14
14
  Gemfile.lock
15
+ gemfiles/*.lock
15
16
 
16
17
  # IDEs
17
18
  .idea
data/Appraisals ADDED
@@ -0,0 +1,39 @@
1
+ appraise "activesupport_3.2" do
2
+ gem "activesupport", "~> 3.2.22"
3
+ end
4
+
5
+ appraise "activesupport_4.0" do
6
+ gem "activesupport", "~> 4.0.13"
7
+ end
8
+
9
+ appraise "activesupport_4.1" do
10
+ gem "activesupport", "~> 4.1.16"
11
+ end
12
+
13
+ appraise "activesupport_4.2" do
14
+ gem "activesupport", "~> 4.2.11"
15
+ end
16
+
17
+ appraise "activesupport_5.0" do
18
+ gem "activesupport", "~> 5.0.7"
19
+ end
20
+
21
+ appraise "activesupport_5.1" do
22
+ gem "activesupport", "~> 5.1.7"
23
+ end
24
+
25
+ appraise "activesupport_5.2" do
26
+ gem "activesupport", "~> 5.2.8"
27
+ end
28
+
29
+ appraise "activesupport_6.0" do
30
+ gem "activesupport", "~> 6.0.6"
31
+ end
32
+
33
+ appraise "activesupport_6.1" do
34
+ gem "activesupport", "~> 6.1.7"
35
+ end
36
+
37
+ appraise "activesupport_7.0" do
38
+ gem "activesupport", "~> 7.0.4"
39
+ end
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ # 0.0.54
2
+ * Work with faraday ~> 0.9.0. With these changes, Saddle no longer works with faraday < 0.9.
3
+
1
4
  # 0.0.49
2
5
  * Support `extra_env` as a client option to load more into the env pre-adapter.
3
6
 
data/Gemfile CHANGED
@@ -4,8 +4,8 @@ gemspec
4
4
 
5
5
  group :test do
6
6
  gem 'rake'
7
- gem 'rspec', '~> 2.14.1'
8
- gem 'rspec-instafail', '~> 0.2'
7
+ gem 'rspec', '~> 3.12'
8
+ gem 'rspec-instafail', '~> 1'
9
9
 
10
10
  gem 'airbrake'
11
11
  gem 'simple_oauth', '~> 0.2.0' # Optional dependency
data/README.md CHANGED
@@ -41,16 +41,16 @@ Saddle enables you to create beautifully stable and functionaly API clients, in
41
41
  [saddle-example](https://github.com/mLewisLogic/saddle-example)
42
42
 
43
43
  ### client construction
44
- 0. For the sake of cleanliness, pick a namespace that everything related to your client should live in. For this example, we'll use __SaddleExample__
45
- 1. Inherit your client class, __SaddleExample::Client__, from __Saddle::Client__
46
- 2. Create an _endpoints_ directory at the same level as your client class file
47
- 3. Create endpoint classes in the _endpoints_ directory that inherit from __Saddle::TraversalEndpoint__ and are under the __SaddleExample::Endpoints__ namespace module
48
- 1. Give these endpoints methods that call _get_ or _post_ to perform the actual request
49
- 2. Their module/class namespace determines how they are accessed in the client's call tree. For example, the get\_all() in __SaddleExample::Endpoints::Fish::Guppy__ would be accessed by:
44
+ 0. For the sake of cleanliness, pick a namespace that everything related to your client should live in. For this example, we'll use __SaddleExample__.
45
+ 1. Inherit your client class, __SaddleExample::Client__, from __Saddle::Client__.
46
+ 2. Create an _endpoints_ directory at the same level as your client class file.
47
+ 3. Create endpoint classes in the _endpoints_ directory that inherit from __Saddle::TraversalEndpoint__ and are under the __SaddleExample::Endpoints__ namespace module.
48
+ 1. Give these endpoints methods that call `get` or `post` to perform the actual request
49
+ 2. Their module/class namespace determines how they are accessed in the client's call tree. For example, the `get_all` in __SaddleExample::Endpoints::Fish::Guppy__ would be accessed by:
50
50
 
51
- client.fish.guppy.get_all()
51
+ client.fish.guppy.get_all
52
52
 
53
- 3. If you need REST style endpoints like client.fish('guppy').catch() then check out __Saddle::ResourceEndpoint__ and how it's used in [saddle-example](https://github.com/mLewisLogic/saddle-example/blob/master/lib/endpoints/kitten.rb)
53
+ 3. If you need REST style endpoints like `client.kitten.by_id('Whiskers').info` then check out __Saddle::ResourceEndpoint__ and how it's used in [saddle-example](https://github.com/mLewisLogic/saddle-example/blob/master/lib/saddle-example/endpoints/kitten.rb)
54
54
 
55
55
  4. Initialize an instance of your client. ex:
56
56
 
@@ -62,11 +62,49 @@ Saddle enables you to create beautifully stable and functionaly API clients, in
62
62
  * xml posting/parsing
63
63
 
64
64
 
65
+ ## version notes
66
+
67
+ * Saddle versions 0.2.x supports Ruby 3.x, drops support for 2.6
68
+ * Saddle versions 0.1.x are compatible with Faraday versions ~> 0.9.0
69
+ * Saddle versions 0.0.x are compatible with Faraday versions ~> 0.8.7
70
+
71
+ ## Appraisal Usage
72
+
73
+ Appraisal is a gem that allows us to test our library against different versions of dependencies in repeatable scenarios called "appraisals". For more information see
74
+ the [Appraisal repository](https://github.com/thoughtbot/appraisal)
75
+
76
+ First make sure appraisal is installed by running
77
+
78
+ ```
79
+ $ bundle install
80
+ ```
81
+
82
+ To update the Appraisal's gemfiles run
83
+
84
+ ```
85
+ $ bundle exec appraisal generate
86
+ ```
87
+
88
+ To test against a specific version of `activesupport` first install the dependencies, ideally we would want to install them by running
89
+ ```
90
+ $ bundle exec appraisal install
91
+ ```
92
+
93
+ However, this isn't posible fot the different constraints these versions have. So instead install the dependencies for the desired version we want to test against by running
94
+
95
+ ```
96
+ $ BUNDLE_GEMFILE=gemfiles/activesupport_6.0.gemfiles bundle install
97
+ ```
98
+
99
+ In this example we want to install the dependencies of `activesupport` version `6.0`. Then to run `rspec` with that constraints we run
100
+
101
+ ```
102
+ $ BUNDLE_GEMFILE=gemfiles/activesupport_6.0.gemfiles bundle exec rspec
103
+ ```
104
+
65
105
  ## Code Status
66
106
 
67
- * [![Build Status](https://travis-ci.org/mLewisLogic/saddle.png?branch=master)](https://travis-ci.org/mLewisLogic/saddle)
68
107
  * [![Code Climate](https://codeclimate.com/github/mLewisLogic/saddle.png)](https://codeclimate.com/github/mLewisLogic/saddle)
69
- * [![Dependency Status](https://gemnasium.com/mLewisLogic/saddle.png)](https://gemnasium.com/mLewisLogic/saddle)
70
108
 
71
109
 
72
110
  ## License
@@ -19,7 +19,7 @@ module <%= root_module %>
19
19
  def call(env)
20
20
  begin
21
21
  @app.call(env)
22
- rescue Faraday::Error::ClientError => e
22
+ rescue Faraday::ClientError => e
23
23
  # This is our chance to reinterpret the response into a meaningful, client-specific
24
24
  # exception that a consuming service can handle
25
25
  exception = <%= root_module %>::GenericException
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 3.2.22"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 3.12"
10
+ gem "rspec-instafail", "~> 1"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 4.0.13"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 3.12"
10
+ gem "rspec-instafail", "~> 1"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 4.1.16"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 3.12"
10
+ gem "rspec-instafail", "~> 1"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 4.2.11"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 3.12"
10
+ gem "rspec-instafail", "~> 1"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 5.0.7"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 3.12"
10
+ gem "rspec-instafail", "~> 1"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 5.1.7"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 3.12"
10
+ gem "rspec-instafail", "~> 1"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 5.2.8"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 3.12"
10
+ gem "rspec-instafail", "~> 1"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 6.0.6"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 3.12"
10
+ gem "rspec-instafail", "~> 1"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 6.1.7"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 3.12"
10
+ gem "rspec-instafail", "~> 1"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -0,0 +1,20 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "~> 7.0.4"
6
+
7
+ group :test do
8
+ gem "rake"
9
+ gem "rspec", "~> 2.14.1"
10
+ gem "rspec-instafail", "~> 0.2"
11
+ gem "airbrake"
12
+ gem "simple_oauth", "~> 0.2.0"
13
+ gem "statsd-ruby", require: ["statsd"]
14
+ end
15
+
16
+ group :development, :test do
17
+ gem "pry"
18
+ end
19
+
20
+ gemspec path: "../"
@@ -17,18 +17,15 @@ module Saddle
17
17
  def initialize(requester, relative_path_override=nil, parent=nil)
18
18
  @requester = requester
19
19
  @parent = parent
20
- @relative_path = relative_path_override || _relative_path()
20
+ @relative_path = relative_path_override || _relative_path
21
21
  end
22
22
 
23
23
 
24
24
  # Generic request wrapper
25
25
  def request(method, action, params={}, options={})
26
26
  # Augment in interesting options
27
- options[:saddle] ||= {}
28
- options[:saddle] = {
29
- :call_chain => _path_array(),
30
- :action => action,
31
- }
27
+ options[:call_chain] = _path_array
28
+ options[:action] = action
32
29
  @requester.send(method, _path(action), params, options)
33
30
  end
34
31
 
@@ -87,7 +84,7 @@ module Saddle
87
84
  if defined?(self.class::ABSOLUTE_PATH)
88
85
  [self.class::ABSOLUTE_PATH]
89
86
  else
90
- _path_array()
87
+ _path_array
91
88
  end
92
89
  # Join it with the action
93
90
  paths = pre_action_paths + [action]
@@ -97,7 +94,7 @@ module Saddle
97
94
  end
98
95
 
99
96
  def _path_array
100
- _endpoint_chain().map(&:relative_path).compact
97
+ _endpoint_chain.map(&:relative_path).compact
101
98
  end
102
99
 
103
100
  # Get the parent chain that led to this endpoint
@@ -108,7 +105,7 @@ module Saddle
108
105
  chain << node
109
106
  node = node.parent
110
107
  end
111
- chain.reverse()
108
+ chain.reverse
112
109
  end
113
110
 
114
111
  # If the parent is not an endpoint, it is a root node
@@ -0,0 +1,15 @@
1
+ module Saddle
2
+ # Same as the standard Faraday::RackBuilder, but also allows passing saddle options to the env.
3
+ class RackBuilder < ::Faraday::RackBuilder
4
+ def saddle_options
5
+ @saddle_options ||= {}
6
+ end
7
+
8
+ def build_env(connection, request)
9
+ env = super
10
+ env[:saddle] = saddle_options.deep_merge(request.saddle_options)
11
+ env
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ # Allow saddle options to be accessible through Faraday::Request.
2
+ Faraday::Request.instance_eval do
3
+ attr_accessor :saddle_options
4
+ end
@@ -14,17 +14,17 @@ module Saddle
14
14
  TYPE_URLENCODED = 'application/x-www-form-urlencoded'.freeze
15
15
 
16
16
  def call(env)
17
- if env[:request][:client_options][:oauth1] &&
18
- env[:request][:client_options][:oauth1][:consumer_key] &&
19
- env[:request][:client_options][:oauth1][:consumer_secret] &&
20
- env[:request][:client_options][:oauth1][:token] &&
21
- env[:request][:client_options][:oauth1][:token_secret]
17
+ if env[:saddle][:client_options][:oauth1] &&
18
+ env[:saddle][:client_options][:oauth1][:consumer_key] &&
19
+ env[:saddle][:client_options][:oauth1][:consumer_secret] &&
20
+ env[:saddle][:client_options][:oauth1][:token] &&
21
+ env[:saddle][:client_options][:oauth1][:token_secret]
22
22
 
23
23
  env[:request_headers]['Authorization'] ||= SimpleOAuth::Header.new(
24
24
  env[:method],
25
25
  env[:url].to_s,
26
26
  filtered_body_params(env),
27
- env[:request][:client_options][:oauth1]
27
+ env[:saddle][:client_options][:oauth1]
28
28
  ).to_s
29
29
  end
30
30
 
@@ -16,10 +16,10 @@ module Saddle
16
16
  end
17
17
 
18
18
  def call(env)
19
- if env[:request][:client_options][@key_name.to_sym]
19
+ if env[:saddle][:client_options][@key_name.to_sym]
20
20
  new_query = []
21
21
  new_query << env[:url].query if env[:url].query
22
- new_query << "#{@key_name}=#{CGI.escape(env[:request][:client_options][@key_name.to_sym].to_s)}"
22
+ new_query << "#{@key_name}=#{CGI.escape(env[:saddle][:client_options][@key_name.to_sym].to_s)}"
23
23
  env[:url].query = new_query.join('&')
24
24
  end
25
25
 
@@ -9,8 +9,8 @@ module Saddle
9
9
 
10
10
  class ExtraEnv < Faraday::Middleware
11
11
  def call(env)
12
- if env[:request][:client_options][:extra_env]
13
- env.merge!(env[:request][:client_options][:extra_env])
12
+ if env[:saddle][:client_options][:extra_env]
13
+ env.merge!(env[:saddle][:client_options][:extra_env])
14
14
  end
15
15
 
16
16
  @app.call env
@@ -15,7 +15,7 @@ module Saddle
15
15
  @app.call(env)
16
16
  rescue => e
17
17
  if defined?(Rails.logger)
18
- Rails.logger.error("#{env[:request][:saddle][:client].name} error: #{e}")
18
+ Rails.logger.error("#{env[:saddle][:client].name} error: #{e}")
19
19
  end
20
20
  # Re-raise the error
21
21
  raise
@@ -33,16 +33,16 @@ module Saddle
33
33
 
34
34
  def call(env)
35
35
  # Try to build up a path for the STATSD logging
36
- if env[:request][:statsd_path]
37
- statsd_path = env[:request][:statsd_path]
38
- elsif env[:request][:saddle]
36
+ if env[:saddle][:statsd_path]
37
+ statsd_path = env[:saddle][:statsd_path]
38
+ elsif env[:saddle][:client]
39
39
  statsd_path_components = [
40
40
  'saddle',
41
- env[:request][:saddle][:client].name.underscore,
41
+ env[:saddle][:client].name.underscore,
42
42
  ]
43
- if env[:request][:saddle][:call_chain] && env[:request][:saddle][:action]
44
- statsd_path_components += env[:request][:saddle][:call_chain]
45
- statsd_path_components << env[:request][:saddle][:action]
43
+ if env[:saddle][:call_chain] && env[:saddle][:action]
44
+ statsd_path_components += env[:saddle][:call_chain]
45
+ statsd_path_components << env[:saddle][:action]
46
46
  else
47
47
  statsd_path_components << 'raw'
48
48
  statsd_path_components << "#{env[:url].host}#{env[:url].path}"
@@ -1,7 +1,5 @@
1
1
  require 'faraday'
2
2
 
3
-
4
-
5
3
  module Saddle
6
4
  module Middleware
7
5
  module Request
@@ -15,12 +13,8 @@ module Saddle
15
13
  CONTENT_TYPE = 'Content-Type'.freeze
16
14
  MIME_TYPE = 'application/json'.freeze
17
15
 
18
- dependency do
19
- require 'json' unless defined?(::JSON)
20
- end
21
-
22
16
  def call(env)
23
- if env[:request][:request_style] == :json
17
+ if env[:saddle][:request_style] == :json
24
18
  # Make sure we're working with a valid body that's not a String
25
19
  if env[:body] and !env[:body].respond_to?(:to_str)
26
20
  env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
@@ -10,8 +10,8 @@ module Saddle
10
10
 
11
11
  class PathPrefix < Faraday::Middleware
12
12
  def call(env)
13
- if env[:request][:client_options][:path_prefix]
14
- env[:url].path = "/#{env[:request][:client_options][:path_prefix]}#{env[:url].path}"
13
+ if env[:saddle][:client_options][:path_prefix]
14
+ env[:url].path = "/#{env[:saddle][:client_options][:path_prefix]}#{env[:url].path}"
15
15
  end
16
16
 
17
17
  @app.call env
@@ -17,13 +17,13 @@ module Saddle
17
17
  end
18
18
 
19
19
  def call(env)
20
- retries = env[:request][:num_retries] || 0
21
- backoff = env[:request][:retry_backoff] || 0.050 # in seconds
20
+ retries = env[:saddle][:num_retries] || 0
21
+ backoff = env[:saddle][:retry_backoff] || 0.050 # in seconds
22
22
  begin
23
23
  @app.call(self.class.deep_copy(env))
24
24
  rescue => e
25
25
  # Only retry for GET or if the request is marked as idempotent
26
- if env[:method] == :get || env[:request][:idempotent]
26
+ if env[:method] == :get || env[:saddle][:idempotent]
27
27
  unless @ignored_exceptions.include?(e.class)
28
28
  # Retry a limited number of times
29
29
  if retries > 0
@@ -40,7 +40,11 @@ module Saddle
40
40
  end
41
41
 
42
42
  def self.deep_copy(value)
43
- if value.is_a?(Hash)
43
+ if value.is_a?(Struct)
44
+ result = value.clone
45
+ value.each{|k, v| result.send("#{k}=", deep_copy(v))}
46
+ result
47
+ elsif value.is_a?(Hash)
44
48
  result = value.clone
45
49
  value.each{|k, v| result[k] = deep_copy(v)}
46
50
  result
@@ -24,7 +24,7 @@ module Saddle
24
24
 
25
25
 
26
26
  def call(env)
27
- if env[:request][:request_style] == :urlencoded
27
+ if env[:saddle][:request_style] == :urlencoded
28
28
  # Make sure we're working with a valid body that's not a String
29
29
  if env[:body] and !env[:body].respond_to?(:to_str)
30
30
  if has_multipart?(env[:body])
@@ -13,7 +13,7 @@ module Saddle
13
13
  user_agent = nil
14
14
  # Build a user agent that looks like 'SaddleExample 0.0.1'
15
15
  begin
16
- user_agent = client_name = env[:request][:saddle][:client].name
16
+ user_agent = client_name = env[:saddle][:client].name
17
17
  parent_module = client_name.split('::')[0..-2].join('::').constantize
18
18
  if parent_module
19
19
  if defined?(parent_module::VERSION)
@@ -13,7 +13,7 @@ module Saddle
13
13
  begin
14
14
  @app.call(env)
15
15
  rescue
16
- if res = env[:request][:default_response]
16
+ if res = env[:saddle][:default_response]
17
17
  return ::Faraday::Response.new(:body => res)
18
18
  else
19
19
  raise
@@ -1,7 +1,5 @@
1
1
  require 'faraday'
2
2
 
3
-
4
-
5
3
  module Saddle
6
4
  module Middleware
7
5
  module Response
@@ -12,10 +10,6 @@ module Saddle
12
10
  CONTENT_TYPE = 'Content-Type'.freeze
13
11
  MIME_TYPE = 'application/json'.freeze
14
12
 
15
- dependency do
16
- require 'json' unless defined?(::JSON)
17
- end
18
-
19
13
  def call(env)
20
14
  result = @app.call(env)
21
15
 
@@ -11,9 +11,9 @@ module Saddle
11
11
 
12
12
  case result.status
13
13
  when 404
14
- raise Faraday::Error::ResourceNotFound, response_values(result)
14
+ raise Faraday::ResourceNotFound, response_values(result)
15
15
  when 400...600
16
- raise Faraday::Error::ClientError, response_values(result)
16
+ raise Faraday::ClientError, response_values(result)
17
17
  end
18
18
 
19
19
  result
@@ -13,13 +13,13 @@ module Saddle
13
13
  class RubyTimeout < Faraday::Middleware
14
14
 
15
15
  def call(env)
16
- timeout = env[:request][:hard_timeout] # nil or 0 means no timeout
16
+ timeout = env[:saddle][:hard_timeout] # nil or 0 means no timeout
17
17
  Timeout.timeout(timeout, Saddle::TimeoutError) do
18
18
  @app.call(env)
19
19
  end
20
20
  # It is possible that faraday will catch the timeout first and throw
21
21
  # this exception, rethrow as a class derived from standard error.
22
- rescue Faraday::Error::TimeoutError
22
+ rescue Faraday::TimeoutError
23
23
  raise Saddle::TimeoutError
24
24
  end
25
25
 
@@ -1,8 +1,9 @@
1
1
  require 'active_support/core_ext/hash'
2
+ require 'active_support/notifications'
2
3
 
3
4
  require 'faraday'
4
- require 'faraday_middleware'
5
-
5
+ require 'saddle/faraday/request'
6
+ require 'saddle/faraday/rack_builder'
6
7
 
7
8
  require 'saddle/middleware/request/encode_json'
8
9
  require 'saddle/middleware/request/path_prefix'
@@ -79,7 +80,7 @@ module Saddle
79
80
  # Make a GET request
80
81
  def get(url, params={}, options={})
81
82
  response = connection.get do |req|
82
- req.options.deep_merge!(options)
83
+ req.saddle_options = options
83
84
  req.body = options[:body] if options.has_key?(:body)
84
85
  req.url(url, params)
85
86
  end
@@ -89,7 +90,7 @@ module Saddle
89
90
  # Make a POST request
90
91
  def post(url, data={}, options={})
91
92
  response = connection.post do |req|
92
- req.options.deep_merge!(options)
93
+ req.saddle_options = options
93
94
  req.url(url)
94
95
  req.body = data
95
96
  end
@@ -99,7 +100,7 @@ module Saddle
99
100
  # Make a PUT request
100
101
  def put(url, data={}, options={})
101
102
  response = connection.put do |req|
102
- req.options.deep_merge!(options)
103
+ req.saddle_options = options
103
104
  req.url(url)
104
105
  req.body = data
105
106
  end
@@ -109,7 +110,7 @@ module Saddle
109
110
  # Make a DELETE request
110
111
  def delete(url, params={}, options={})
111
112
  response = connection.delete do |req|
112
- req.options.deep_merge!(options)
113
+ req.saddle_options = options
113
114
  req.url(url, params)
114
115
  end
115
116
  handle_response(response)
@@ -131,61 +132,59 @@ module Saddle
131
132
 
132
133
  # Build a connection instance, wrapped in the middleware that we want
133
134
  def connection
134
- @connection ||= Faraday.new(base_url) do |builder|
135
+ @connection ||= Faraday.new(base_url, :builder_class => Saddle::RackBuilder) do |connection|
135
136
  # Include the requester level options
136
- builder.options[:client_options] = @options
137
+ connection.builder.saddle_options[:client_options] = @options
137
138
 
138
139
  # Config options
139
- builder.options[:timeout] = @timeout
140
- builder.options[:request_style] = @request_style
141
- builder.options[:num_retries] = @num_retries
142
- builder.options[:saddle] = {
143
- :client => @parent_client,
144
- }
140
+ connection.options[:timeout] = @timeout
141
+ connection.builder.saddle_options[:request_style] = @request_style
142
+ connection.builder.saddle_options[:num_retries] = @num_retries
143
+ connection.builder.saddle_options[:client] = @parent_client
145
144
 
146
145
  # Support default return values upon exception
147
- builder.use(Saddle::Middleware::Response::DefaultResponse)
146
+ connection.use(Saddle::Middleware::Response::DefaultResponse)
148
147
 
149
148
  # Hard timeout on the entire request
150
- builder.use(Saddle::Middleware::RubyTimeout)
149
+ connection.use(Saddle::Middleware::RubyTimeout)
151
150
 
152
151
  # Set up a user agent
153
- builder.use(Saddle::Middleware::Request::UserAgent)
152
+ connection.use(Saddle::Middleware::Request::UserAgent)
154
153
 
155
154
  # Set up the path prefix if needed
156
- builder.use(Saddle::Middleware::Request::PathPrefix)
155
+ connection.use(Saddle::Middleware::Request::PathPrefix)
157
156
 
158
157
  # Apply additional implementation-specific middlewares
159
158
  @additional_middlewares.each do |m|
160
- m[:args] ? builder.use(m[:klass], *m[:args]) : builder.use(m[:klass])
159
+ m[:args] ? connection.use(m[:klass], *m[:args]) : connection.use(m[:klass])
161
160
  end
162
161
 
163
162
  # Request encoding
164
- builder.use(Saddle::Middleware::Request::JsonEncoded)
165
- builder.use(Saddle::Middleware::Request::UrlEncoded)
163
+ connection.use(Saddle::Middleware::Request::JsonEncoded)
164
+ connection.use(Saddle::Middleware::Request::UrlEncoded)
166
165
 
167
166
  # Automatic retries
168
- builder.use(Saddle::Middleware::Request::Retry)
167
+ connection.use(Saddle::Middleware::Request::Retry)
169
168
 
170
169
  # Raise exceptions on 4xx and 5xx errors
171
- builder.use(Saddle::Middleware::Response::RaiseError)
170
+ connection.use(Saddle::Middleware::Response::RaiseError)
172
171
 
173
172
  # Handle parsing out the response if it's JSON
174
- builder.use(Saddle::Middleware::Response::ParseJson)
173
+ connection.use(Saddle::Middleware::Response::ParseJson)
175
174
 
176
175
  # Set up instrumentation around the adapter for extensibility
177
- builder.use(FaradayMiddleware::Instrumentation)
176
+ connection.request :instrumentation
178
177
 
179
178
  # Add in extra env data if needed
180
- builder.use(Saddle::Middleware::ExtraEnv)
179
+ connection.use(Saddle::Middleware::ExtraEnv)
181
180
 
182
181
  # Set up our adapter
183
182
  if @stubs.nil?
184
183
  # Use the default adapter
185
- builder.adapter(@http_adapter[:key], *@http_adapter[:args])
184
+ connection.adapter(@http_adapter[:key], *@http_adapter[:args])
186
185
  else
187
186
  # Use the test adapter
188
- builder.adapter(:test, @stubs)
187
+ connection.adapter(:test, @stubs)
189
188
  end
190
189
  end
191
190
  end
@@ -1,3 +1,3 @@
1
1
  module Saddle
2
- VERSION = '0.0.53'
2
+ VERSION = '0.2.0'
3
3
  end
data/saddle.gemspec CHANGED
@@ -21,13 +21,11 @@ Gem::Specification.new do |s|
21
21
  s.files = `git ls-files`.split($\)
22
22
  s.executables = ['saddle']
23
23
  s.test_files = s.files.grep(%r{^(spec)/})
24
-
25
- if RUBY_VERSION < '1.9'
26
- s.add_dependency 'activesupport', '~> 3.0'
27
- else
28
- s.add_dependency 'activesupport', '>= 3.0'
29
- end
30
24
 
31
- s.add_dependency 'faraday', '~> 0.8.7'
32
- s.add_dependency 'faraday_middleware', '~> 0.9.0'
25
+ s.required_ruby_version = '>= 2.6'
26
+
27
+ s.add_dependency 'activesupport', '>= 3.2'
28
+ s.add_dependency 'faraday', '~> 2.1'
29
+
30
+ s.add_development_dependency 'appraisal'
33
31
  end
@@ -4,11 +4,11 @@ describe Saddle::BaseEndpoint do
4
4
  let(:base_endpoint) { Saddle::BaseEndpoint.new(Saddle::Client.create) }
5
5
 
6
6
  it 'can define singleton methods' do
7
- expect(base_endpoint.respond_to?(:define_singleton_method)).to be_true
7
+ expect(base_endpoint.respond_to?(:define_singleton_method)).to be_truthy
8
8
  end
9
9
 
10
10
  it 'responds to any defined singleton methods' do
11
11
  base_endpoint.define_singleton_method(:my_method) { true }
12
- expect(base_endpoint.my_method).to be_true
12
+ expect(base_endpoint.my_method).to be_truthy
13
13
  end
14
14
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
 
4
- describe 'FaradayMiddleware::Instrumentation' do
4
+ describe 'Faraday::Instrumentation' do
5
5
 
6
6
  context "test integration of instrumentation middleware" do
7
7
 
@@ -72,7 +72,7 @@ describe Saddle::Client do
72
72
  }
73
73
  expect {
74
74
  @default_client.requester.post(url)
75
- }.to raise_error(Faraday::Error::ClientError)
75
+ }.to raise_error(Faraday::ClientError)
76
76
  end
77
77
 
78
78
  it "should retry if it is marked as idempotent" do
@@ -26,7 +26,7 @@ describe Saddle::Client do
26
26
  end
27
27
 
28
28
  it "should request properly with params in the body" do
29
- @stubs.send(:new_stub, :get, '/test', "body data") {
29
+ @stubs.send(:new_stub, :get, '/test', {}, "body data") {
30
30
  [
31
31
  200,
32
32
  {},
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saddle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.53
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Lewis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-13 00:00:00.000000000 Z
11
+ date: 2023-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ! '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.0'
19
+ version: '3.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ! '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '3.0'
26
+ version: '3.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: faraday
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.8.7
33
+ version: '2.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.8.7
40
+ version: '2.1'
41
41
  - !ruby/object:Gem::Dependency
42
- name: faraday_middleware
42
+ name: appraisal
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 0.9.0
48
- type: :runtime
47
+ version: '0'
48
+ type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 0.9.0
54
+ version: '0'
55
55
  description: Makes writing API clients as easy as giving high fives
56
56
  email: mike.lewis@airbnb.com
57
57
  executables:
@@ -59,9 +59,11 @@ executables:
59
59
  extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
- - .gitignore
63
- - .rspec
64
- - .travis.yml
62
+ - ".github/workflows/ci.yml"
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - ".travis.yml"
66
+ - Appraisals
65
67
  - CHANGELOG.md
66
68
  - Gemfile
67
69
  - LICENSE
@@ -83,10 +85,22 @@ files:
83
85
  - bin/template/spec/middleware/exception_raiser_spec.rb
84
86
  - bin/template/spec/spec_helper.rb
85
87
  - bin/template/spec/stub/stub_spec.rb
88
+ - gemfiles/activesupport_3.2.gemfile
89
+ - gemfiles/activesupport_4.0.gemfile
90
+ - gemfiles/activesupport_4.1.gemfile
91
+ - gemfiles/activesupport_4.2.gemfile
92
+ - gemfiles/activesupport_5.0.gemfile
93
+ - gemfiles/activesupport_5.1.gemfile
94
+ - gemfiles/activesupport_5.2.gemfile
95
+ - gemfiles/activesupport_6.0.gemfile
96
+ - gemfiles/activesupport_6.1.gemfile
97
+ - gemfiles/activesupport_7.0.gemfile
86
98
  - lib/saddle.rb
87
99
  - lib/saddle/client_attributes.rb
88
100
  - lib/saddle/endpoint.rb
89
101
  - lib/saddle/errors.rb
102
+ - lib/saddle/faraday/rack_builder.rb
103
+ - lib/saddle/faraday/request.rb
90
104
  - lib/saddle/method_tree_builder.rb
91
105
  - lib/saddle/middleware/authentication/oauth1.rb
92
106
  - lib/saddle/middleware/authentication/oauth2.rb
@@ -130,17 +144,16 @@ require_paths:
130
144
  - lib
131
145
  required_ruby_version: !ruby/object:Gem::Requirement
132
146
  requirements:
133
- - - ! '>='
147
+ - - ">="
134
148
  - !ruby/object:Gem::Version
135
- version: '0'
149
+ version: '2.6'
136
150
  required_rubygems_version: !ruby/object:Gem::Requirement
137
151
  requirements:
138
- - - ! '>='
152
+ - - ">="
139
153
  - !ruby/object:Gem::Version
140
154
  version: '0'
141
155
  requirements: []
142
- rubyforge_project:
143
- rubygems_version: 2.2.2
156
+ rubygems_version: 3.0.3.1
144
157
  signing_key:
145
158
  specification_version: 4
146
159
  summary: A full-featured, generic consumer layer for you to build API client implementations