brainstem 2.0.0 → 2.1.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +147 -0
  3. data/Gemfile.lock +68 -39
  4. data/lib/brainstem/api_docs.rb +9 -4
  5. data/lib/brainstem/api_docs/atlas.rb +3 -3
  6. data/lib/brainstem/api_docs/controller.rb +12 -4
  7. data/lib/brainstem/api_docs/controller_collection.rb +11 -2
  8. data/lib/brainstem/api_docs/endpoint.rb +17 -7
  9. data/lib/brainstem/api_docs/endpoint_collection.rb +9 -1
  10. data/lib/brainstem/api_docs/formatters/open_api_specification/helper.rb +19 -16
  11. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/param_definitions_formatter.rb +52 -80
  12. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/response_definitions_formatter.rb +64 -84
  13. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint_formatter.rb +1 -1
  14. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/endpoint_param_formatter.rb +39 -0
  15. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/presenter_field_formatter.rb +147 -0
  16. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/response_field_formatter.rb +146 -0
  17. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/presenter_formatter.rb +53 -55
  18. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/tags_formatter.rb +1 -1
  19. data/lib/brainstem/api_docs/presenter.rb +16 -8
  20. data/lib/brainstem/api_docs/presenter_collection.rb +8 -5
  21. data/lib/brainstem/api_docs/sinks/open_api_specification_sink.rb +3 -1
  22. data/lib/brainstem/cli/generate_api_docs_command.rb +4 -0
  23. data/lib/brainstem/concerns/controller_dsl.rb +90 -20
  24. data/lib/brainstem/concerns/presenter_dsl.rb +16 -8
  25. data/lib/brainstem/dsl/association.rb +12 -0
  26. data/lib/brainstem/dsl/fields_block.rb +1 -1
  27. data/lib/brainstem/version.rb +1 -1
  28. data/spec/brainstem/api_docs/controller_spec.rb +127 -5
  29. data/spec/brainstem/api_docs/endpoint_spec.rb +489 -57
  30. data/spec/brainstem/api_docs/formatters/open_api_specification/helper_spec.rb +15 -4
  31. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/param_definitions_formatter_spec.rb +112 -66
  32. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/response_definitions_formatter_spec.rb +404 -32
  33. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/endpoint_param_formatter_spec.rb +335 -0
  34. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/presenter_field_formatter_spec.rb +237 -0
  35. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/field_definitions/response_field_formatter_spec.rb +413 -0
  36. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/presenter_formatter_spec.rb +116 -4
  37. data/spec/brainstem/api_docs/presenter_spec.rb +406 -24
  38. data/spec/brainstem/cli/generate_api_docs_command_spec.rb +8 -0
  39. data/spec/brainstem/concerns/controller_dsl_spec.rb +606 -45
  40. data/spec/brainstem/concerns/presenter_dsl_spec.rb +34 -2
  41. data/spec/brainstem/dsl/association_spec.rb +54 -3
  42. metadata +11 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9abf1184c78ea43d4e00ae5aa6f2a11fdb663013
4
- data.tar.gz: 421ffc9a7dd8cce73ad64bcadd40a4108b79c7bf
3
+ metadata.gz: e825c08d783b4cecd7da03879db5545efd3e0697
4
+ data.tar.gz: 1478c23f3186dd7d065585d102245e995e6d9df5
5
5
  SHA512:
6
- metadata.gz: 8a230a3bbe9bee9643bc96a6b894a8e86669483b1057cb6d7131a3c0ed34817b81739bb1cdc8bc15e64d6c3ca50a84a947133cb68bf3ebbdea702769f5542f59
7
- data.tar.gz: 0b20e2fc89ce9d3b5ac655b959ca56779d37fc2c22ed2e229666d65925932a46fae573e1ef56b7c15ead24c5fe1d8b8e4109523b531d2c273ee9eecc45549e81
6
+ metadata.gz: 27a6f03a61dcd1371ffe0b7860563fe8ba94b6be14814f21ae35f4230d2af65fdcf1790f8a547c5913d11611a4ded52e8f17136cd6b6efb4d8a32adf40b1680c
7
+ data.tar.gz: 501e3164fade58216384cc7ddfe32a07e009af99029a75ddd0f1db19d770e356983af1d4786953997ff18ce3ea03a55e376db05a784db06088e0e3090b131b84
@@ -1,5 +1,151 @@
1
1
  # Changelog
2
2
 
