brainstem 1.1.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +81 -4
- data/Gemfile.lock +9 -9
- data/README.md +134 -37
- data/brainstem.gemspec +1 -1
- data/lib/brainstem/api_docs/endpoint.rb +40 -18
- data/lib/brainstem/api_docs/formatters/markdown/endpoint_formatter.rb +27 -22
- data/lib/brainstem/api_docs/formatters/markdown/helper.rb +9 -0
- data/lib/brainstem/api_docs/formatters/markdown/presenter_formatter.rb +14 -6
- data/lib/brainstem/api_docs/presenter.rb +3 -7
- data/lib/brainstem/concerns/controller_dsl.rb +138 -14
- data/lib/brainstem/concerns/presenter_dsl.rb +39 -6
- data/lib/brainstem/dsl/array_block_field.rb +25 -0
- data/lib/brainstem/dsl/block_field.rb +69 -0
- data/lib/brainstem/dsl/configuration.rb +13 -5
- data/lib/brainstem/dsl/field.rb +15 -1
- data/lib/brainstem/dsl/fields_block.rb +20 -2
- data/lib/brainstem/dsl/hash_block_field.rb +30 -0
- data/lib/brainstem/presenter.rb +10 -6
- data/lib/brainstem/presenter_validator.rb +20 -11
- data/lib/brainstem/version.rb +1 -1
- data/spec/brainstem/api_docs/endpoint_spec.rb +347 -14
- data/spec/brainstem/api_docs/formatters/markdown/endpoint_formatter_spec.rb +106 -13
- data/spec/brainstem/api_docs/formatters/markdown/helper_spec.rb +19 -0
- data/spec/brainstem/api_docs/formatters/markdown/presenter_formatter_spec.rb +150 -37
- data/spec/brainstem/api_docs/presenter_spec.rb +85 -18
- data/spec/brainstem/concerns/controller_dsl_spec.rb +615 -31
- data/spec/brainstem/concerns/inheritable_configuration_spec.rb +32 -9
- data/spec/brainstem/concerns/presenter_dsl_spec.rb +99 -25
- data/spec/brainstem/dsl/array_block_field_spec.rb +43 -0
- data/spec/brainstem/dsl/block_field_spec.rb +188 -0
- data/spec/brainstem/dsl/field_spec.rb +86 -20
- data/spec/brainstem/dsl/hash_block_field_spec.rb +166 -0
- data/spec/brainstem/presenter_collection_spec.rb +24 -24
- data/spec/brainstem/presenter_spec.rb +233 -9
- data/spec/brainstem/query_strategies/filter_and_search_spec.rb +1 -1
- data/spec/spec_helpers/presenters.rb +8 -0
- data/spec/spec_helpers/schema.rb +13 -0
- metadata +15 -6
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'set'
|
3
3
|
require 'ostruct'
|
4
|
+
require 'brainstem/presenter'
|
4
5
|
require 'brainstem/api_docs/presenter'
|
5
6
|
|
6
7
|
module Brainstem
|
@@ -111,14 +112,25 @@ module Brainstem
|
|
111
112
|
|
112
113
|
|
113
114
|
describe "#valid_fields" do
|
114
|
-
let(:
|
115
|
-
|
115
|
+
let(:presenter_class) do
|
116
|
+
Class.new(Brainstem::Presenter) do
|
117
|
+
presents Workspace
|
118
|
+
end
|
119
|
+
end
|
116
120
|
|
117
|
-
|
118
|
-
|
121
|
+
subject { described_class.new(atlas, target_class: 'Workspace', const: presenter_class) }
|
122
|
+
|
123
|
+
before do
|
124
|
+
stub(atlas).find_by_class(anything) { nil }
|
125
|
+
end
|
119
126
|
|
127
|
+
describe "leafs" do
|
120
128
|
context "when nodoc" do
|
121
|
-
|
129
|
+
before do
|
130
|
+
presenter_class.fields do
|
131
|
+
field :new_field, :string, dynamic: lambda { "new_field value" }, nodoc: true
|
132
|
+
end
|
133
|
+
end
|
122
134
|
|
123
135
|
it "rejects the field" do
|
124
136
|
expect(subject.valid_fields.count).to eq 0
|
@@ -126,18 +138,43 @@ module Brainstem
|
|
126
138
|
end
|
127
139
|
|
128
140
|
context "when not nodoc" do
|
141
|
+
before do
|
142
|
+
presenter_class.fields do
|
143
|
+
field :new_field, :string, dynamic: lambda { "new_field value" }, nodoc: false
|
144
|
+
field :new_field2, :string, dynamic: lambda { "new_field2 value" }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
129
148
|
it "keeps the field" do
|
130
|
-
expect(subject.valid_fields.
|
149
|
+
expect(subject.valid_fields.keys).to match_array(%w(new_field new_field2))
|
131
150
|
end
|
132
151
|
end
|
133
152
|
end
|
134
153
|
|
135
154
|
describe "branches" do
|
136
155
|
describe "single nesting" do
|
137
|
-
|
156
|
+
context "when nested field is nodoc" do
|
157
|
+
before do
|
158
|
+
presenter_class.fields do
|
159
|
+
fields :nested_field, :hash, dynamic: lambda { {} }, nodoc: true do
|
160
|
+
field :sub_field, :string, dynamic: lambda { "sub_field value" }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
138
164
|
|
139
|
-
|
140
|
-
|
165
|
+
it "rejects the nested field and its sub fields" do
|
166
|
+
expect(subject.valid_fields.count).to eq 0
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "when all sub fields in a nested field are nodoc" do
|
171
|
+
before do
|
172
|
+
presenter_class.fields do
|
173
|
+
fields :nested_field, :hash, dynamic: lambda { {} }, nodoc: false do
|
174
|
+
field :sub_field, :string, dynamic: lambda { "new_field2 value" }, nodoc: true
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
141
178
|
|
142
179
|
it "rejects the nested field" do
|
143
180
|
expect(subject.valid_fields.count).to eq 0
|
@@ -145,30 +182,60 @@ module Brainstem
|
|
145
182
|
end
|
146
183
|
|
147
184
|
context "when not all nodoc" do
|
185
|
+
before do
|
186
|
+
presenter_class.fields do
|
187
|
+
fields :nested_field, :hash, dynamic: lambda { {} } do
|
188
|
+
field :sub_field, :string, dynamic: lambda { "new_field2 value" }
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
148
193
|
it "keeps the nested field" do
|
149
|
-
|
194
|
+
valid_fields = subject.valid_fields.to_h.with_indifferent_access
|
195
|
+
|
196
|
+
expect(valid_fields.keys).to eq(%w(nested_field))
|
197
|
+
expect(valid_fields[:nested_field].keys).to eq(%w(sub_field))
|
150
198
|
end
|
151
199
|
end
|
152
|
-
|
153
200
|
end
|
154
201
|
|
155
202
|
describe "double nesting" do
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
203
|
+
context "when the only double nested field is nodoc" do
|
204
|
+
before do
|
205
|
+
presenter_class.fields do
|
206
|
+
fields :nested_field, :hash, dynamic: lambda { {} } do
|
207
|
+
fields :double_nested_field, :hash, dynamic: lambda { {} }, nodoc: true do
|
208
|
+
field :leaf_field, :string, dynamic: lambda { "leaf value" }
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
160
213
|
|
161
|
-
it "rejects the nested field" do
|
214
|
+
it "rejects the nested field and its sub fields" do
|
162
215
|
expect(subject.valid_fields.count).to eq 0
|
163
216
|
end
|
164
217
|
end
|
165
218
|
|
166
219
|
context "when not all nodoc" do
|
220
|
+
before do
|
221
|
+
presenter_class.fields do
|
222
|
+
fields :nested_field, :hash, dynamic: lambda { {} } do
|
223
|
+
fields :double_nested_field, :hash, dynamic: lambda { {} } do
|
224
|
+
field :leaf_field_1, :string, dynamic: lambda { "leaf_field_1 value" }
|
225
|
+
field :leaf_field_2, :string, dynamic: lambda { "leaf_field_2 value" }, nodoc: false
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
167
231
|
it "keeps the nested field" do
|
168
|
-
|
232
|
+
valid_fields = subject.valid_fields.to_h.with_indifferent_access
|
233
|
+
|
234
|
+
expect(valid_fields.keys).to match_array(%w(nested_field))
|
235
|
+
expect(valid_fields[:nested_field].keys).to match_array(%w(double_nested_field))
|
236
|
+
expect(valid_fields[:nested_field][:double_nested_field].keys).to match_array(%w(leaf_field_1 leaf_field_2))
|
169
237
|
end
|
170
238
|
end
|
171
|
-
|
172
239
|
end
|
173
240
|
end
|
174
241
|
end
|
@@ -102,23 +102,31 @@ module Brainstem
|
|
102
102
|
end
|
103
103
|
|
104
104
|
describe ".model_params" do
|
105
|
+
let(:root_proc) { Proc.new {} }
|
106
|
+
|
105
107
|
before do
|
106
108
|
stub(subject).brainstem_model_name { "widgets" }
|
109
|
+
stub(subject).format_root_name(:widgets) { root_proc }
|
107
110
|
end
|
108
111
|
|
109
112
|
it "evaluates the block given to it" do
|
110
|
-
mock(subject).valid(:thing,
|
113
|
+
mock(subject).valid(:thing, :string, 'root' => root_proc, 'ancestors' => [root_proc])
|
111
114
|
|
112
115
|
subject.model_params :widgets do |param|
|
113
|
-
param.valid :thing
|
116
|
+
param.valid :thing, :string
|
114
117
|
end
|
115
118
|
end
|
116
119
|
|
117
120
|
it "merges options" do
|
118
|
-
mock(subject).valid(:thing,
|
121
|
+
mock(subject).valid(:thing, :integer,
|
122
|
+
'root' => root_proc,
|
123
|
+
'ancestors' => [root_proc],
|
124
|
+
'nodoc' => true,
|
125
|
+
'required' => true
|
126
|
+
)
|
119
127
|
|
120
128
|
subject.model_params :widgets do |param|
|
121
|
-
param.valid :thing, nodoc: true
|
129
|
+
param.valid :thing, :integer, nodoc: true, required: true
|
122
130
|
end
|
123
131
|
end
|
124
132
|
end
|
@@ -127,29 +135,405 @@ module Brainstem
|
|
127
135
|
context "when given a name and an options hash" do
|
128
136
|
it "appends to the valid params hash" do
|
129
137
|
subject.brainstem_params do
|
130
|
-
valid :
|
131
|
-
info: "sprockets[
|
138
|
+
valid :sprocket_ids, :array,
|
139
|
+
info: "sprockets[sprocket_ids] is required",
|
140
|
+
required: true,
|
141
|
+
item_type: :integer
|
132
142
|
end
|
133
143
|
|
134
|
-
|
135
|
-
|
144
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
145
|
+
expect(valid_params.keys.length).to eq(1)
|
146
|
+
expect(valid_params.keys[0]).to be_a(Proc)
|
147
|
+
expect(valid_params.keys[0].call).to eq("sprocket_ids")
|
148
|
+
|
149
|
+
sprocket_ids_config = valid_params[valid_params.keys[0]]
|
150
|
+
expect(sprocket_ids_config[:info]).to eq "sprockets[sprocket_ids] is required"
|
151
|
+
expect(sprocket_ids_config[:required]).to be_truthy
|
152
|
+
expect(sprocket_ids_config[:type]).to eq("array")
|
153
|
+
expect(sprocket_ids_config[:item_type]).to eq("integer")
|
136
154
|
end
|
137
155
|
end
|
138
156
|
|
139
|
-
context "when given a name and an options hash" do
|
157
|
+
context "when given a name and an HWIA options hash" do
|
140
158
|
it "appends to the valid params hash" do
|
141
|
-
# This is
|
159
|
+
# This is Hash With Indifferent Access, so all keys are stringified
|
142
160
|
data = {
|
143
161
|
"recursive" => true,
|
144
|
-
"info"
|
162
|
+
"info" => "sprockets[sub_sprockets] is recursive and an array",
|
163
|
+
"required" => true
|
145
164
|
}
|
146
165
|
|
147
166
|
subject.brainstem_params do
|
148
|
-
valid :sub_sprockets, data
|
167
|
+
valid :sub_sprockets, :hash, data
|
168
|
+
end
|
169
|
+
|
170
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
171
|
+
expect(valid_params.keys.length).to eq(1)
|
172
|
+
expect(valid_params.keys[0].call).to eq("sub_sprockets")
|
173
|
+
expect(valid_params[valid_params.keys[0]]).to eq({
|
174
|
+
"recursive" => true,
|
175
|
+
"info" => "sprockets[sub_sprockets] is recursive and an array",
|
176
|
+
"required" => true,
|
177
|
+
"type" => "hash",
|
178
|
+
"nodoc" => false
|
179
|
+
})
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "when no options are provided" do
|
184
|
+
it "sets default options for the param" do
|
185
|
+
subject.brainstem_params do
|
186
|
+
valid :sprocket_name, :text
|
187
|
+
end
|
188
|
+
|
189
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
190
|
+
expect(valid_params.keys.length).to eq(1)
|
191
|
+
expect(valid_params.keys[0].call).to eq("sprocket_name")
|
192
|
+
|
193
|
+
configuration = valid_params[valid_params.keys[0]]
|
194
|
+
expect(configuration[:nodoc]).to be_falsey
|
195
|
+
expect(configuration[:required]).to be_falsey
|
196
|
+
expect(configuration[:type]).to eq("text")
|
197
|
+
end
|
198
|
+
|
199
|
+
context "when block is specified" do
|
200
|
+
it "defaults type to string and sets default options for the param" do
|
201
|
+
subject.brainstem_params do
|
202
|
+
valid :sprocket, :hash do
|
203
|
+
valid :title, :string
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
208
|
+
expect(valid_params.keys.length).to eq(2)
|
209
|
+
|
210
|
+
param_keys = valid_params.keys
|
211
|
+
expect(param_keys[0].call).to eq('sprocket')
|
212
|
+
expect(param_keys[1].call).to eq('title')
|
213
|
+
|
214
|
+
sprocket_key = param_keys[0]
|
215
|
+
sprocket_configuration = valid_params[sprocket_key]
|
216
|
+
expect(sprocket_configuration[:nodoc]).to be_falsey
|
217
|
+
expect(sprocket_configuration[:required]).to be_falsey
|
218
|
+
expect(sprocket_configuration[:type]).to eq('hash')
|
219
|
+
expect(sprocket_configuration[:ancestors]).to be_nil
|
220
|
+
expect(sprocket_configuration[:root]).to be_nil
|
221
|
+
|
222
|
+
title_configuration = valid_params[param_keys[1]]
|
223
|
+
expect(title_configuration[:nodoc]).to be_falsey
|
224
|
+
expect(title_configuration[:required]).to be_falsey
|
225
|
+
expect(title_configuration[:type]).to eq('string')
|
226
|
+
expect(title_configuration[:root]).to be_nil
|
227
|
+
expect(title_configuration[:ancestors]).to eq([sprocket_key])
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context "when type is hash" do
|
233
|
+
it "adds the nested fields to valid params" do
|
234
|
+
subject.brainstem_params do
|
235
|
+
valid :id, :integer
|
236
|
+
|
237
|
+
valid :info, :hash, required: true do |param|
|
238
|
+
param.valid :title, :string, required: true
|
239
|
+
end
|
240
|
+
|
241
|
+
model_params :sprocket do |param|
|
242
|
+
param.valid :data, :text
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
247
|
+
expect(valid_params.keys.length).to eq(4)
|
248
|
+
|
249
|
+
param_keys = valid_params.keys
|
250
|
+
expect(param_keys[0].call).to eq('id')
|
251
|
+
expect(param_keys[1].call).to eq('info')
|
252
|
+
expect(param_keys[2].call).to eq('title')
|
253
|
+
expect(param_keys[3].call).to eq('data')
|
254
|
+
|
255
|
+
id_config = valid_params[param_keys[0]]
|
256
|
+
expect(id_config[:root]).to be_nil
|
257
|
+
expect(id_config[:ancestors]).to be_nil
|
258
|
+
|
259
|
+
info_key = param_keys[1]
|
260
|
+
info_config = valid_params[info_key]
|
261
|
+
expect(info_config[:root]).to be_nil
|
262
|
+
expect(info_config[:ancestors]).to be_nil
|
263
|
+
|
264
|
+
info_title_config = valid_params[param_keys[2]]
|
265
|
+
expect(info_title_config[:root]).to be_nil
|
266
|
+
expect(info_title_config[:ancestors]).to eq([info_key])
|
267
|
+
|
268
|
+
sprocket_data_config = valid_params[param_keys[3]]
|
269
|
+
sprocket_data_root_key = sprocket_data_config[:root]
|
270
|
+
expect(sprocket_data_root_key).to be_present
|
271
|
+
expect(sprocket_data_config[:ancestors]).to eq([sprocket_data_root_key])
|
272
|
+
end
|
273
|
+
|
274
|
+
context "when multi nested attributes are specified" do
|
275
|
+
it "adds the nested fields to valid params" do
|
276
|
+
subject.brainstem_params do
|
277
|
+
model_params :sprocket do |param|
|
278
|
+
param.valid :title, :string
|
279
|
+
|
280
|
+
param.valid :details, :hash do |nested_param|
|
281
|
+
nested_param.valid :category, :string
|
282
|
+
|
283
|
+
nested_param.valid :data, :hash do |double_nested_param|
|
284
|
+
double_nested_param.valid :raw_text, :string
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
291
|
+
param_keys = valid_params.keys
|
292
|
+
expect(param_keys.length).to eq(5)
|
293
|
+
|
294
|
+
expect(param_keys[0].call).to eq('title')
|
295
|
+
title_config = valid_params[param_keys[0]]
|
296
|
+
root_param_key = title_config[:root]
|
297
|
+
expect(root_param_key).to be_present
|
298
|
+
expect(title_config[:ancestors]).to eq([root_param_key])
|
299
|
+
|
300
|
+
expect(param_keys[1].call).to eq('details')
|
301
|
+
details_key = param_keys[1]
|
302
|
+
details_config = valid_params[details_key]
|
303
|
+
expect(details_config[:root]).to eq(root_param_key)
|
304
|
+
expect(details_config[:ancestors]).to eq([root_param_key])
|
305
|
+
|
306
|
+
expect(param_keys[2].call).to eq('category')
|
307
|
+
details_category_config = valid_params[param_keys[2]]
|
308
|
+
expect(details_category_config[:root]).to be_nil
|
309
|
+
expect(details_category_config[:ancestors]).to eq([root_param_key, details_key])
|
310
|
+
|
311
|
+
expect(param_keys[3].call).to eq('data')
|
312
|
+
details_data_key = param_keys[3]
|
313
|
+
details_data_config = valid_params[details_data_key]
|
314
|
+
expect(details_data_config[:root]).to be_nil
|
315
|
+
expect(details_data_config[:ancestors]).to eq([root_param_key, details_key])
|
316
|
+
|
317
|
+
expect(param_keys[4].call).to eq('raw_text')
|
318
|
+
details_data_raw_text_config = valid_params[param_keys[4]]
|
319
|
+
expect(details_data_raw_text_config[:root]).to be_nil
|
320
|
+
expect(details_data_raw_text_config[:ancestors]).to eq([root_param_key, details_key, details_data_key])
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
context "when root has no required attribute" do
|
325
|
+
it "sets the required attribute for the parent configuration to false" do
|
326
|
+
subject.brainstem_params do
|
327
|
+
valid :template, :hash do |param|
|
328
|
+
param.valid :id, :integer
|
329
|
+
param.valid :title, :string
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
334
|
+
|
335
|
+
template_key = valid_params.keys[0]
|
336
|
+
expect(template_key.call).to eq('template')
|
337
|
+
expect(valid_params[template_key][:required]).to be_falsey
|
338
|
+
end
|
339
|
+
|
340
|
+
context "when one of the nested fields is required" do
|
341
|
+
it "sets the required attribute for the parent configuration to true" do
|
342
|
+
subject.brainstem_params do
|
343
|
+
valid :template, :hash do |param|
|
344
|
+
param.valid :id, :integer, required: true
|
345
|
+
param.valid :title, :string
|
346
|
+
end
|
347
|
+
|
348
|
+
model_params :sprocket do |param|
|
349
|
+
param.valid :details, :hash do |nested_param|
|
350
|
+
nested_param.valid :data, :hash do |double_nested_param|
|
351
|
+
double_nested_param.valid :raw_text, :string, required: true
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
358
|
+
|
359
|
+
template_key = valid_params.keys[0]
|
360
|
+
expect(template_key.call).to eq('template')
|
361
|
+
expect(valid_params[template_key][:required]).to be_truthy
|
362
|
+
|
363
|
+
sprocket_details_key = valid_params.keys[3]
|
364
|
+
expect(sprocket_details_key.call).to eq('details')
|
365
|
+
expect(valid_params[sprocket_details_key][:required]).to be_truthy
|
366
|
+
|
367
|
+
sprocket_details_data_key = valid_params.keys[4]
|
368
|
+
expect(sprocket_details_data_key.call).to eq('data')
|
369
|
+
expect(valid_params[sprocket_details_data_key][:required]).to be_truthy
|
370
|
+
|
371
|
+
sprocket_details_data_raw_text_key = valid_params.keys[5]
|
372
|
+
expect(sprocket_details_data_raw_text_key.call).to eq('raw_text')
|
373
|
+
expect(valid_params[sprocket_details_data_raw_text_key][:required]).to be_truthy
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
context "when root is nodoc" do
|
379
|
+
it "updates the nodoc property on its nested fields to true" do
|
380
|
+
subject.brainstem_params do
|
381
|
+
model_params :sprocket do |param|
|
382
|
+
param.valid :title, :string
|
383
|
+
param.valid :details, :hash, nodoc: true do |param|
|
384
|
+
param.valid :category, :string
|
385
|
+
param.valid :data, :hash do |nested_param|
|
386
|
+
param.valid :raw_text, :string
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
393
|
+
|
394
|
+
title_key = valid_params.keys[0]
|
395
|
+
expect(title_key.call).to eq('title')
|
396
|
+
expect(valid_params[title_key][:nodoc]).to be_falsey
|
397
|
+
|
398
|
+
details_key = valid_params.keys[1]
|
399
|
+
expect(details_key.call).to eq('details')
|
400
|
+
expect(valid_params[details_key][:nodoc]).to be_truthy
|
401
|
+
|
402
|
+
details_category_key = valid_params.keys[2]
|
403
|
+
expect(details_category_key.call).to eq('category')
|
404
|
+
expect(valid_params[details_category_key][:nodoc]).to be_truthy
|
405
|
+
|
406
|
+
details_data_key = valid_params.keys[3]
|
407
|
+
expect(details_data_key.call).to eq('data')
|
408
|
+
expect(valid_params[details_data_key][:nodoc]).to be_truthy
|
409
|
+
|
410
|
+
details_data_raw_text_key = valid_params.keys[4]
|
411
|
+
expect(details_data_raw_text_key.call).to eq('raw_text')
|
412
|
+
expect(valid_params[details_data_raw_text_key][:nodoc]).to be_truthy
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
context "when type is array" do
|
418
|
+
it "sets the type and sub type appropriately" do
|
419
|
+
subject.brainstem_params do
|
420
|
+
valid :sprocket_ids, :array,
|
421
|
+
required: true,
|
422
|
+
item_type: :string
|
423
|
+
end
|
424
|
+
|
425
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
426
|
+
|
427
|
+
sprocket_ids_key = valid_params.keys[0]
|
428
|
+
expect(sprocket_ids_key.call).to eq('sprocket_ids')
|
429
|
+
|
430
|
+
sprocket_ids_config = valid_params[sprocket_ids_key]
|
431
|
+
expect(sprocket_ids_config[:required]).to be_truthy
|
432
|
+
expect(sprocket_ids_config[:type]).to eq('array')
|
433
|
+
expect(sprocket_ids_config[:item_type]).to eq('string')
|
434
|
+
end
|
435
|
+
|
436
|
+
context "when a block is given" do
|
437
|
+
it "sets the type and sub type appropriately" do
|
438
|
+
subject.brainstem_params do
|
439
|
+
valid :sprocket_tasks, :array, required: true, item_type: 'hash' do |param|
|
440
|
+
param.valid :task_id, :integer, required: true
|
441
|
+
param.valid :task_title, :string
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
446
|
+
|
447
|
+
sprocket_tasks_key = valid_params.keys[0]
|
448
|
+
expect(sprocket_tasks_key.call).to eq('sprocket_tasks')
|
449
|
+
|
450
|
+
sprocket_tasks_config = valid_params[sprocket_tasks_key]
|
451
|
+
expect(sprocket_tasks_config[:required]).to be_truthy
|
452
|
+
expect(sprocket_tasks_config[:type]).to eq('array')
|
453
|
+
expect(sprocket_tasks_config[:item_type]).to eq('hash')
|
454
|
+
|
455
|
+
task_id_key = valid_params.keys[1]
|
456
|
+
expect(task_id_key.call).to eq('task_id')
|
457
|
+
|
458
|
+
task_id_config = valid_params[task_id_key]
|
459
|
+
expect(task_id_config[:required]).to be_truthy
|
460
|
+
expect(task_id_config[:type]).to eq('integer')
|
461
|
+
expect(task_id_config[:root]).to be_nil
|
462
|
+
expect(task_id_config[:ancestors]).to eq([sprocket_tasks_key])
|
463
|
+
|
464
|
+
task_title_key = valid_params.keys[2]
|
465
|
+
expect(task_title_key.call).to eq('task_title')
|
466
|
+
|
467
|
+
task_title_config = valid_params[task_title_key]
|
468
|
+
expect(task_title_config[:required]).to be_falsey
|
469
|
+
expect(task_title_config[:type]).to eq('string')
|
470
|
+
expect(task_title_config[:root]).to be_nil
|
471
|
+
expect(task_title_config[:ancestors]).to eq([sprocket_tasks_key])
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
context "deprecated type behavior" do
|
477
|
+
context "when no type is provided" do
|
478
|
+
before do
|
479
|
+
mock(subject).deprecated_type_warning
|
480
|
+
end
|
481
|
+
|
482
|
+
it "defaults to type string" do
|
483
|
+
subject.brainstem_params do
|
484
|
+
valid :sprocket_name, required: true
|
485
|
+
end
|
486
|
+
|
487
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
488
|
+
expect(valid_params.keys.length).to eq(1)
|
489
|
+
expect(valid_params.keys[0].call).to eq("sprocket_name")
|
490
|
+
|
491
|
+
configuration = valid_params[valid_params.keys[0]]
|
492
|
+
expect(configuration[:type]).to eq("string")
|
493
|
+
expect(configuration[:required]).to be_truthy
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
context "when no type and options are provided" do
|
498
|
+
before do
|
499
|
+
mock(subject).deprecated_type_warning
|
500
|
+
end
|
501
|
+
|
502
|
+
it "defaults type to string and sets default options for the param" do
|
503
|
+
subject.brainstem_params do
|
504
|
+
valid :sprocket_name
|
505
|
+
end
|
506
|
+
|
507
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
508
|
+
expect(valid_params.keys.length).to eq(1)
|
509
|
+
expect(valid_params.keys[0].call).to eq("sprocket_name")
|
510
|
+
|
511
|
+
configuration = valid_params[valid_params.keys[0]]
|
512
|
+
expect(configuration[:nodoc]).to be_falsey
|
513
|
+
expect(configuration[:required]).to be_falsey
|
514
|
+
expect(configuration[:type]).to eq("string")
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
context "when type and options are hashes" do
|
519
|
+
before do
|
520
|
+
mock(subject).deprecated_type_warning
|
521
|
+
end
|
522
|
+
|
523
|
+
it "ignores the type and defaults to string" do
|
524
|
+
subject.brainstem_params do
|
525
|
+
valid :sprocket_name, { troll: true }, { required: true }
|
149
526
|
end
|
150
527
|
|
151
|
-
|
152
|
-
|
528
|
+
valid_params = subject.configuration[:_default][:valid_params]
|
529
|
+
expect(valid_params.keys.length).to eq(1)
|
530
|
+
expect(valid_params.keys[0].call).to eq("sprocket_name")
|
531
|
+
|
532
|
+
configuration = valid_params[valid_params.keys[0]]
|
533
|
+
expect(configuration[:nodoc]).to be_falsey
|
534
|
+
expect(configuration[:required]).to be_truthy
|
535
|
+
expect(configuration[:type]).to eq("string")
|
536
|
+
end
|
153
537
|
end
|
154
538
|
end
|
155
539
|
end
|
@@ -276,15 +660,15 @@ module Brainstem
|
|
276
660
|
it "uses the existing context" do
|
277
661
|
subject.brainstem_params do
|
278
662
|
action_context :show do
|
279
|
-
valid :param_1, info: "something"
|
663
|
+
valid :param_1, :integer, info: "something"
|
280
664
|
end
|
281
665
|
|
282
666
|
action_context :show do
|
283
|
-
valid :param_2, info: "something else"
|
667
|
+
valid :param_2, :string, info: "something else"
|
284
668
|
end
|
285
669
|
end
|
286
670
|
|
287
|
-
expect(subject.configuration[:show][:valid_params].keys).to \
|
671
|
+
expect(subject.configuration[:show][:valid_params].keys.map(&:call)).to \
|
288
672
|
eq ["param_1", "param_2"]
|
289
673
|
|
290
674
|
end
|
@@ -297,7 +681,7 @@ module Brainstem
|
|
297
681
|
|
298
682
|
subject.brainstem_params do
|
299
683
|
actions [:show, :index] do
|
300
|
-
valid :param_1, info: "something"
|
684
|
+
valid :param_1, :integer, info: "something"
|
301
685
|
end
|
302
686
|
end
|
303
687
|
end
|
@@ -305,12 +689,12 @@ module Brainstem
|
|
305
689
|
it "allows passing an array" do
|
306
690
|
subject.brainstem_params do
|
307
691
|
actions [:show, :index] do
|
308
|
-
valid :param_1, info: "something"
|
692
|
+
valid :param_1, :string, info: "something"
|
309
693
|
end
|
310
694
|
end
|
311
695
|
|
312
696
|
%w(index show).each do |meth|
|
313
|
-
expect(subject.configuration[meth.to_sym][:valid_params].keys).to \
|
697
|
+
expect(subject.configuration[meth.to_sym][:valid_params].keys.map(&:call)).to \
|
314
698
|
include "param_1"
|
315
699
|
end
|
316
700
|
end
|
@@ -318,17 +702,201 @@ module Brainstem
|
|
318
702
|
it "allows passing multiple symbols" do
|
319
703
|
subject.brainstem_params do
|
320
704
|
actions :show, :index do
|
321
|
-
valid :param_1, "something"
|
705
|
+
valid :param_1, :integer, info: "something"
|
322
706
|
end
|
323
707
|
end
|
324
708
|
|
325
709
|
%w(index show).each do |meth|
|
326
|
-
expect(subject.configuration[meth.to_sym][:valid_params].keys).to \
|
710
|
+
expect(subject.configuration[meth.to_sym][:valid_params].keys.map(&:call)).to \
|
327
711
|
include "param_1"
|
328
712
|
end
|
329
713
|
end
|
330
714
|
end
|
331
715
|
|
716
|
+
describe "#valid_params_tree" do
|
717
|
+
context "when no root is specified" do
|
718
|
+
it "returns the field names as the top level keys" do
|
719
|
+
stub.any_instance_of(subject).action_name { "show" }
|
720
|
+
|
721
|
+
subject.brainstem_params do
|
722
|
+
actions :show do
|
723
|
+
valid :sprocket_ids, :array,
|
724
|
+
info: "sprockets[sprocket_ids] is required",
|
725
|
+
required: true,
|
726
|
+
item_type: :integer
|
727
|
+
|
728
|
+
valid :widget_id, :integer,
|
729
|
+
info: "sprockets[widget_id] is not required"
|
730
|
+
end
|
731
|
+
end
|
732
|
+
|
733
|
+
result = subject.new.valid_params_tree
|
734
|
+
expect(result.keys).to match_array(%w(sprocket_ids widget_id))
|
735
|
+
|
736
|
+
sprocket_ids_config = result[:sprocket_ids][:_config]
|
737
|
+
expect(sprocket_ids_config).to eq({
|
738
|
+
"info" => "sprockets[sprocket_ids] is required",
|
739
|
+
"required" => true,
|
740
|
+
"item_type" => "integer",
|
741
|
+
"nodoc" => false,
|
742
|
+
"type" => "array"
|
743
|
+
})
|
744
|
+
|
745
|
+
widget_id_config = result[:widget_id][:_config]
|
746
|
+
expect(widget_id_config).to eq({
|
747
|
+
"info" => "sprockets[widget_id] is not required",
|
748
|
+
"required" => false,
|
749
|
+
"nodoc" => false,
|
750
|
+
"type" => "integer"
|
751
|
+
})
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
755
|
+
context "when root is specified" do
|
756
|
+
let(:brainstem_model_name) { "widget" }
|
757
|
+
|
758
|
+
it "returns the root as a top level key" do
|
759
|
+
stub(subject).brainstem_model_name { brainstem_model_name }
|
760
|
+
stub.any_instance_of(subject).brainstem_model_name { brainstem_model_name }
|
761
|
+
stub.any_instance_of(subject).action_name { "show" }
|
762
|
+
|
763
|
+
subject.brainstem_params do
|
764
|
+
valid :unrelated_root_key, :string,
|
765
|
+
info: "it's unrelated.",
|
766
|
+
required: true
|
767
|
+
|
768
|
+
model_params(brainstem_model_name) do |params|
|
769
|
+
params.valid :sprocket_parent_id, :long,
|
770
|
+
info: "widget[sprocket_parent_id] is not required"
|
771
|
+
end
|
772
|
+
|
773
|
+
actions :show do
|
774
|
+
model_params(brainstem_model_name) do |params|
|
775
|
+
params.valid :sprocket_name, :string,
|
776
|
+
info: "widget[sprocket_name] is required",
|
777
|
+
required: true
|
778
|
+
end
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
result = subject.new.valid_params_tree
|
783
|
+
expect(result.keys).to match_array(%w(widget unrelated_root_key))
|
784
|
+
expect(result[:widget].keys).to match_array(%w(sprocket_parent_id sprocket_name))
|
785
|
+
|
786
|
+
sprocket_parent_id_config = result[:widget][:sprocket_parent_id][:_config]
|
787
|
+
expect(sprocket_parent_id_config).to eq({
|
788
|
+
"info" => "widget[sprocket_parent_id] is not required",
|
789
|
+
"required" => false,
|
790
|
+
"nodoc" => false,
|
791
|
+
"type" => "long"
|
792
|
+
})
|
793
|
+
|
794
|
+
sprocket_name_config = result[:widget][:sprocket_name][:_config]
|
795
|
+
expect(sprocket_name_config).to eq({
|
796
|
+
"info" => "widget[sprocket_name] is required",
|
797
|
+
"required" => true,
|
798
|
+
"nodoc" => false,
|
799
|
+
"type" => "string"
|
800
|
+
})
|
801
|
+
end
|
802
|
+
end
|
803
|
+
|
804
|
+
context "when multiple fields share the same name" do
|
805
|
+
let(:brainstem_model_name) { "widget" }
|
806
|
+
|
807
|
+
it "retains config for both fields" do
|
808
|
+
stub(subject).brainstem_model_name { brainstem_model_name }
|
809
|
+
stub.any_instance_of(subject).brainstem_model_name { brainstem_model_name }
|
810
|
+
stub.any_instance_of(subject).action_name { "update" }
|
811
|
+
|
812
|
+
subject.brainstem_params do
|
813
|
+
actions :update do
|
814
|
+
valid :id, :integer,
|
815
|
+
info: "ID of the widget.",
|
816
|
+
required: true
|
817
|
+
|
818
|
+
model_params(brainstem_model_name) do |params|
|
819
|
+
params.valid :id, :integer,
|
820
|
+
info: "widget[id] is optional"
|
821
|
+
end
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
result = subject.new.valid_params_tree
|
826
|
+
expect(result.keys).to match_array(%w(widget id))
|
827
|
+
expect(result[:widget].keys).to match_array(%w(id))
|
828
|
+
|
829
|
+
id_param_config = result[:id][:_config]
|
830
|
+
expect(id_param_config).to eq({
|
831
|
+
"info" => "ID of the widget.",
|
832
|
+
"required" => true,
|
833
|
+
"nodoc" => false,
|
834
|
+
"type" => "integer"
|
835
|
+
})
|
836
|
+
|
837
|
+
nested_id_param_config = result[:widget][:id][:_config]
|
838
|
+
expect(nested_id_param_config).to eq({
|
839
|
+
"info" => "widget[id] is optional",
|
840
|
+
"required" => false,
|
841
|
+
"nodoc" => false,
|
842
|
+
"type" => "integer"
|
843
|
+
})
|
844
|
+
end
|
845
|
+
end
|
846
|
+
|
847
|
+
context "when multiple nested params are specified" do
|
848
|
+
let(:brainstem_model_name) { "widget" }
|
849
|
+
|
850
|
+
it "retains config for both fields" do
|
851
|
+
stub(subject).brainstem_model_name { brainstem_model_name }
|
852
|
+
stub.any_instance_of(subject).brainstem_model_name { brainstem_model_name }
|
853
|
+
stub.any_instance_of(subject).action_name { "update" }
|
854
|
+
|
855
|
+
subject.brainstem_params do
|
856
|
+
actions :update do
|
857
|
+
model_params(brainstem_model_name) do |params|
|
858
|
+
params.valid :title, :string,
|
859
|
+
info: "widget[title] is required",
|
860
|
+
required: true
|
861
|
+
|
862
|
+
params.valid :sprocket, :hash do |nested_params|
|
863
|
+
nested_params.valid :name, :string,
|
864
|
+
info: "sprocket[name] is optional"
|
865
|
+
end
|
866
|
+
end
|
867
|
+
end
|
868
|
+
end
|
869
|
+
|
870
|
+
result = subject.new.valid_params_tree
|
871
|
+
expect(result.keys).to match_array(%w(widget))
|
872
|
+
expect(result[:widget].keys).to match_array(%w(title sprocket))
|
873
|
+
|
874
|
+
title_param_config = result[:widget][:title][:_config]
|
875
|
+
expect(title_param_config).to eq({
|
876
|
+
"info" => "widget[title] is required",
|
877
|
+
"required" => true,
|
878
|
+
"nodoc" => false,
|
879
|
+
"type" => "string"
|
880
|
+
})
|
881
|
+
|
882
|
+
sprocket_param_config = result[:widget][:sprocket][:_config]
|
883
|
+
expect(sprocket_param_config).to eq({
|
884
|
+
"required" => false,
|
885
|
+
"nodoc" => false,
|
886
|
+
"type" => "hash"
|
887
|
+
})
|
888
|
+
|
889
|
+
sprocket_name_param_config = result[:widget][:sprocket][:name][:_config]
|
890
|
+
expect(sprocket_name_param_config).to eq({
|
891
|
+
"info" => "sprocket[name] is optional",
|
892
|
+
"required" => false,
|
893
|
+
"nodoc" => false,
|
894
|
+
"type" => "string"
|
895
|
+
})
|
896
|
+
end
|
897
|
+
end
|
898
|
+
end
|
899
|
+
|
332
900
|
describe "#brainstem_valid_params" do
|
333
901
|
let(:brainstem_model_name) { "widget" }
|
334
902
|
|
@@ -337,18 +905,20 @@ module Brainstem
|
|
337
905
|
stub.any_instance_of(subject).brainstem_model_name { brainstem_model_name }
|
338
906
|
|
339
907
|
subject.brainstem_params do
|
340
|
-
valid :unrelated_root_key,
|
341
|
-
info: "it's unrelated."
|
908
|
+
valid :unrelated_root_key, :string,
|
909
|
+
info: "it's unrelated.",
|
910
|
+
required: true
|
342
911
|
|
343
912
|
model_params(brainstem_model_name) do |params|
|
344
|
-
params.valid :sprocket_parent_id,
|
345
|
-
info: "sprockets[sprocket_parent_id] is required"
|
913
|
+
params.valid :sprocket_parent_id, :long,
|
914
|
+
info: "sprockets[sprocket_parent_id] is not required"
|
346
915
|
end
|
347
916
|
|
348
917
|
actions :show do
|
349
918
|
model_params(brainstem_model_name) do |params|
|
350
|
-
params.valid :sprocket_name,
|
351
|
-
info: "sprockets[sprocket_name] is required"
|
919
|
+
params.valid :sprocket_name, :string,
|
920
|
+
info: "sprockets[sprocket_name] is required",
|
921
|
+
required: true
|
352
922
|
end
|
353
923
|
end
|
354
924
|
end
|
@@ -359,7 +929,7 @@ module Brainstem
|
|
359
929
|
|
360
930
|
subject.brainstem_params do
|
361
931
|
model_params Proc.new { |k| k.arbitrary_method } do |params|
|
362
|
-
params.valid :nested_key, info: "it's nested!"
|
932
|
+
params.valid :nested_key, :hash, info: "it's nested!"
|
363
933
|
end
|
364
934
|
end
|
365
935
|
|
@@ -371,8 +941,22 @@ module Brainstem
|
|
371
941
|
stub.any_instance_of(subject).action_name { "show" }
|
372
942
|
|
373
943
|
expect(subject.new.brainstem_valid_params).to eq({
|
374
|
-
"sprocket_name" => {
|
375
|
-
|
944
|
+
"sprocket_name" => {
|
945
|
+
"_config" => {
|
946
|
+
"info" => "sprockets[sprocket_name] is required",
|
947
|
+
"required" => true,
|
948
|
+
"type" => "string",
|
949
|
+
"nodoc" => false
|
950
|
+
}
|
951
|
+
},
|
952
|
+
"sprocket_parent_id" => {
|
953
|
+
"_config" => {
|
954
|
+
"info" => "sprockets[sprocket_parent_id] is not required",
|
955
|
+
"type" => "long",
|
956
|
+
"nodoc" => false,
|
957
|
+
"required" => false
|
958
|
+
}
|
959
|
+
}
|
376
960
|
})
|
377
961
|
end
|
378
962
|
|