spyke 4.1.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 25dd79a32574d3585c1f3823b1306458bc1b389b
4
- data.tar.gz: a644d3fba35342f673d257bea9e1ce2f1f324ca0
3
+ metadata.gz: 2a430604d1097764cd8add4c5b0f44161e5939d4
4
+ data.tar.gz: af8c8efb25d69ee8555510408edc393b5f8d1e5d
5
5
  SHA512:
6
- metadata.gz: a796e6db458d43dc92511cbc877493fa43a7280ced8d843f4150bf3fabb3f598fd433f949fc310c34489e709d02f94564e8fe52d34f6f7e07912ab77595c4a4f
7
- data.tar.gz: a6fe1f3e863c4aa305cff5b4cde884e9666c0ea0bbf90c3a4f103d220a9f42114af1061bae3fcf20ba956a2f301a648a06d04af6a3d3894c8c3cd5312046abd3
6
+ metadata.gz: 805690aac305cad08aeb0d8f34a63ca17aab8296080d42c51cb9f23117679592c3e8e1addf867595e2d1f82e19ad7607a06b1e2b6c8adf99b7dd4c2a3625d551
7
+ data.tar.gz: 8337033aea0abef30be2ce84d83e80c947ee643eb3a0214fb6637f8a1404b36c5f1f67c7d02e06b0429aa027010d737aa8a705f9bf92c6cc87d6a199b886892b
data/README.md CHANGED
@@ -167,6 +167,24 @@ remap it in Faraday to match the above. Doing this will allow you to
167
167
  show errors returned from the server in forms and f.ex using
168
168
  `@post.errors.full_messages` just like ActiveRecord.
169
169
 
170
+ ### Error handling and fallbacks
171
+
172
+ Should the API fail to connect or time out, a `Spyke::ConnectionError` will be raised.
173
+ If you need to recover gracefully from connection problems, you can
174
+ either rescue that exception or use the `with_fallback` feature:
175
+
176
+ ```ruby
177
+ # API is down
178
+ Article.all # => Spyke::ConnectionError
179
+ Article.with_fallback.all # => []
180
+
181
+ Article.find(1) # => Spyke::ConnectionError
182
+ Article.with_fallback.find(1) # => nil
183
+
184
+ article = Article.with_fallback(Article.new(title: "Dummy")).find(1)
185
+ article.title # => "Dummy"
186
+ ```
187
+
170
188
  ### Attributes-wrapping
171
189
 
172
190
  Spyke, like Rails, by default wraps sent attributes in a root element,
data/circle.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  machine:
2
2
  ruby:
3
- version: 2.1.5
3
+ version: 2.2.2
@@ -1,3 +1,4 @@
1
1
  module Spyke
2
2
  class ResourceNotFound < StandardError; end
3
+ class ConnectionError < StandardError; end
3
4
  end
data/lib/spyke/http.rb CHANGED
@@ -22,14 +22,7 @@ module Spyke
22
22
 
23
23
  def request(method, path, params = {})
24
24
  ActiveSupport::Notifications.instrument('request.spyke', method: method) do |payload|
25
- response = connection.send(method) do |request|
26
- if method == :get
27
- request.url path.to_s, params
28
- else
29
- request.url path.to_s
30
- request.body = params
31
- end
32
- end
25
+ response = send_request(method, path, params)
33
26
  payload[:url], payload[:status] = response.env.url, response.status
34
27
  Result.new_from_response(response)
35
28
  end
@@ -49,6 +42,19 @@ module Spyke
49
42
 
50
43
  private
51
44
 
45
+ def send_request(method, path, params)
46
+ connection.send(method) do |request|
47
+ if method == :get
48
+ request.url path.to_s, params
49
+ else
50
+ request.url path.to_s
51
+ request.body = params
52
+ end
53
+ end
54
+ rescue Faraday::ConnectionFailed, Faraday::TimeoutError
55
+ raise ConnectionError
56
+ end
57
+
52
58
  def scoped_request(method)
53
59
  uri = new.uri
54
60
  params = current_scope.params.except(*uri.variables)
@@ -9,7 +9,10 @@ module Spyke
9
9
  delegate :to_ary, :[], :any?, :empty?, :last, :size, :metadata, to: :find_some
10
10
 
11
11
  def initialize(klass, options = {})
12
- @klass, @options, @params = klass, options, {}
12
+ @klass = klass
13
+ @options = options
14
+ @params = {}
15
+ @should_fallback = false
13
16
  end
14
17
 
15
18
  def where(conditions = {})