3
+ + **2.1.0** - _05/10/2019_
4
+ ### New Features
5
+ - Add the ability to mark properties as internal for Open API.
6
+ ```ruby
7
+ class ContactsController < ApiController
8
+ internal! "Only used internally"
9
+
10
+ brainstem_params do
11
+ actions :index do
12
+ response :hash do
13
+ field :count, :integer,
14
+ info: "Total count of contacts",
15
+ internal: "Internal eyes only"
16
+ fields :contacts, :array,
17
+ item_type: :hash,
18
+ nodoc: true,
19
+ info: "Array of contact details" do
20
+ field :full_name, :string,
21
+ info: "Full name of the contact",
22
+ internal: true
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ ```
29
+
30
+ - Add `--include-internal` option to CLI:
31
+ `brainstem generate --include-internal --open-api-specification=2` will generate documentation for
32
+ everything that is not marked as `nodoc`.
33
+
34
+ - Automatically generate documentation for associations
35
+ - `response_key` will be used if given, otherwise, it will use the name of the association appended
36
+ with `_id` or `_ids` for `has_many`.
37
+
38
+ Using the example below, the association for `PetCategory` will generate documentation for `shooby_id`,
39
+ while the `Owner` association will generate documentation for `owner_id`.
40
+ - The response will include references to all of the associations, including any `polymorphic_classes` added to
41
+ polymorphic associations.
42
+
43
+ In the example below, the documentation for the response will contain references to `PetCategory`, `Vaccine`,
44
+ `Owner`, `Dog`, and `Cat`.
45
+
46
+ ```ruby
47
+ class PetsPresenter < Brainstem::Presenter
48
+ presents Pet
49
+
50
+ associations do
51
+ association :pet_category, PetCategory,
52
+ response_key: :shooby_id,
53
+ type: :belongs_to
54
+ association :vaccines, Vaccine,
55
+ response_key: :vaccine_ids,
56
+ type: :has_many
57
+ association :owner, Owner,
58
+ response_key: :owner_id,
59
+ type: :has_one
60
+ association :pettable, :polymorphic,
61
+ response_key: :pettable_ref,
62
+ polymorphic_classes: [Dog, Cat]
63
+ end
64
+ end
65
+ ```
66
+
67
+ - Add support for non-static key fields in responses. When key is non-static, use the new DSL for response params.
68
+ See example below for usage.
69
+
70
+ ```ruby
71
+ {
72
+ :attributes => {
73
+ :"#{name}_field" => 'world',
74
+ :"#{name}_ids" => [1, 2, 3],
75
+ :name => name
76
+ },
77
+ :"#{model.class_name}_klass" => {
78
+ :"#{model.class_name}_identifier" => model.identifier,
79
+ :"#{model.association_name}_ids" => [1, 2, 3]
80
+ }
81
+ }
82
+ ```
83
+
84
+ A response with non-static key fields written above can be described as follows:
85
+
86
+ ```ruby
87
+ class ContactsController < ApiController
88
+ brainstem_params do
89
+ actions :show do
90
+ response :hash do |response_param|
91
+ response_param.fields :attributes, :hash do |attributes|
92
+ attributes.dynamic_key_field :string
93
+ attributes.field :some_ids, :array, dynamic: true
94
+ attributes.field :name, :string, required: true
95
+ end
96
+
97
+ response_param.dynamic_key_field :hash do |dk|
98
+ dk.dynamic_key_field :string
99
+ dk.field :other_ids, :array, dynamic: true
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ ```
106
+
107
+ - Add support for non-static key params. When key is non-static, use the new DSL for request params.
108
+ See example below for usage.
109
+
110
+ A param with non-static keys like `{ contact.id => 10, :"#{contact.friends_association_name}_ids" => [1, 2, 3] }`
111
+ can be described as follows:
112
+
113
+ ```ruby
114
+ class ContactsController < ApiController
115
+ brainstem_params do
116
+ actions :create do
117
+ valid :info, :hash, required: true do |param|
118
+ param.valid_dynamic_param :integer, required: true
119
+ param.valid :some_ids, :array, dynamic: true
120
+ end
121
+ end
122
+ end
123
+ end
124
+ ```
125
+
126
+ - Sort orders now default to directions `asc` and `desc`.
127
+ When direction is passed as false, no sort order is generated for the docs.
128
+ - ex.
129
+ ```ruby
130
+ presenter_class.sort_order :created_at, value, info: "sorts by creation time", direction: false
131
+ ```
132
+
133
+ - Add new DSL for nested arrays
134
+ ```ruby
135
+ response :array, nested_level: 2, item_type: :hash do
136
+ nested.field :a, :string
137
+ nested.field :b, :integer
138
+ end
139
+ ```
140
+ - An example of the response above: `[[{a: "string", b: 1}, "another string", 4]]`
141
+
142
+ ### Bugfixes
143
+ - Nested required fields will now no longer bubble up the required to its parent. A deeply nested field that is
144
+ required will now only be required on its direct parent.
145
+ - Required fields for a create / update (POST / PUT) request are explicitly called out in the OAS specification
146
+ - Default top-level query params like `only `, `order `, `page`, `per_page`, `include` & `optional` are not
147
+ displayed when the endpoint is not returning brainstem models.
148
+
3
149
  + **2.0.0** - _05/17/2018_
