spyke 5.3.1 → 5.4.1

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,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a8f605cd12c22641c85ffdaf643cead8ef8eab997e347075596a7b7c9149e0c
4
- data.tar.gz: 97caf4cac49eb5e66164193845e5a5bb60069cc910f349de38eaf01e0d7fd57c
3
+ metadata.gz: 46c56a1975e770acc9b1e9d40abdfbfd7d59b15705da333d293d0ecb18678628
4
+ data.tar.gz: bbc4a65e7cc6293ce9e93410eae69dd4003ede73364207c17bff79c1736770a2
5
5
  SHA512:
6
- metadata.gz: 1afad1b576ca01dd62b642da238ad80f2048da50a73ca387ed8df541a005601ba55a2c4769c881e991f79d40adbfa0992377989881dc49ce12c58174265ffd36
7
- data.tar.gz: 6e99ad81b53c136acadb85bc5363510067cb7704bbdc74a8ad1c84c0b79ff0079ac5029e5aa6aa65b74e24446068d01e568fb4258080bdf4202ccb4c75303be9
6
+ metadata.gz: 6e741d1302b7a404d2f052329814b74af2aab61f17a5edff94b06f1bb5fadf78a8bbb43c93dbd2ed4a48064721dad8e57a28d53fde35b5d14f7a44f19fe01a31
7
+ data.tar.gz: 9a7cbdf9fd0b504c9772dd5388ff949b1ab5abe666277e11efc8e347e3aae22e5337cba0b506388f90f9cc2b68f5ddb97bf4dd8b08b50694a43e1f2d99c32a9a
data/.travis.yml CHANGED
@@ -1,6 +1,5 @@
1
1
  notifications:
2
2
  email: false
3
3
  rvm:
4
- - 2.3.1
5
- - 2.5.1
4
+ - 2.6.6
6
5
  sudo: false
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Spyke
2
2
 
3
3
  <p align="center">
4
- <img src="http://upload.wikimedia.org/wikipedia/en/thumb/2/21/Spyke.jpg/392px-Spyke.jpg" width="20%" />
4
+ <img src="http://upload.wikimedia.org/wikipedia/en/thumb/2/21/Spyke.jpg/392px-Spyke.jpg" width="15%" />
5
5
  <br/>
6
6
  Interact with remote <strong>REST services</strong> in an <strong>ActiveRecord-like</strong> manner.
7
7
  <br /><br />
@@ -30,6 +30,7 @@ Add this line to your application's Gemfile:
30
30
 
31
31
  ```ruby
32
32
  gem 'spyke'
33
+ gem 'multi_json' # or whatever is needed to parse responses
33
34
  ```
34
35
 
35
36
  Spyke uses Faraday to handle requests and expects it to parse the response body into a hash in the following format:
@@ -152,6 +153,19 @@ Post.request(:post, 'posts/3/log', time: '12:00')
152
153
  # => POST http://api.com/posts/3/log - { time: '12:00' }
