grape-active_model_serializers 1.5.0 → 1.5.1

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: e8ff356c3449ed21a7317fa1aba4f2166bd37f08
4
- data.tar.gz: d5d8c18b882b728fa2dc80ef8fc117f50514cfcf
3
+ metadata.gz: b3e93ead8a09d258d62697918cb9f2c02b928bcd
4
+ data.tar.gz: 3674a40549e956720723447f751b8a9dea4f2158
5
5
  SHA512:
6
- metadata.gz: 1d759b25c58f6f4f822268643888949e4a499361c987ff2900b535ec59af5ca9926701cf87ade34f7346dca4a664c97836d08aabb6e704d022bb72dfb81bdca2
7
- data.tar.gz: bcf1bebecde31d684cc11d7ae200caf6b9ff1ec254f328292f882162ac3c909efc03caace67a20925174fdd2d9aa1b6f89657bb76fd6e5a24d6f4164b98841b6
6
+ metadata.gz: b735ccb020ec984ab176a277b0864373923234f0927c87c4b434decf633b8b17281e865753b2b43289524aa65f1db8495f0c3e16155e89f1d84a42957d6e4acd
7
+ data.tar.gz: a152d5e8e472f71b2dd316bf10815502a13f1fc250c2cffa1a999a2a377ca0e3f0053fe74103120118f3f4c9880d33110c2878a664c81c382d176fbe926e3834
@@ -4,6 +4,9 @@ sudo: false
4
4
 
5
5
  matrix:
6
6
  include:
7
+ - rvm: 2.3.1
8
+ script:
9
+ - bundle exec danger
7
10
  - rvm: 2.3.1
8
11
  env: GRAPE_VERSION=0.8.0
9
12
  - rvm: 2.3.1
@@ -1,8 +1,15 @@
1
1
  ## Changelog
2
2
 
3
- ### 1.5.1 (Next)
3
+ ### 1.5.2 (Next)
4
4
 