4
150
  - Introduce the capability to document custom response on endpoints
5
151
  ```ruby
@@ -20,6 +166,7 @@
20
166
  end
21
167
  end
22
168
  end
169
+ end
23
170
  ```
24
171
  - Add DSL on controllers to set Open API Specification 2.0 configurations
25
172
  ```ruby
@@ -1,70 +1,99 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- brainstem (1.4.1)
4
+ brainstem (2.2.0)
5
5
  activerecord (>= 4.1)
6
6
  activesupport (>= 4.1)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (5.1.4)
12
- activesupport (= 5.1.4)
13
- activerecord (5.1.4)
14
- activemodel (= 5.1.4)
15
- activesupport (= 5.1.4)
16
- arel (~> 8.0)
17
- activesupport (5.1.4)
11
+ actionpack (5.2.3)
12
+ actionview (= 5.2.3)
13
+ activesupport (= 5.2.3)
14
+ rack (~> 2.0)
15
+ rack-test (>= 0.6.3)
16
+ rails-dom-testing (~> 2.0)
17
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
18
+ actionview (5.2.3)
19
+ activesupport (= 5.2.3)
20
+ builder (~> 3.1)
21
+ erubi (~> 1.4)
22
+ rails-dom-testing (~> 2.0)
23
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
24
+ activemodel (5.2.3)
25
+ activesupport (= 5.2.3)
26
+ activerecord (5.2.3)
27
+ activemodel (= 5.2.3)
28
+ activesupport (= 5.2.3)
29
+ arel (>= 9.0)
30
+ activesupport (5.2.3)
18
31
  concurrent-ruby (~> 1.0, >= 1.0.2)
19
- i18n (~> 0.7)
32
+ i18n (>= 0.7, < 2)
20
33
  minitest (~> 5.1)
21
34
  tzinfo (~> 1.1)
22
- arel (8.0.0)
35
+ arel (9.0.0)
36
+ builder (3.2.3)
23
37
  coderay (1.1.2)
24
- concurrent-ruby (1.0.5)
25
- database_cleaner (1.6.1)
38
+ concurrent-ruby (1.1.5)
39
+ crass (1.0.4)
40
+ database_cleaner (1.7.0)
26
41
  db-query-matchers (0.9.0)
27
42
  activesupport (>= 4.0, <= 6.0)
28
43
  rspec (~> 3.0)
29
44
  diff-lcs (1.3)
30
- i18n (0.9.0)
45
+ erubi (1.8.0)
46
+ i18n (1.6.0)
31
47
  concurrent-ruby (~> 1.0)
32
- method_source (0.9.0)
33
- minitest (5.10.3)
48
+ loofah (2.2.3)
49
+ crass (~> 1.0.2)
50
+ nokogiri (>= 1.5.9)
51
+ method_source (0.9.2)
52
+ mini_portile2 (2.4.0)
53
+ minitest (5.11.3)
34
54
  mysql2 (0.4.10)
35
- pry (0.9.12.6)
36
- coderay (~> 1.0)
37
- method_source (~> 0.8)
38
- slop (~> 3.4)
39
- pry-nav (0.2.4)
40
- pry (>= 0.9.10, < 0.11.0)
41
- rake (12.2.1)
42
- redcarpet (3.4.0)
55
+ nokogiri (1.10.3)
56
+ mini_portile2 (~> 2.4.0)
57
+ pry (0.12.2)
58
+ coderay (~> 1.1.0)
59
+ method_source (~> 0.9.0)
60
+ pry-nav (0.3.0)
61
+ pry (>= 0.9.10, < 0.13.0)
62
+ rack (2.0.7)
63
+ rack-test (1.1.0)
64
+ rack (>= 1.0, < 3)
65
+ rails-dom-testing (2.0.3)
66
+ activesupport (>= 4.2.0)
67
+ nokogiri (>= 1.6)
68
+ rails-html-sanitizer (1.1.0)
69
+ loofah (~> 2.2, >= 2.2.2)
70
+ rake (12.3.3)
71
+ redcarpet (3.5.0)
43
72
  rr (1.2.1)
44
- rspec (3.7.0)
45
- rspec-core (~> 3.7.0)
46
- rspec-expectations (~> 3.7.0)
47
- rspec-mocks (~> 3.7.0)
48
- rspec-core (3.7.0)
49
- rspec-support (~> 3.7.0)
50
- rspec-expectations (3.7.0)
73
+ rspec (3.8.0)
74
+ rspec-core (~> 3.8.0)
75
+ rspec-expectations (~> 3.8.0)
76
+ rspec-mocks (~> 3.8.0)
77
+ rspec-core (3.8.2)
78
+ rspec-support (~> 3.8.0)
79
+ rspec-expectations (3.8.4)
51
80
  diff-lcs (>= 1.2.0, < 2.0)
52
- rspec-support (~> 3.7.0)
53
- rspec-mocks (3.7.0)
81
+ rspec-support (~> 3.8.0)
82
+ rspec-mocks (3.8.1)
54
83
  diff-lcs (>= 1.2.0, < 2.0)
55
- rspec-support (~> 3.7.0)
56
- rspec-support (3.7.0)
57
- slop (3.6.0)
58
- sqlite3 (1.3.13)
84
+ rspec-support (~> 3.8.0)
85
+ rspec-support (3.8.2)
86
+ sqlite3 (1.4.1)
59
87
  thread_safe (0.3.6)
60
- tzinfo (1.2.4)
88
+ tzinfo (1.2.5)
61
89
  thread_safe (~> 0.1)
62
- yard (0.9.9)
90
+ yard (0.9.20)
63
91
 
64
92
  PLATFORMS
65
93
  ruby
66
94
 
67
95
  DEPENDENCIES
96
+ actionpack
68
97
  brainstem!
69
98
  database_cleaner
70
99
  db-query-matchers
@@ -79,4 +108,4 @@ DEPENDENCIES
79
108
  yard
80
109
 
81
110
  BUNDLED WITH
82
- 1.13.6
111
+ 1.17.3
@@ -141,7 +141,7 @@ module Brainstem
141
141
  FORMATTERS = {
142
142
 
143
143
  # Formatter for entire response
144
- document: {},
144
+ document: {},
145
145
 
146
146
  # Formatters for collections
147
147
  controller_collection: {},
@@ -149,9 +149,9 @@ module Brainstem
149
149
  presenter_collection: {},
150
150
 
151
151
  # Formatters for individual entities
152
- controller: {},
153
- endpoint: {},
154
- presenter: {},
152
+ controller: {},
153
+ endpoint: {},
154
+ presenter: {},
155
155
 
156
156
  # Formatter for Open API Specifications
157
157
  info: {},
@@ -159,6 +159,11 @@ module Brainstem
159
159
  parameters: {},
160
160
  security: {},
161
161
  tags: {},
162
+
163
+ # Formatter for Open API Specifications Individual field / param definition
164
+ endpoint_param: {},
165
+ presenter_field: {},
166
+ response_field: {},
162
167
  }
163
168
  end
164
169
  end
@@ -18,9 +18,9 @@ module Brainstem
18
18
  include Concerns::Optional
19
19
 
20
20
  def initialize(introspector, options = {})
21
- self.endpoints = EndpointCollection.new(self)
22
- self.controllers = ControllerCollection.new(self)
23
- self.presenters = ::Brainstem::ApiDocs::PresenterCollection.new(self)
21
+ self.endpoints = EndpointCollection.new(self, options)
22
+ self.controllers = ControllerCollection.new(self, options)
23
+ self.presenters = ::Brainstem::ApiDocs::PresenterCollection.new(self, options)
24
24
  self.resolver = Resolver.new(self)
25
25
 
26
26
  self.controller_matches = []
@@ -22,7 +22,8 @@ module Brainstem
22
22
  :name,
23
23
  :endpoints,
24
24
  :filename_pattern,
25
- :atlas
25
+ :atlas,
26
+ :include_internal
26
27
 
27
28
  attr_writer :filename_pattern,
28
29
  :filename_link_pattern
@@ -33,7 +34,8 @@ module Brainstem
33
34
  :name,
34
35
  :formatters,
35
36
  :filename_pattern,
36
- :filename_link_pattern
37
+ :filename_link_pattern,
38
+ :include_internal
37
39
  ]
38
40
  end
39
41
 
@@ -77,7 +79,7 @@ module Brainstem
77
79
  end
78
80
 
79
81
  def nodoc?
80
- default_configuration[:nodoc]
82
+ nodoc_for?(default_configuration)
81
83
  end
82
84
 
83
85
  def title
@@ -101,13 +103,19 @@ module Brainstem
101
103
  #
102
104
  def contextual_documentation(key)
103
105
  default_configuration.has_key?(key) &&
104
- !default_configuration[key][:nodoc] &&
106
+ !nodoc_for?(default_configuration[key]) &&
105
107
  default_configuration[key][:info]
106
108
  end
107
109
 
108
110
  def valid_sorted_endpoints
109
111
  endpoints.sorted_with_actions_in_controller(const)
110
112
  end
113
+
114
+ private
115
+
116
+ def nodoc_for?(config)
117
+ !!(config[:nodoc] || (config[:internal] && !include_internal))
118
+ end
111
119
  end
112
120
  end
113
121
  end
@@ -5,13 +5,22 @@ module Brainstem
5
5
  module ApiDocs
6
6
  class ControllerCollection < AbstractCollection
7
7
 
8
+ attr_accessor :include_internal
9
+
10
+ def valid_options
11
+ super | [
12
+ :include_internal
13
+ ]
14
+ end
15
+
8
16
  #
9
17
  # Creates a new controller from a route object and appends it to the
10
18
  # collection.
11
19
  def create_from_route(route)
12
20
  Controller.new(atlas,
13
- const: route[:controller],
14
- name: route[:controller_name].split("/").last
21
+ const: route[:controller],
22
+ name: route[:controller_name].split("/").last,
23
+ include_internal: include_internal
15
24
  ).tap { |controller| self.<< controller }
16
25
  end
17
26
 
@@ -23,7 +23,8 @@ module Brainstem
23
23
  :controller,
24
24
  :controller_name,
25
25
  :action,
26
- :presenter
26
+ :presenter,
27
+ :include_internal
27
28
  ]
28
29
  end
29
30
 
@@ -38,7 +39,8 @@ module Brainstem
38
39
  :controller,
39
40
  :controller_name,
40
41
  :action,
41
- :atlas
42
+ :atlas,
43
+ :include_internal
42
44
 
43
45
  #
44
46
  # Pretty prints each endpoint.
@@ -94,7 +96,7 @@ module Brainstem
94
96
  # Is the entire endpoint undocumentable?
95
97
  #
96
98
  def nodoc?
97
- action_configuration[:nodoc]
99
+ nodoc_for?(action_configuration)
98
100
  end
99
101
 
100
102
  def title
@@ -156,7 +158,8 @@ module Brainstem
156
158
  .with_indifferent_access
157
159
  .inject(ActiveSupport::HashWithIndifferentAccess.new) do |result, (field_name_proc, field_config)|
158
160
 
159
- next result if field_config[:nodoc]
161
+ next result if nodoc_for?(field_config)
162
+ field_config = field_config.except(:nodoc, :internal)
160
163
 
161
164
  field_name = evaluate_field_name(field_name_proc)
162
165
  if field_config.has_key?(:ancestors)
@@ -199,7 +202,8 @@ module Brainstem
199
202
  .except(:_config)
200
203
  .inject(custom_config_tree) do |result, (field_name_proc, field_config)|
201
204
 
202
- next result if field_config[:nodoc]
205
+ next result if nodoc_for?(field_config)
206
+ field_config = field_config.except(:nodoc, :internal)
203
207
 
204
208
  field_name = evaluate_field_name(field_name_proc)
205
209
  if field_config.has_key?(:ancestors)
@@ -243,7 +247,7 @@ module Brainstem
243
247
  #
244
248
  def declared_presented_class
245
249
  valid_presents.has_key?(:target_class) &&
246
- !valid_presents[:nodoc] &&
250
+ !nodoc_for?(valid_presents) &&
247
251
  valid_presents[:target_class]
248
252
  end
249
253
 
@@ -281,7 +285,7 @@ module Brainstem
281
285
  #
282
286
  def contextual_documentation(key)
283
287
  action_configuration.has_key?(key) &&
284
- !action_configuration[key][:nodoc] &&
288
+ !nodoc_for?(action_configuration[key]) &&
285
289
  action_configuration[key][:info]
286
290
  end
287
291
 
@@ -305,6 +309,12 @@ module Brainstem
305
309
  presenter_path.relative_path_from(controller_path).to_s
306
310
  end
307
311
  end
312
+
313
+ private
314
+
315
+ def nodoc_for?(config)
316
+ !!(config[:nodoc] || (config[:internal] && !include_internal))
317
+ end
308
318
  end
309
319
  end
310
320
  end