@@ -27,6 +30,12 @@ module Spyke
27
30
  where
28
31
  end
29
32
 
33
+ def with_fallback(fallback = nil)
34
+ @should_fallback = true
35
+ @fallback = fallback
36
+ where
37
+ end
38
+
30
39
  # Overrides Enumerable find
31
40
  def find(id)
32
41
  scoping { klass.find(id) }
@@ -34,10 +43,14 @@ module Spyke
34
43
 
35
44
  def find_one
36
45
  @find_one ||= klass.new_instance_from_result(fetch)
46
+ rescue ConnectionError => error
47
+ fallback_or_reraise(error, default: nil)
37
48
  end
38
49
 
39
50
  def find_some
40
51
  @find_some ||= klass.new_collection_from_result(fetch)
52
+ rescue ConnectionError => error
53
+ fallback_or_reraise(error, default: [])
41
54
  end
42
55
 
43
56
  def each(&block)
@@ -65,5 +78,17 @@ module Spyke
65
78
  ensure
66
79
  klass.current_scope = previous
67
80
  end
81
+
82
+ def fallback_or_reraise(error, default:)
83
+ if should_fallback?
84
+ @fallback || default
85
+ else
86
+ raise error
87
+ end
88
+ end
89
+
90
+ def should_fallback?
91
+ @should_fallback
92
+ end
68
93
  end
69
94
  end
data/lib/spyke/scoping.rb CHANGED
@@ -7,7 +7,7 @@ module Spyke
7
7
 
8
8
  module ClassMethods
9
9
  delegate :where, :build, :any?, :empty?, to: :all
10
- delegate :with, to: :all
10
+ delegate :with, :with_fallback, to: :all
11
11
 
12
12
  def all
13
13
  current_scope || Relation.new(self, uri: uri)
data/lib/spyke/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Spyke
2
- VERSION = '4.1.1'
2
+ VERSION = '5.0.0'
3
3
  end
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+
3
+ module Spyke
4
+ class FallbacksTest < MiniTest::Test
5
+ def setup
6
+ stub_request(:get, "http://sushi.com/recipes/1").to_timeout
7
+ stub_request(:get, "http://sushi.com/recipes?published=true").to_timeout
8
+ end
9
+
10
+ def test_find_with_default_fallback
11
+ assert_raises ResourceNotFound do
12
+ Recipe.with_fallback.find(1)
13
+ end
14
+ end
15
+
16
+ def test_find_with_custom_fallback
17
+ dummy_recipe = Recipe.new(title: "Dummy Recipe")
18
+
19
+ result = Recipe.with_fallback(dummy_recipe).find(1)
20
+
21
+ assert_equal "Dummy Recipe", result.title
22
+ end
23
+
24
+ def test_find_one_with_default_fallback
25
+ recipe = Recipe.with_fallback.where(id: 1).find_one
26
+
27
+ assert_equal nil, recipe
28
+ end
29
+
30
+ def test_find_some_with_default_fallback
31
+ assert_equal [], Recipe.where(published: true).with_fallback.all.to_a
32
+ end
33
+
34
+ def test_find_some_with_custom_fallback
35
+ dummy_result = [Recipe.new(title: "Dummy Recipe")]
36
+
37
+ result = Recipe.where(published: true).with_fallback(dummy_result).all
38
+
39
+ assert_equal "Dummy Recipe", result.first.title
40
+ end
41
+ end
42
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spyke
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jens Balvig
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-12 00:00:00.000000000 Z
11
+ date: 2017-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -293,6 +293,7 @@ files:
293
293
  - test/attributes_test.rb
294
294
  - test/callbacks_test.rb
295
295
  - test/custom_request_test.rb
296
+ - test/fallbacks_test.rb
296
297
  - test/orm_test.rb
297
298
  - test/path_test.rb
298
299
  - test/scopes_test.rb
@@ -319,7 +320,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
319
320
  version: '0'
320
321
  requirements: []
321
322
  rubyforge_project:
322
- rubygems_version: 2.5.1
323
+ rubygems_version: 2.5.2
323
324
  signing_key:
324
325
  specification_version: 4
325
326
  summary: Interact with REST services in an ActiveRecord-like manner
@@ -328,6 +329,7 @@ test_files:
328
329
  - test/attributes_test.rb
329
330
  - test/callbacks_test.rb
330
331
  - test/custom_request_test.rb
332
+ - test/fallbacks_test.rb
331
333
  - test/orm_test.rb
332
334
  - test/path_test.rb
333
335
  - test/scopes_test.rb