5
- * ...
5
+ * Your contribution here.
6
+
7
+ ### 1.5.1 (April 25, 2017)
8
+
9
+ * [#74](https://github.com/ruby-grape/grape-active_model_serializers/pull/74): Add support for Sequel - [@drn](https://github.com/drn).
10
+ * [#73](https://github.com/ruby-grape/grape-active_model_serializers/pull/73): Ensure all AMS options are passed through - [@drn](https://github.com/drn).
11
+ * [#65](https://github.com/ruby-grape/grape-active_model_serializers/pull/65): Added Danger, PR linter - [@dblock](https://github.com/dblock).
12
+ * [#63](https://github.com/ruby-grape/grape-active_model_serializers/pull/63): Pass adapter options through render - [@drn](https://github.com/drn).
6
13
 
7
14
  ### 1.5.0 (August 24, 2016)
8
15
 
@@ -0,0 +1 @@
1
+ danger.import_dangerfile(gem: 'ruby-grape-danger')
data/Gemfile CHANGED
@@ -8,3 +8,9 @@ when 'HEAD'
8
8
  else
9
9
  gem 'grape', version
10
10
  end
11
+
12
+ group :test do
13
+ gem 'sqlite3'
14
+ gem 'sequel', '~> 4.37', require: false
15
+ gem 'ruby-grape-danger', '~> 0.1.0', require: false
16
+ end
data/README.md CHANGED
@@ -150,10 +150,10 @@ Or as follows.
150
150
 
151
151
  ActiveModelSerializer will fetch automatically the right serializer to render.
152
152
 
153
- ### Manually specifying serializer options
153
+ ### Manually specifying serializer / adapter options
154
154
 
155
155
  ```ruby
156
- # Serializer options can be specified on routes or namespaces.
156
+ # Serializer and adapter options can be specified on routes or namespaces.
157
157
  namespace 'foo', serializer: BarSerializer do
158
158
  get "/" do
159
159
  # will use "bar" serializer
@@ -171,6 +171,36 @@ namespace 'foo', serializer: BarSerializer do
171
171
  end
172
172
  ```
173
173
 
174
+ ```ruby
175
+ # Serializer and adapter options can also be specified in the body of the route
176
+ resource :users do
177
+ get '/:id' do
178
+ if conditional
179
+ # uses UserSerializer and configured default adapter automatically
180
+ current_user
181
+ else
182
+ # uses specified serializer and adapter
183
+ render current_user, serializer: ErrorSerializer, adapter: :attributes
184
+ end
185
+ end
186
+ end
187
+ ```
188
+
189
+ ```ruby
190
+ # Adhoc serializer options can be specified in the body of the route
191
+ resource :users do
192
+ get '/:id' do
193
+ render current_user, extra: { adhoc_name_option: 'value' }
194
+ end
195
+ end
196
+
197
+ class UserSerializer
198
+ def name
199
+ instance_options[:adhoc_name_option] # accessible in instance_options
200
+ end
201
+ end
202
+ ```
203
+
174
204
  ### Custom Metadata
175
205
 
176
206
  ```ruby
@@ -37,8 +37,16 @@ module Grape
37
37
  end
38
38
  end
39
39
 
40
- def render(resources, meta = {})
41
- env['ams_meta'] = meta
40
+ def render(resources, extra_options = {})
41
+ options = extra_options.symbolize_keys
42
+ env['ams_meta'] = options.slice(
43
+ :meta, :meta_key
44
+ )
45
+ env['ams_adapter'] = options.slice(
46
+ :adapter, :serializer, :each_serializer, :include,
47
+ :fields, :key_transform, :links, :namespace
48
+ )
49
+ env['ams_extra'] = options[:extra]
42
50
  resources
43
51
  end
44
52
 
@@ -12,6 +12,8 @@ module Grape
12
12
  options[:scope] = endpoint unless options.key?(:scope)
13
13
  options.merge!(default_root_options) unless options.key?(:root)
14
14
  options.merge!(meta_options)
15
+ options.merge!(adapter_options)
16
+ options.merge!(extra_options)
15
17
  options
16
18
  )
17
19
  end
@@ -56,13 +58,23 @@ module Grape
56
58
 
57
59
  def meta_options
58
60
  options = {}
59
- ams_meta = env['ams_meta'] || {}
60
- meta = ams_meta[:meta]
61
- meta_key = ams_meta[:meta_key]
61
+ meta_options = env['ams_meta'] || {}
62
+ meta = meta_options[:meta]
63
+ meta_key = meta_options[:meta_key]
62
64
  options[:meta] = meta if meta
63
65
  options[:meta_key] = meta_key if meta && meta_key
64
66
  options
65
67
  end
68
+
69
+ def adapter_options
70
+ env['ams_adapter'] || {}
71
+ end
72
+
73
+ def extra_options
74
+ options = env['ams_extra'] || {}
75
+ return options if options.is_a?(Hash)
76
+ raise 'Extra options must be a hash'
77
+ end
66
78
  end
67
79
  end
68
80
  end
@@ -48,8 +48,9 @@ module Grape
48
48
  end
49
49
 
50
50
  def collection_class
51
- return nil unless resource.respond_to?(:to_ary)
52
- ActiveModel::Serializer.config.collection_serializer
51
+ if resource.respond_to?(:to_ary) || resource.respond_to?(:all)
52
+ ActiveModel::Serializer.config.collection_serializer
53
+ end
53
54
  end
54
55
 
55
56
  def namespace_inferred_class
@@ -84,8 +85,10 @@ module Grape
84
85
  end
85
86
 
86
87
  def resource_class
87
- if resource.respond_to?(:to_ary)
88
- resource.try(:klass) || resource.compact.first.class
88
+ if resource.respond_to?(:klass)
89
+ resource.klass
90
+ elsif resource.respond_to?(:to_ary) || resource.respond_to?(:all)
91
+ resource.first.class
89
92
  else
90
93
  resource.class
91
94
  end
@@ -1,5 +1,5 @@
1
1
  module Grape
2
2
  module ActiveModelSerializers
3
- VERSION = '1.5.0'.freeze
3
+ VERSION = '1.5.1'.freeze
4
4
  end
5
5
  end
@@ -16,45 +16,126 @@ describe 'Grape::EndpointExtension' do
16
16
  end
17
17
 
18
18
  let(:serializer) { Grape::Formatter::ActiveModelSerializers }
19
-
20
- let(:user) do
19
+ let(:user) {
21
20
  Object.new do
22
21
  def name
23
22
  'sven'
24
23
  end
25
24
  end
26
- end
27
-
25
+ }
28
26
  let(:users) { [user, user] }
29
27
 
30
28
  describe '#render' do
29
+ let(:env) { {} }
30
+ let(:env_key) {}
31
+
31
32
  before do
32
- allow(subject).to receive(:env).and_return({})
33
+ allow(subject).to receive(:env).and_return(env)
34
+ end
35
+
36
+ shared_examples_for 'option capture' do
37
+ it 'captures options' do
38
+ subject.render(users, options)
39
+ expect(env[env_key]).to eq(options)
40
+ end
41
+ end
42
+
43
+ shared_examples_for 'skipped option capture' do
44
+ it 'does not capture options' do
45
+ subject.render(users, options)
46
+ expect(env[env_key]).to eq({})
47
+ end
33
48
  end
34
49
 
35
50
  it { should respond_to(:render) }
36
- let(:meta_content) { { total: 2 } }
37
- let(:meta_full) { { meta: meta_content } }
38
51
 
39
- context 'supplying meta' do
40
- before do
41
- allow(subject).to receive(:env) { { meta: meta_full } }
52
+ context 'meta options' do
53
+ let(:env_key) { 'ams_meta' }
54
+ let(:meta_full) { { meta: meta_content } }
55
+
56
+ context 'meta' do
57
+ let(:options) { { meta: { total: 2 } } }
58
+ it_behaves_like 'option capture'
59
+ end
60
+
61
+ context 'meta_key' do
62
+ let(:options) { { meta_key: 'custom_meta' } }
63
+ it_behaves_like 'option capture'
42
64
  end
43
65
 
44
- it 'passes through the Resource and uses given meta settings' do
45
- expect(subject.render(users, meta_full)).to eq(users)
66
+ context 'unknown option' do
67
+ let(:options) { { unknown: 'value' } }
68
+ it_behaves_like 'skipped option capture'
46
69
  end
47
70
  end
48
71
 
49
- context 'supplying meta and key' do
50
- let(:meta_key) { { meta_key: :custom_key_name } }
72
+ context 'adapter options' do
73
+ let(:options) { {} }
74
+ let(:env_key) { 'ams_adapter' }
75
+
76
+ context 'adapter' do
77
+ let(:options) { { adapter: :json } }
78
+ it_behaves_like 'option capture'
79
+ end
51
80
 
52
- before do
53
- allow(subject).to receive(:env) { { meta: meta_full.merge(meta_key) } }
81
+ context 'include' do
82
+ let(:options) { { include: '*' } }
83
+ it_behaves_like 'option capture'
54
84
  end
55
85
 
56
- it 'passes through the Resource and uses given meta settings' do
57
- expect(subject.render(users, meta_full.merge(meta_key))).to eq(users)
86
+ context 'fields' do
87
+ let(:options) { { fields: [:id] } }
88
+ it_behaves_like 'option capture'
89
+ end
90
+
91
+ context 'key_transform' do
92
+ let(:options) { { key_transform: :camel_lower } }
93
+ it_behaves_like 'option capture'
94
+ end
95
+
96
+ context 'links' do
97
+ let(:links_object) {
98
+ {
99
+ href: 'http://example.com/api/posts',
100
+ meta: {
101
+ count: 10
102
+ }
103
+ }
104
+ }
105
+ let(:options) { { links: links_object } }
106
+ it_behaves_like 'option capture'
107
+ end
108
+
109
+ context 'namespace' do
110
+ let(:options) { { namespace: V4 } }
111
+ it_behaves_like 'option capture'
112
+ end
113
+
114
+ context 'unknown option' do
115
+ let(:options) { { unknown: 'value' } }
116
+ it_behaves_like 'skipped option capture'
117
+ end
118
+ end
119
+
120
+ context 'extra options' do
121
+ let(:env_key) { 'ams_extra' }
122
+
123
+ context 'namespace' do
124
+ let(:options) { { extra: { option: 'value' } } }
125
+
126
+ it 'captures options' do
127
+ subject.render(users, options)
128
+ expect(env[env_key]).to eq(options[:extra])
129
+ end
130
+ end
131
+
132
+ context 'unknown option' do
133
+ let(:options) { { unknown: 'value' } }
134
+
135
+ it 'does not capture options' do
136
+ subject.render(users, options)
137
+ expect(env[env_key]).to eq(nil)
138
+ end
58
139
  end
59
140
  end
60
141
  end
@@ -0,0 +1,129 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::ActiveModelSerializers::OptionsBuilder do
4
+ let(:resolver) { described_class.new(resource, env) }
5
+ let(:resource) { User.new }
6
+ let(:env) { { 'api.endpoint' => UsersApi.endpoints.first } }
7
+
8
+ context '#options' do
9
+ let(:options) { resolver.options }
10
+
11
+ context 'meta options' do
12
+ let(:env) { super().merge('ams_meta' => meta_options) }
13
+ let(:meta_options) {
14
+ {
15
+ meta: meta,
16
+ meta_key: meta_key
17
+ }
18
+ }
19
+ let(:meta) { { sample: 'metadata' } }
20
+ let(:meta_key) { 'specified_key' }
21
+
22
+ context 'meta option set' do
23
+ context 'meta_key set' do
24
+ it 'includes meta' do
25
+ expect(options[:meta]).to eq(meta)
26
+ end
27
+
28
+ it 'includes meta_key' do
29
+ expect(options[:meta_key]).to eq(meta_key)
30
+ end
31
+ end
32
+
33
+ context 'meta_key unset' do
34
+ let(:meta_key) { nil }
35
+
36
+ it 'includes meta' do
37
+ expect(options[:meta]).to eq(meta)
38
+ end
39
+
40
+ it 'does not include meta_key' do
41
+ expect(options.keys).not_to include(:meta_key)
42
+ end
43
+ end
44
+ end
45
+
46
+ context 'meta option unset' do
47
+ let(:meta) { nil }
48
+
49
+ context 'meta_key set' do
50
+ it 'does not include meta' do
51
+ expect(options.keys).not_to include(:meta)
52
+ end
53
+
54
+ it 'does not include meta_key' do
55
+ expect(options.keys).not_to include(:meta_key)
56
+ end
57
+ end
58
+
59
+ context 'meta_key unset' do
60
+ let(:meta_key) { nil }
61
+
62
+ it 'does not include meta' do
63
+ expect(options.keys).not_to include(:meta)
64
+ end
65
+
66
+ it 'does not include meta_key' do
67
+ expect(options.keys).not_to include(:meta_key)
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ context 'adapter options' do
74
+ let(:env) { super().merge('ams_adapter' => adapter_options) }
75
+ let(:adapter_options) { {} }
76
+
77
+ context 'adapter' do
78
+ let(:adapter_options) { { adapter: adapter } }
79
+ let(:adapter) { :attributes }
80
+
81
+ it 'includes adapter as top-level option' do
82
+ expect(options[:adapter]).to eq(adapter)
83
+ end
84
+ end
85
+
86
+ context 'serializer' do
87
+ let(:adapter_options) { { serializer: serializer } }
88
+ let(:serializer) { V2::UserSerializer }
89
+
90
+ it 'includes serializer as top-level option' do
91
+ expect(options[:serializer]).to eq(serializer)
92
+ end
93
+ end
94
+
95
+ context 'each_serializer' do
96
+ let(:adapter_options) { { each_serializer: each_serializer } }
97
+ let(:each_serializer) { V2::UserSerializer }
98
+
99
+ it 'includes each_serializer as top-level option' do
100
+ expect(options[:each_serializer]).to eq(each_serializer)
101
+ end
102
+ end
103
+ end
104
+
105
+ context 'extra options' do
106
+ let(:env) { super().merge('ams_extra' => extra_options) }
107
+
108
+ context 'hash' do
109
+ let(:extra_options) { { extra: 'info' } }
110
+
111
+ it 'includes extra options in top-level options' do
112
+ expect(options.keys).to include(:extra)
113
+ end
114
+ end
115
+
116
+ context 'not a hash' do
117
+ let(:extra_options) { 'extra' }
118
+
119
+ it 'raises an exception' do
120
+ expect {
121
+ options
122
+ }.to raise_exception(
123
+ 'Extra options must be a hash'
124
+ )
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -1,4 +1,3 @@
1
- require 'pry'
2
1
  require 'spec_helper'
3
2
 
4
3
  # asserts serializer resolution order:
@@ -0,0 +1,68 @@
1
+ require 'sequel'
2
+ require 'spec_helper'
3
+
4
+ describe 'Sequel Integration' do
5
+ before do
6
+ DB = Sequel.sqlite unless defined?(DB)
7
+ DB.create_table(:users) do
8
+ primary_key :id
9
+ String :name
10
+ end
11
+ ActiveModelSerializers.config.adapter = :json
12
+ app.format :json
13
+ app.formatter :json, Grape::Formatter::ActiveModelSerializers
14
+ end
15
+
16
+ after do
17
+ DB.drop_table(:users)
18
+ Object.send(:remove_const, :SequelUser)
19
+ Object.send(:remove_const, :SequelUserSerializer)
20
+ end
21
+
22
+ let!(:model) {
23
+ SequelUser = Class.new(Sequel::Model(:users)) do
24
+ include ActiveModel::Serialization
25
+ def self.model_name
26
+ 'User'
27
+ end
28
+ end
29
+ }
30
+ let!(:serializer) {
31
+ SequelUserSerializer = Class.new(ActiveModel::Serializer) do
32
+ attributes :id, :name
33
+ end
34
+ }
35
+ let(:app) { Class.new(Grape::API) }
36
+
37
+ context 'collection' do
38
+ let!(:users) {
39
+ [
40
+ model.create(name: 'one'),
41
+ model.create(name: 'two')
42
+ ]
43
+ }
44
+
45
+ it 'renders' do
46
+ app.get('/users') { render SequelUser.dataset }
47
+ response = get '/users'
48
+ expect(JSON.parse(response.body)).to eq(
49
+ 'users' => [
50
+ { 'id' => 1, 'name' => 'one' },
51
+ { 'id' => 2, 'name' => 'two' }
52
+ ]
53
+ )
54
+ end
55
+ end
56
+
57
+ context 'member' do
58
+ let!(:user) { model.create(name: 'name') }
59
+
60
+ it 'renders' do
61
+ app.get('/user/1') { render SequelUser.first }
62
+ response = get '/user/1'
63
+ expect(JSON.parse(response.body)).to eq(
64
+ 'user' => { 'id' => 1, 'name' => 'name' }
65
+ )
66
+ end
67
+ end
68
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape-active_model_serializers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Richard Henry Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-24 00:00:00.000000000 Z
11
+ date: 2017-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grape
@@ -136,6 +136,7 @@ files:
136
136
  - ".travis.yml"
137
137
  - CHANGELOG.md
138
138
  - CONTRIBUTING.md
139
+ - Dangerfile
139
140
  - Gemfile
140
141
  - Guardfile
141
142
  - LICENSE.txt
@@ -156,7 +157,9 @@ files:
156
157
  - spec/grape-active_model_serializers/formatter_spec.rb
157
158
  - spec/grape-active_model_serializers/versioned_api_formatter_spec.rb
158
159
  - spec/grape-active_model_serializers_spec.rb
160
+ - spec/grape/active_model_serializers/options_builder_spec.rb
159
161
  - spec/grape/active_model_serializers/serializer_resolver_spec.rb
162
+ - spec/integration/sequel_spec.rb
160
163
  - spec/old_grape_ams_spec.rb
161
164
  - spec/spec_helper.rb
162
165
  - spec/support/api/users_api.rb
@@ -190,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
190
193
  version: '0'
191
194
  requirements: []
192
195
  rubyforge_project:
193
- rubygems_version: 2.6.6
196
+ rubygems_version: 2.5.1
194
197
  signing_key:
195
198
  specification_version: 4
196
199
  summary: Use active_model_serializer in grape
@@ -200,7 +203,9 @@ test_files:
200
203
  - spec/grape-active_model_serializers/formatter_spec.rb
201
204
  - spec/grape-active_model_serializers/versioned_api_formatter_spec.rb
202
205
  - spec/grape-active_model_serializers_spec.rb
206
+ - spec/grape/active_model_serializers/options_builder_spec.rb
203
207
  - spec/grape/active_model_serializers/serializer_resolver_spec.rb
208
+ - spec/integration/sequel_spec.rb
204
209
  - spec/old_grape_ams_spec.rb
205
210
  - spec/spec_helper.rb
206
211
  - spec/support/api/users_api.rb