153
154
  ```
154
155
 
156
+ ### Custom primary keys
157
+
158
+ Custom primary keys can be defined with `self.primary_key = :custom_key`:
159
+
160
+ ```ruby
161
+ class User < Spyke::Base
162
+ self.primary_key = :user_id
163
+
164
+ # When using custom URIs the :id parameter also has to be adjusted
165
+ uri 'people(/:user_id)'
166
+ end
167
+ ```
168
+
155
169
  ### API-side validations
156
170
 
157
171
  Spyke expects errors to be formatted in the same way as the
@@ -6,7 +6,6 @@ module Spyke
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  included do
9
- attr_reader :attributes
10
9
  delegate :[], :[]=, to: :attributes
11
10
  end
12
11
 
@@ -40,11 +39,19 @@ module Spyke
40
39
  yield self if block_given?
41
40
  end
42
41
 
42
+ def attributes
43
+ @spyke_attributes
44
+ end
45
+
43
46
  def attributes=(new_attributes)
44
- @attributes ||= Attributes.new(scope.params)
47
+ @spyke_attributes ||= Attributes.new(scope.params)
45
48
  use_setters(new_attributes) if new_attributes
46
49
  end
47
50
 
51
+ def id?
52
+ id.present?
53
+ end
54
+
48
55
  def id
49
56
  attributes[primary_key]
50
57
  end
@@ -76,7 +83,7 @@ module Spyke
76
83
  # Set id attribute directly if using a custom primary key alongside an attribute named "id" to avoid clobbering
77
84
  set_attribute :id, attributes.delete(:id) if conflicting_ids?(attributes)
78
85
 
79
- attributes.each do |key, value|
86
+ attributes.to_h.each do |key, value|
80
87
  send "#{key}=", value
81
88
  end
82
89
  end
data/lib/spyke/http.rb CHANGED
@@ -41,20 +41,20 @@ module Spyke
41
41
  @uri ||= uri_template || default_uri
42
42
  end
43
43
 
44
- private
45
-
46
- def send_request(method, path, params)
47
- connection.send(method) do |request|
48
- if method == :get
49
- request.url path.to_s, params
50
- else
51
- request.url path.to_s
52
- request.body = params
53
- end
44
+ def send_request(method, path, params)
45
+ connection.send(method) do |request|
46
+ if method == :get
47
+ request.url path.to_s, params
48
+ else
49
+ request.url path.to_s
50
+ request.body = params
54
51
  end
55
- rescue Faraday::ConnectionFailed, Faraday::TimeoutError
56
- raise ConnectionError
57
52
  end
53
+ rescue Faraday::ConnectionFailed, Faraday::TimeoutError
54
+ raise ConnectionError
55
+ end
56
+
57
+ private
58
58
 
59
59
  def scoped_request(method)
60
60
  uri = new.uri
data/lib/spyke/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Spyke
2
- VERSION = '5.3.1'
2
+ VERSION = '5.4.1'
3
3
  end
data/spyke.gemspec CHANGED
@@ -18,12 +18,13 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency 'activesupport', '>= 4.0.0', '< 6.0'
22
- spec.add_dependency 'activemodel', '>= 4.0.0', '< 6.0'
21
+ spec.add_dependency 'activesupport', '>= 4.0.0'
22
+ spec.add_dependency 'activemodel', '>= 4.0.0'
23
23
  spec.add_dependency 'faraday', '>= 0.9.0', '< 2.0'
24
24
  spec.add_dependency 'faraday_middleware', '>= 0.9.1', '< 2.0'
25
25
  spec.add_dependency 'addressable', '>= 2.5.2'
26
26
 
27
+ spec.add_development_dependency 'actionpack', '>= 4.0.0'
27
28
  spec.add_development_dependency 'bundler', '~> 1.6'
28
29
  spec.add_development_dependency 'coveralls', '~> 0.7'
29
30
  spec.add_development_dependency 'minitest'
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ module Spyke
4
+ class ActiveModelDirtyTest < MiniTest::Test
5
+ def test_attributes_instance_var_compatibility
6
+ recipe = RecipeWithDirty.new(title: 'Cheeseburger')
7
+
8
+ # If @attributes is set on recipe ActiveModel::Dirty will crash
9
+ assert_equal false, recipe.attribute_changed_in_place?(:title)
10
+ end
11
+ end
12
+ end
@@ -301,6 +301,22 @@ module Spyke
301
301
  assert_equal %w{ starter sauce }, recipe.groups.map(&:title)
302
302
  end
303
303
 
304
+ def test_nested_attributes_has_one_using_strong_params
305
+ recipe = Recipe.new(image_attributes: strong_params(file: 'bob.jpg').permit!)
306
+ assert_equal 'bob.jpg', recipe.image.file
307
+ end
308
+
309
+ def test_nested_attributes_belongs_to_using_strong_params
310
+ recipe = Recipe.new(user_attributes: strong_params({ name: 'Bob' }).permit!)
311
+ assert_equal 'Bob', recipe.user.name
312
+ end
313
+
314
+ def test_nested_attributes_has_many_using_strong_params
315
+ params = strong_params(groups_attributes: [strong_params(title: 'starter').permit!, strong_params(title: 'sauce').permit!]).permit!
316
+ recipe = Recipe.new(params)
317
+ assert_equal %w{ starter sauce }, recipe.groups.map(&:title)
318
+ end
319
+
304
320
  def test_nested_attributes_replacing_existing_when_no_ids_present
305
321
  recipe = Recipe.new(groups_attributes: [{ title: 'starter' }, { title: 'sauce' }])
306
322
  recipe.attributes = { groups_attributes: [{ title: 'flavor' }] }
@@ -325,6 +341,17 @@ module Spyke
325
341
  assert_equal %w{ starter sauce }, recipe.groups.map(&:title)
326
342
  end
327
343
 
344
+ def test_nested_attributes_has_many_using_strong_params_with_hash_syntax
345
+ params = strong_params(
346
+ groups_attributes: strong_params(
347
+ '0' => strong_params(title: 'starter').permit!,
348
+ '1' => strong_params(title: 'sauce').permit!,
349
+ ).permit!
350
+ ).permit!
351
+ recipe = Recipe.new(params)
352
+ assert_equal %w{ starter sauce }, recipe.groups.map(&:title)
353
+ end
354
+
328
355
  def test_deeply_nested_attributes_has_many_using_array_syntax
329
356
  params = { groups_attributes: [{ id: 1, ingredients_attributes: [{ id: 1, name: 'Salt' }, { id: 2, name: 'Pepper' } ]}] }
330
357
  recipe = Recipe.new(params)
@@ -357,6 +384,40 @@ module Spyke
357
384
  assert_equal %w{ Salt Pepper }, recipe.ingredients.map(&:name)
358
385
  end
359
386
 
387
+ def test_deeply_nested_attributes_has_many_using_strong_params_with_array_syntax
388
+ params = strong_params(
389
+ groups_attributes: [
390
+ strong_params(
391
+ ingredients_attributes: [
392
+ strong_params(id: '', name: 'Salt').permit!,
393
+ strong_params(id: '', name: 'Pepper').permit!,
394
+ ]
395
+ ).permit!
396
+ ]
397
+ ).permit!
398
+ recipe = Recipe.new(params)
399
+ assert_equal %w{ Salt Pepper }, recipe.ingredients.map(&:name)
400
+ recipe.attributes = params
401
+ assert_equal %w{ Salt Pepper }, recipe.ingredients.map(&:name)
402
+ end
403
+
404
+ def test_deeply_nested_attributes_has_many_using_strong_params_with_hash_syntax
405
+ params = strong_params(
406
+ groups_attributes: strong_params(
407
+ '0' => strong_params(
408
+ ingredients_attributes: strong_params(
409
+ '0' => strong_params(id: '', name: 'Salt').permit!,
410
+ '1' => strong_params(id: '', name: 'Pepper').permit!,
411
+ ).permit!
412
+ ).permit!
413
+ ).permit!
414
+ ).permit!
415
+ recipe = Recipe.new(params)
416
+ assert_equal %w{ Salt Pepper }, recipe.ingredients.map(&:name)
417
+ recipe.attributes = params
418
+ assert_equal %w{ Salt Pepper }, recipe.ingredients.map(&:name)
419
+ end
420
+
360
421
  def test_reflect_on_association
361
422
  assert_equal Group, Recipe.reflect_on_association(:group).klass
362
423
  assert_equal Cookbook::Like, Cookbook::Tip.reflect_on_association(:like).klass
@@ -11,6 +11,18 @@ module Spyke
11
11
  assert_equal 'Tasty', recipe.description
12
12
  end
13
13
 
14
+ def test_initializing_using_permitted_strong_params
15
+ ingredient = Ingredient.new(strong_params(name: 'Flour').permit!)
16
+
17
+ assert_equal 'Flour', ingredient.name
18
+ end
19
+
20
+ def test_initializing_using_unpermitted_strong_params
21
+ assert_raises ActionController::UnfilteredParameters do
22
+ Ingredient.new(strong_params(name: 'Flour'))
23
+ end
24
+ end
25
+
14
26
  def test_to_params
15
27
  attr = Attributes.new(id: 3, 'title' => 'Fish', groups: [ Group.new(name: 'Starter'), { name: 'Dessert' } ])
16
28
  assert_equal({ 'id' => 3 , 'title' => 'Fish', 'groups' => [{ 'name' => 'Starter' }, { 'name' => 'Dessert' }] }, attr.to_params)
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ module Spyke
4
+ class ConfigConnectionWarnTest < MiniTest::Test
5
+ def test_config_connection_warn
6
+ assert_output '', "[DEPRECATION] `Spyke::Config.connection=` is deprecated. Please use `Spyke::Base.connection=` instead.\n" do
7
+ Spyke::Config.connection = Spyke::Base.connection
8
+ end
9
+ end
10
+ end
11
+ end
@@ -63,9 +63,16 @@ module Spyke
63
63
  end
64
64
 
65
65
  def test_multiple_apis
66
- endpoint = stub_request(:get, 'http://sashimi.com/other_recipes')
66
+ endpoint = stub_request(:get, 'http://sashimi.com/recipes')
67
67
  OtherRecipe.all.to_a
68
68
  assert_requested endpoint
69
69
  end
70
+
71
+ def test_multiple_apis_with_custom_fallback
72
+ fallback_endpoint = stub_request(:get, 'http://sushi.com/recipes')
73
+ primary_endpoint = stub_request(:get, 'http://sashimi.com/recipes').to_timeout
74
+ OtherRecipe.all.to_a
75
+ assert_requested fallback_endpoint
76
+ end
70
77
  end
71
78
  end
data/test/orm_test.rb CHANGED
@@ -54,6 +54,22 @@ module Spyke
54
54
  assert_requested endpoint
55
55
  end
56
56
 
57
+ def test_save_hash_attribute
58
+ endpoint = stub_request(:post, 'http://sushi.com/recipes').with(body: { recipe: { meta: { foo: 'bar' } } })
59
+
60
+ Recipe.create(meta: { foo: 'bar' })
61
+
62
+ assert_requested endpoint
63
+ end
64
+
65
+ def test_save_hash_attribute_with_strong_params
66
+ endpoint = stub_request(:post, 'http://sushi.com/recipes').with(body: { recipe: { meta: { foo: 'bar' } } })
67
+
68
+ Recipe.create(strong_params(meta: { foo: 'bar' }).permit!)
69
+
70
+ assert_requested endpoint
71
+ end
72
+
57
73
  def test_update_attributes
58
74
  endpoint = stub_request(:put, 'http://sushi.com/recipes/1').with(body: { recipe: { title: 'Sushi' } }).to_return_json(result: { id: 1, title: 'Sushi (saved)' })
59
75
 
@@ -206,5 +222,13 @@ module Spyke
206
222
  assert_equal 1, user[:uuid]
207
223
  assert_equal 42, user[:id]
208
224
  end
225
+
226
+ def test_custom_primary_key_used_for_persistence_check
227
+ user = User.new
228
+ refute user.persisted?
229
+
230
+ user.uuid = 1
231
+ assert user.persisted?
232
+ end
209
233
  end
210
234
  end
@@ -116,7 +116,15 @@ class OtherApi < Spyke::Base
116
116
  end
117
117
  end
118
118
 
119
- class OtherRecipe < OtherApi; end
119
+ class OtherRecipe < OtherApi
120
+ uri 'recipes/(:id)'
121
+
122
+ def self.send_request(method, path, params)
123
+ super
124
+ rescue Spyke::ConnectionError
125
+ Recipe.send_request(method, path, params)
126
+ end
127
+ end
120
128
 
121
129
  class Search
122
130
  def initialize(query)
@@ -152,3 +160,10 @@ module Cookbook
152
160
  include_root_in_json :foto
153
161
  end
154
162
  end
163
+
164
+ class RecipeWithDirty < Recipe
165
+ # NOTE: Simply including ActiveModel::Dirty doesn't provide all the dirty
166
+ # functionality. This is left intentionally incomplete as it's all we need
167
+ # for testing compatibility.
168
+ include ActiveModel::Dirty
169
+ end
data/test/test_helper.rb CHANGED
@@ -9,7 +9,7 @@ end
9
9
  require 'spyke'
10
10
  require 'minitest/autorun'
11
11
  require 'minitest/reporters'
12
- require 'mocha/mini_test'
12
+ require 'mocha/minitest'
13
13
  require 'multi_json'
14
14
  require 'pry'
15
15
 
@@ -18,3 +18,10 @@ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f }
18
18
 
19
19
  # Pretty colors
20
20
  Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
21
+
22
+ # For testing strong params
23
+ require 'action_controller/metal/strong_parameters'
24
+
25
+ def strong_params(params)
26
+ ActionController::Parameters.new(params)
27
+ 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: 5.3.1
4
+ version: 5.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jens Balvig
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-07 00:00:00.000000000 Z
11
+ date: 2021-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -17,9 +17,6 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 4.0.0
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '6.0'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
@@ -27,9 +24,6 @@ dependencies:
27
24
  - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: 4.0.0
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '6.0'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: activemodel
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -37,9 +31,6 @@ dependencies:
37
31
  - - ">="
38
32
  - !ruby/object:Gem::Version
39
33
  version: 4.0.0
40
- - - "<"
41
- - !ruby/object:Gem::Version
42
- version: '6.0'
43
34
  type: :runtime
44
35
  prerelease: false
45
36
  version_requirements: !ruby/object:Gem::Requirement
@@ -47,9 +38,6 @@ dependencies:
47
38
  - - ">="
48
39
  - !ruby/object:Gem::Version
49
40
  version: 4.0.0
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: '6.0'
53
41
  - !ruby/object:Gem::Dependency
54
42
  name: faraday
55
43
  requirement: !ruby/object:Gem::Requirement
@@ -104,6 +92,20 @@ dependencies:
104
92
  - - ">="
105
93
  - !ruby/object:Gem::Version
106
94
  version: 2.5.2
95
+ - !ruby/object:Gem::Dependency
96
+ name: actionpack
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: 4.0.0
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: 4.0.0
107
109
  - !ruby/object:Gem::Dependency
108
110
  name: bundler
109
111
  requirement: !ruby/object:Gem::Requirement
@@ -257,7 +259,6 @@ files:
257
259
  - LICENSE.txt
258
260
  - README.md
259
261
  - Rakefile
260
- - circle.yml
261
262
  - lib/spyke.rb
262
263
  - lib/spyke/associations.rb
263
264
  - lib/spyke/associations/association.rb
@@ -285,9 +286,11 @@ files:
285
286
  - lib/spyke/scoping.rb
286
287
  - lib/spyke/version.rb
287
288
  - spyke.gemspec
289
+ - test/activemodel_dirty_test.rb
288
290
  - test/associations_test.rb
289
291
  - test/attributes_test.rb
290
292
  - test/callbacks_test.rb
293
+ - test/config_test.rb
291
294
  - test/custom_request_test.rb
292
295
  - test/fallbacks_test.rb
293
296
  - test/orm_test.rb
@@ -300,7 +303,7 @@ homepage: https://github.com/balvig/spyke
300
303
  licenses:
301
304
  - MIT
302
305
  metadata: {}
303
- post_install_message:
306
+ post_install_message:
304
307
  rdoc_options: []
305
308
  require_paths:
306
309
  - lib
@@ -315,15 +318,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
315
318
  - !ruby/object:Gem::Version
316
319
  version: '0'
317
320
  requirements: []
318
- rubyforge_project:
319
- rubygems_version: 2.7.6
320
- signing_key:
321
+ rubygems_version: 3.0.3
322
+ signing_key:
321
323
  specification_version: 4
322
324
  summary: Interact with REST services in an ActiveRecord-like manner
323
325
  test_files:
326
+ - test/activemodel_dirty_test.rb
324
327
  - test/associations_test.rb
325
328
  - test/attributes_test.rb
326
329
  - test/callbacks_test.rb
330
+ - test/config_test.rb
327
331
  - test/custom_request_test.rb
328
332
  - test/fallbacks_test.rb
329
333
  - test/orm_test.rb
data/circle.yml DELETED
@@ -1,3 +0,0 @@
1
- machine:
2
- ruby:
3
- version: 2.2.2