grape-active_model_serializers 1.5.0 → 1.5.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
  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