brainstem 1.1.1 → 1.3.0
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 +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
|
|