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
@@ -129,19 +129,40 @@ module Brainstem
|
|
129
129
|
|
130
130
|
|
131
131
|
describe "#format_params!" do
|
132
|
+
let(:const) do
|
133
|
+
Class.new do
|
134
|
+
def self.brainstem_model_name
|
135
|
+
:widget
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
132
140
|
before do
|
141
|
+
stub(controller).const { const }
|
142
|
+
|
133
143
|
subject.send(:format_params!)
|
134
144
|
end
|
135
145
|
|
136
|
-
|
137
146
|
context "with valid params" do
|
138
|
-
let(:
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
147
|
+
let(:root_proc) { Proc.new { "widget" } }
|
148
|
+
let(:sprocket_id_proc) { Proc.new { "sprocket_id" } }
|
149
|
+
let(:sprocket_child_proc) { Proc.new { "sprocket_child" } }
|
150
|
+
let(:default_show_config) {
|
151
|
+
{
|
152
|
+
valid_params: {
|
153
|
+
only: {
|
154
|
+
info: "which ids to include", nodoc: nodoc, type: "array", item_type: "integer"
|
155
|
+
},
|
156
|
+
sprocket_id_proc => {
|
157
|
+
info: "the id of the sprocket", root: root_proc, ancestors: [root_proc], nodoc: nodoc, type: "integer"
|
158
|
+
},
|
159
|
+
sprocket_child_proc => {
|
160
|
+
recursive: true, legacy: false, info: "it does the thing", root: root_proc, ancestors: [root_proc], type: "string"
|
161
|
+
},
|
162
|
+
}
|
143
163
|
}
|
144
|
-
}
|
164
|
+
}
|
165
|
+
let(:show_config) { default_show_config }
|
145
166
|
|
146
167
|
context "when nodoc" do
|
147
168
|
let(:nodoc) { true }
|
@@ -169,12 +190,18 @@ module Brainstem
|
|
169
190
|
|
170
191
|
context "for non-root params" do
|
171
192
|
it "outputs sub params under a list item" do
|
172
|
-
expect(subject.output).to include "- `widget
|
193
|
+
expect(subject.output).to include "- `widget` (`Hash`)\n - `sprocket_id` (`Integer`) - the id of the sprocket\n - `sprocket_child` (`String`)"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context "for params with type array" do
|
198
|
+
it "outputs item type along with the field type" do
|
199
|
+
expect(subject.output).to include "- `only` (`Array<Integer>`) - which ids to include\n"
|
173
200
|
end
|
174
201
|
end
|
175
202
|
|
176
203
|
it "includes the info on a hash key" do
|
177
|
-
expect(subject.output).to include "`sprocket_child` - it does the thing"
|
204
|
+
expect(subject.output).to include "`sprocket_child` (`String`) - it does the thing"
|
178
205
|
end
|
179
206
|
|
180
207
|
it "includes the recursivity if specified" do
|
@@ -184,14 +211,82 @@ module Brainstem
|
|
184
211
|
it "includes the legacy status if specified" do
|
185
212
|
expect(subject.output).to include "Legacy: false"
|
186
213
|
end
|
214
|
+
|
215
|
+
context "when required option is specified" do
|
216
|
+
let(:show_config) {
|
217
|
+
default_show_config.tap do |config|
|
218
|
+
config[:valid_params][sprocket_id_proc][:required] = required
|
219
|
+
end
|
220
|
+
}
|
221
|
+
|
222
|
+
context "when required is true" do
|
223
|
+
let(:required) { true }
|
224
|
+
|
225
|
+
it "includes if required" do
|
226
|
+
expect(subject.output).to include "Required: true"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
context "when required is false" do
|
231
|
+
let(:required) { false }
|
232
|
+
|
233
|
+
it "includes if required" do
|
234
|
+
expect(subject.output).to_not include "Required"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
context "with multiple levels of nested params" do
|
240
|
+
let(:sprocket_template_proc) { Proc.new { "sprocket_template" } }
|
241
|
+
let(:sprocket_template_json_proc) { Proc.new { "sprocket_template_json" } }
|
242
|
+
let(:sprocket_template_title_proc) { Proc.new { "sprocket_template_title" } }
|
243
|
+
let(:multi_nested_params) {
|
244
|
+
{
|
245
|
+
sprocket_template_proc => {
|
246
|
+
info: "the template for the sprocket",
|
247
|
+
type: "hash",
|
248
|
+
root: root_proc,
|
249
|
+
ancestors: [root_proc]
|
250
|
+
},
|
251
|
+
sprocket_template_json_proc => {
|
252
|
+
info: "the json blob of the sprocket template",
|
253
|
+
type: "string",
|
254
|
+
ancestors: [root_proc, sprocket_template_proc]
|
255
|
+
},
|
256
|
+
sprocket_template_title_proc => {
|
257
|
+
info: "the title of the sprocket template",
|
258
|
+
type: "string",
|
259
|
+
ancestors: [root_proc, sprocket_template_proc]
|
260
|
+
}
|
261
|
+
}
|
262
|
+
}
|
263
|
+
let(:show_config) {
|
264
|
+
default_show_config.tap do |config|
|
265
|
+
config[:valid_params].merge!(multi_nested_params)
|
266
|
+
end
|
267
|
+
}
|
268
|
+
|
269
|
+
it "outputs sub params under a list item" do
|
270
|
+
output = subject.output
|
271
|
+
expect(output).to include("##### Valid Parameters\n\n")
|
272
|
+
expect(output).to include("- `only` (`Array<Integer>`) - which ids to include\n")
|
273
|
+
expect(output).to include("- `widget` (`Hash`)\n")
|
274
|
+
expect(output).to include(" - `sprocket_id` (`Integer`) - the id of the sprocket\n")
|
275
|
+
expect(output).to include(" - `sprocket_child` (`String`) - it does the thing\n")
|
276
|
+
expect(output).to include(" - Legacy: false\n")
|
277
|
+
expect(output).to include(" - Recursive: true\n")
|
278
|
+
expect(output).to include(" - `sprocket_template` (`Hash`) - the template for the sprocket\n")
|
279
|
+
expect(output).to include(" - `sprocket_template_json` (`String`) - the json blob of the sprocket template\n")
|
280
|
+
expect(output).to include(" - `sprocket_template_title` (`String`) - the title of the sprocket template\n\n\n")
|
281
|
+
end
|
282
|
+
end
|
187
283
|
end
|
188
284
|
end
|
189
285
|
|
190
|
-
|
191
286
|
context "with only default params" do
|
192
287
|
let(:default_config) { {
|
193
288
|
valid_params: {
|
194
|
-
sprocket_name
|
289
|
+
Proc.new { "sprocket_name" } => {
|
195
290
|
info: "the name of the sprocket",
|
196
291
|
nodoc: nodoc
|
197
292
|
}
|
@@ -218,10 +313,8 @@ module Brainstem
|
|
218
313
|
expect(subject.output).to eq ""
|
219
314
|
end
|
220
315
|
end
|
221
|
-
|
222
316
|
end
|
223
317
|
|
224
|
-
|
225
318
|
describe "#format_presents!" do
|
226
319
|
let(:presenter) { Object.new }
|
227
320
|
|
@@ -93,6 +93,25 @@ module Brainstem
|
|
93
93
|
expect(subject.md_a("text", "link.md")).to eq "[text](link.md)"
|
94
94
|
end
|
95
95
|
end
|
96
|
+
|
97
|
+
|
98
|
+
describe "#md_inline_type" do
|
99
|
+
it "renders the code between single backticks" do
|
100
|
+
expect(subject.md_inline_type("string")).to eq " (`String`)"
|
101
|
+
end
|
102
|
+
|
103
|
+
context "when type is blank" do
|
104
|
+
it "returns an empty string" do
|
105
|
+
expect(subject.md_inline_type("")).to eq ""
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when item type is specified" do
|
110
|
+
it "renders the code between single backticks" do
|
111
|
+
expect(subject.md_inline_type("array", "integer")).to eq " (`Array<Integer>`)"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
96
115
|
end
|
97
116
|
end
|
98
117
|
end
|
@@ -54,7 +54,6 @@ module Brainstem
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
|
58
57
|
describe "formatting" do
|
59
58
|
let(:lorem) { "lorem ipsum dolor sit amet" }
|
60
59
|
|
@@ -110,39 +109,39 @@ module Brainstem
|
|
110
109
|
|
111
110
|
|
112
111
|
describe "#format_fields!" do
|
113
|
-
let(:
|
112
|
+
let(:presenter_class) do
|
113
|
+
Class.new(Brainstem::Presenter) do
|
114
|
+
presents Workspace
|
115
|
+
end
|
116
|
+
end
|
117
|
+
let(:presenter) { Presenter.new(Object.new, const: presenter_class, target_class: 'Workspace') }
|
114
118
|
let(:conditionals) { {} }
|
115
|
-
let(:optional) { false }
|
116
|
-
|
117
|
-
let(:sprocket_name_long) { OpenStruct.new(
|
118
|
-
name: :sprocket_name,
|
119
|
-
description: lorem,
|
120
|
-
options: { via: :name },
|
121
|
-
type: :string
|
122
|
-
) }
|
123
|
-
|
124
|
-
let(:sprocket_name_short) { OpenStruct.new(
|
125
|
-
name: :sprocket_name,
|
126
|
-
type: :string,
|
127
|
-
options: { }
|
128
|
-
) }
|
129
119
|
|
130
120
|
before do
|
131
|
-
stub(
|
132
|
-
stub(sprocket_name_short).optional? { optional }
|
133
|
-
stub(presenter).conditionals { conditionals }
|
134
|
-
stub(presenter).valid_fields { valid_fields }
|
135
|
-
subject.send(:format_fields!)
|
121
|
+
stub(presenter).conditionals { conditionals }
|
136
122
|
end
|
137
123
|
|
138
124
|
it "outputs a header" do
|
125
|
+
presenter_class.fields do
|
126
|
+
field :name, :string
|
127
|
+
end
|
128
|
+
subject.send(:format_fields!)
|
129
|
+
|
139
130
|
expect(subject.output).to include "Fields"
|
140
131
|
end
|
141
132
|
|
142
133
|
context "with fields present" do
|
143
134
|
context "branch node" do
|
144
135
|
context "with single branch" do
|
145
|
-
|
136
|
+
before do
|
137
|
+
presenter_class.fields do
|
138
|
+
fields :sprockets do
|
139
|
+
field :sprocket_name, :string, via: :name, info: "whatever"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
subject.send(:format_fields!)
|
144
|
+
end
|
146
145
|
|
147
146
|
it "outputs the name of the branch as a list item" do
|
148
147
|
expect(subject.output.scan(/\n-/).count).to eq 1
|
@@ -151,13 +150,22 @@ module Brainstem
|
|
151
150
|
end
|
152
151
|
|
153
152
|
it "outputs the child nodes as sub-list items" do
|
154
|
-
expect(subject.output).to \
|
155
|
-
include("\n- `sprockets`\n - `sprocket_name`")
|
153
|
+
expect(subject.output).to include("\n- `sprockets` (`Hash`)\n - `sprocket_name`")
|
156
154
|
end
|
157
155
|
end
|
158
156
|
|
159
157
|
context "with sub-branch" do
|
160
|
-
|
158
|
+
before do
|
159
|
+
presenter_class.fields do
|
160
|
+
fields :sprockets do
|
161
|
+
fields :sub_sprocket do
|
162
|
+
field :sprocket_name, :string, via: :name, info: "whatever"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
subject.send(:format_fields!)
|
168
|
+
end
|
161
169
|
|
162
170
|
it "outputs the name of sub-branches as a sub-list item" do
|
163
171
|
expect(subject.output.scan(/\n-/).count).to eq 1
|
@@ -168,13 +176,60 @@ module Brainstem
|
|
168
176
|
|
169
177
|
it "outputs the child nodes as sub-list items" do
|
170
178
|
expect(subject.output).to \
|
171
|
-
include("\n- `sprockets
|
179
|
+
include("\n- `sprockets` (`Hash`)\n - `sub_sprocket` (`Hash`)\n - `sprocket_name`")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "when branch has properties" do
|
184
|
+
let(:conditionals) do
|
185
|
+
{
|
186
|
+
:it_is_a_friday => OpenStruct.new(
|
187
|
+
description: "it is a friday",
|
188
|
+
name: :it_is_a_friday,
|
189
|
+
type: :request,
|
190
|
+
options: {}
|
191
|
+
)
|
192
|
+
}
|
193
|
+
end
|
194
|
+
|
195
|
+
before do
|
196
|
+
presenter_class.fields do
|
197
|
+
fields :sprockets, :array, info: "parent", if: :it_is_a_friday do
|
198
|
+
field :sprocket_name, :string, via: :name, info: "whatever"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
subject.send(:format_fields!)
|
203
|
+
end
|
204
|
+
|
205
|
+
it "outputs the name of the branch as a list item" do
|
206
|
+
expect(subject.output.scan(/\n-/).count).to eq 1
|
207
|
+
expect(subject.output.scan(/\n -/).count).to eq 3
|
208
|
+
expect(subject.output.scan(/\n -/).count).to eq 2
|
209
|
+
end
|
210
|
+
|
211
|
+
it "outputs the parent node with its properties" do
|
212
|
+
result = subject.output
|
213
|
+
|
214
|
+
expect(result).to include("##### Fields\n\n")
|
215
|
+
expect(result).to include("- `sprockets` (`Array`)\n")
|
216
|
+
expect(result).to include(" - parent\n")
|
217
|
+
expect(result).to include(" - visible when it is a friday\n")
|
218
|
+
expect(result).to include(" - `sprocket_name` (`String`)\n")
|
219
|
+
expect(result).to include(" - whatever\n")
|
220
|
+
expect(result).to include(" - visible when it is a friday\n\n\n\n")
|
172
221
|
end
|
173
222
|
end
|
174
223
|
end
|
175
224
|
|
176
225
|
context "leaf node" do
|
177
|
-
|
226
|
+
before do
|
227
|
+
presenter_class.fields do
|
228
|
+
field :sprocket_name, :string, via: :name
|
229
|
+
end
|
230
|
+
|
231
|
+
subject.send(:format_fields!)
|
232
|
+
end
|
178
233
|
|
179
234
|
context "if it is not conditional" do
|
180
235
|
it "outputs each field as a list item" do
|
@@ -191,7 +246,16 @@ module Brainstem
|
|
191
246
|
|
192
247
|
describe "optional" do
|
193
248
|
context "when true" do
|
194
|
-
|
249
|
+
before do
|
250
|
+
presenter_class.fields do
|
251
|
+
field :sprocket_name, :string,
|
252
|
+
info: "lorem ipsum dolor sit amet",
|
253
|
+
optional: true,
|
254
|
+
via: :name
|
255
|
+
end
|
256
|
+
|
257
|
+
subject.send(:format_fields!)
|
258
|
+
end
|
195
259
|
|
196
260
|
it "says so" do
|
197
261
|
expect(subject.output).to include "only returned when requested"
|
@@ -208,29 +272,58 @@ module Brainstem
|
|
208
272
|
|
209
273
|
describe "description" do
|
210
274
|
context "when present" do
|
275
|
+
before do
|
276
|
+
presenter_class.fields do
|
277
|
+
field :sprocket_name, :string, info: "lorem ipsum dolor sit amet"
|
278
|
+
end
|
279
|
+
|
280
|
+
subject.send(:format_fields!)
|
281
|
+
end
|
282
|
+
|
211
283
|
it "outputs the description" do
|
212
284
|
expect(subject.output).to include " - #{lorem}"
|
213
285
|
end
|
214
286
|
end
|
215
287
|
|
216
288
|
context "when absent" do
|
217
|
-
|
289
|
+
before do
|
290
|
+
presenter_class.fields do
|
291
|
+
field :sprocket_name, :string
|
292
|
+
end
|
293
|
+
|
294
|
+
subject.send(:format_fields!)
|
295
|
+
end
|
218
296
|
|
219
297
|
it "does not include the description" do
|
220
298
|
expect(subject.output).not_to include " -"
|
221
299
|
end
|
222
300
|
end
|
223
301
|
end
|
302
|
+
|
303
|
+
describe "when field has an item type" do
|
304
|
+
before do
|
305
|
+
presenter_class.fields do
|
306
|
+
field :sprocket_ids, :array, item_type: :integer
|
307
|
+
end
|
308
|
+
|
309
|
+
subject.send(:format_fields!)
|
310
|
+
end
|
311
|
+
|
312
|
+
it "outputs each field's type along with the sub item type" do
|
313
|
+
expect(subject.output).to include "`sprocket_ids` (`Array<Integer>`)"
|
314
|
+
end
|
315
|
+
end
|
224
316
|
end
|
225
317
|
|
226
318
|
|
227
319
|
context "if it is conditional" do
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
320
|
+
before do
|
321
|
+
presenter_class.fields do
|
322
|
+
field :sprocket_name, :string, if: :it_is_a_friday
|
323
|
+
end
|
324
|
+
|
325
|
+
subject.send(:format_fields!)
|
326
|
+
end
|
234
327
|
|
235
328
|
context "if nodoc" do
|
236
329
|
let(:conditionals) { {
|
@@ -303,8 +396,9 @@ module Brainstem
|
|
303
396
|
let(:valid_filters) {
|
304
397
|
{
|
305
398
|
"published" => {
|
399
|
+
type: "string",
|
306
400
|
value: Proc.new { nil },
|
307
|
-
info:
|
401
|
+
info: "limits to published"
|
308
402
|
}
|
309
403
|
}
|
310
404
|
}
|
@@ -315,9 +409,28 @@ module Brainstem
|
|
315
409
|
|
316
410
|
it "lists them" do
|
317
411
|
expect(subject.output.scan(/\n-/).count).to eq 1
|
318
|
-
expect(subject.output).to include "`published`"
|
412
|
+
expect(subject.output).to include "`published` (`String`)"
|
319
413
|
expect(subject.output).to include " - limits to published"
|
320
414
|
end
|
415
|
+
|
416
|
+
context "when items specified" do
|
417
|
+
let(:valid_filters) {
|
418
|
+
{
|
419
|
+
"published" => {
|
420
|
+
type: "string",
|
421
|
+
value: Proc.new { nil },
|
422
|
+
info: "limits to published",
|
423
|
+
items: ["fizz", "buzz"]
|
424
|
+
}
|
425
|
+
}
|
426
|
+
}
|
427
|
+
|
428
|
+
it "lists them with items" do
|
429
|
+
expect(subject.output.scan(/\n-/).count).to eq 1
|
430
|
+
expect(subject.output).to include "`published` (`String`)"
|
431
|
+
expect(subject.output).to include " - limits to published. Available values: fizz, buzz."
|
432
|
+
end
|
433
|
+
end
|
321
434
|
end
|
322
435
|
|
323
436
|
context "when no filters" do
|