brainstem 1.0.0.pre.1 → 1.0.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +383 -32
  5. data/bin/brainstem +6 -0
  6. data/brainstem.gemspec +2 -0
  7. data/docs/api_doc_generator.markdown +175 -0
  8. data/docs/brainstem_executable.markdown +32 -0
  9. data/docs/docgen.png +0 -0
  10. data/docs/docgen_ascii.txt +63 -0
  11. data/docs/executable.png +0 -0
  12. data/docs/executable_ascii.txt +10 -0
  13. data/lib/brainstem/api_docs.rb +146 -0
  14. data/lib/brainstem/api_docs/abstract_collection.rb +116 -0
  15. data/lib/brainstem/api_docs/atlas.rb +158 -0
  16. data/lib/brainstem/api_docs/builder.rb +167 -0
  17. data/lib/brainstem/api_docs/controller.rb +122 -0
  18. data/lib/brainstem/api_docs/controller_collection.rb +40 -0
  19. data/lib/brainstem/api_docs/endpoint.rb +234 -0
  20. data/lib/brainstem/api_docs/endpoint_collection.rb +58 -0
  21. data/lib/brainstem/api_docs/exceptions.rb +8 -0
  22. data/lib/brainstem/api_docs/formatters/abstract_formatter.rb +64 -0
  23. data/lib/brainstem/api_docs/formatters/markdown/controller_formatter.rb +76 -0
  24. data/lib/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter.rb +73 -0
  25. data/lib/brainstem/api_docs/formatters/markdown/endpoint_formatter.rb +169 -0
  26. data/lib/brainstem/api_docs/formatters/markdown/helper.rb +76 -0
  27. data/lib/brainstem/api_docs/formatters/markdown/presenter_formatter.rb +200 -0
  28. data/lib/brainstem/api_docs/introspectors/abstract_introspector.rb +100 -0
  29. data/lib/brainstem/api_docs/introspectors/rails_introspector.rb +232 -0
  30. data/lib/brainstem/api_docs/presenter.rb +225 -0
  31. data/lib/brainstem/api_docs/presenter_collection.rb +97 -0
  32. data/lib/brainstem/api_docs/resolver.rb +73 -0
  33. data/lib/brainstem/api_docs/sinks/abstract_sink.rb +37 -0
  34. data/lib/brainstem/api_docs/sinks/controller_presenter_multifile_sink.rb +93 -0
  35. data/lib/brainstem/api_docs/sinks/stdout_sink.rb +44 -0
  36. data/lib/brainstem/cli.rb +146 -0
  37. data/lib/brainstem/cli/abstract_command.rb +97 -0
  38. data/lib/brainstem/cli/generate_api_docs_command.rb +169 -0
  39. data/lib/brainstem/concerns/controller_dsl.rb +300 -0
  40. data/lib/brainstem/concerns/controller_param_management.rb +30 -9
  41. data/lib/brainstem/concerns/formattable.rb +38 -0
  42. data/lib/brainstem/concerns/inheritable_configuration.rb +3 -2
  43. data/lib/brainstem/concerns/optional.rb +43 -0
  44. data/lib/brainstem/concerns/presenter_dsl.rb +76 -15
  45. data/lib/brainstem/controller_methods.rb +6 -3
  46. data/lib/brainstem/dsl/association.rb +6 -3
  47. data/lib/brainstem/dsl/associations_block.rb +6 -3
  48. data/lib/brainstem/dsl/base_block.rb +2 -4
  49. data/lib/brainstem/dsl/conditional.rb +7 -3
  50. data/lib/brainstem/dsl/conditionals_block.rb +4 -4
  51. data/lib/brainstem/dsl/configuration.rb +184 -8
  52. data/lib/brainstem/dsl/field.rb +6 -3
  53. data/lib/brainstem/dsl/fields_block.rb +2 -3
  54. data/lib/brainstem/help_text.txt +8 -0
  55. data/lib/brainstem/presenter.rb +27 -6
  56. data/lib/brainstem/presenter_validator.rb +5 -2
  57. data/lib/brainstem/time_classes.rb +1 -1
  58. data/lib/brainstem/version.rb +1 -1
  59. data/spec/brainstem/api_docs/abstract_collection_spec.rb +156 -0
  60. data/spec/brainstem/api_docs/atlas_spec.rb +353 -0
  61. data/spec/brainstem/api_docs/builder_spec.rb +100 -0
  62. data/spec/brainstem/api_docs/controller_collection_spec.rb +92 -0
  63. data/spec/brainstem/api_docs/controller_spec.rb +225 -0
  64. data/spec/brainstem/api_docs/endpoint_collection_spec.rb +144 -0
  65. data/spec/brainstem/api_docs/endpoint_spec.rb +346 -0
  66. data/spec/brainstem/api_docs/formatters/abstract_formatter_spec.rb +30 -0
  67. data/spec/brainstem/api_docs/formatters/markdown/controller_formatter_spec.rb +126 -0
  68. data/spec/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter_spec.rb +85 -0
  69. data/spec/brainstem/api_docs/formatters/markdown/endpoint_formatter_spec.rb +261 -0
  70. data/spec/brainstem/api_docs/formatters/markdown/helper_spec.rb +100 -0
  71. data/spec/brainstem/api_docs/formatters/markdown/presenter_formatter_spec.rb +485 -0
  72. data/spec/brainstem/api_docs/introspectors/abstract_introspector_spec.rb +192 -0
  73. data/spec/brainstem/api_docs/introspectors/rails_introspector_spec.rb +170 -0
  74. data/spec/brainstem/api_docs/presenter_collection_spec.rb +84 -0
  75. data/spec/brainstem/api_docs/presenter_spec.rb +519 -0
  76. data/spec/brainstem/api_docs/resolver_spec.rb +72 -0
  77. data/spec/brainstem/api_docs/sinks/abstract_sink_spec.rb +16 -0
  78. data/spec/brainstem/api_docs/sinks/controller_presenter_multifile_sink_spec.rb +56 -0
  79. data/spec/brainstem/api_docs/sinks/stdout_sink_spec.rb +22 -0
  80. data/spec/brainstem/api_docs_spec.rb +58 -0
  81. data/spec/brainstem/cli/abstract_command_spec.rb +91 -0
  82. data/spec/brainstem/cli/generate_api_docs_command_spec.rb +125 -0
  83. data/spec/brainstem/cli_spec.rb +67 -0
  84. data/spec/brainstem/concerns/controller_dsl_spec.rb +471 -0
  85. data/spec/brainstem/concerns/controller_param_management_spec.rb +36 -16
  86. data/spec/brainstem/concerns/formattable_spec.rb +30 -0
  87. data/spec/brainstem/concerns/inheritable_configuration_spec.rb +104 -4
  88. data/spec/brainstem/concerns/optional_spec.rb +48 -0
  89. data/spec/brainstem/concerns/presenter_dsl_spec.rb +202 -31
  90. data/spec/brainstem/dsl/association_spec.rb +18 -2
  91. data/spec/brainstem/dsl/conditional_spec.rb +25 -2
  92. data/spec/brainstem/dsl/configuration_spec.rb +1 -1
  93. data/spec/brainstem/dsl/field_spec.rb +18 -2
  94. data/spec/brainstem/presenter_collection_spec.rb +10 -2
  95. data/spec/brainstem/presenter_spec.rb +32 -0
  96. data/spec/brainstem/presenter_validator_spec.rb +12 -7
  97. data/spec/dummy/rails.rb +49 -0
  98. data/spec/shared/atlas_taker.rb +18 -0
  99. data/spec/shared/formattable.rb +14 -0
  100. data/spec/spec_helper.rb +2 -0
  101. data/spec/spec_helpers/db.rb +1 -1
  102. data/spec/spec_helpers/presenters.rb +20 -14
  103. metadata +106 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a8bd5fc16e1e1886466bd5d575c4ea7217a7bf0d
4
- data.tar.gz: 0cc3b8df6885253815b47108273153e67105bfd2
3
+ metadata.gz: 115ca6ee598304821711410e09788b194b4463d3
4
+ data.tar.gz: eb49966eafe33595f32048f087ee7148a0b4da36
5
5
  SHA512:
6
- metadata.gz: 3aa58b60f630f1f89875a7afce69e51faf6745c2b8a1f93495d57f754a208b17d80736aba4fd2ca2e08612bd41e570441e6faf19bca5cb70204a0e7678d2c1ad
7
- data.tar.gz: 9b090b4841129d96d5581ee116eba190e40cfcd214fd1893845e8019a563f8c90c9214c298ba40e7e6047cb8501093162c2fce74b2517a18492f5752be796167
6
+ metadata.gz: 45af28ac0b45a91167174b0809e79c22a20864cb2facb3c59c23fdad0d71e62dec0299db8f74748a0c0306169aa05eaf756f5564459f43d19edb2b0045bbb30c
7
+ data.tar.gz: 8050a810b6b1046d00d7aa961bebe48698604be562f28c73943c5160d4668b47c92ff9c4bb52a03e67eb67804d4f9d5a8391507cd5328b8138546e7febefcdc8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ + **1.0.0 - _07/20/2017_
4
+ - Add the capability to generate the documentation extracted from your properly annotated
5
+ presenters and controllers using `bundle exec brainstem generate [ARGS]`.
6
+ - Update Brainstem to use Ruby version 2.3.3.
7
+ - Add support for Ruby versions 2.2.7, 2.3.4 & 2.4.1 and drop support for Ruby version 2.1.10.
8
+ - Drop support for specifying description param as a string and not with the `info` key in the options hash.
9
+
10
+ + **1.0.0.pre.2** - _04/12/2017_
11
+ - Added support for specifying the description for conditionals, fields and associations with the `info` key in the options hash.
12
+ - Added a deprecation warning when description param is specified as a string and not with the `info` key in the options hash.
13
+ - Fixed: support for conditional, field and association options to be a hash with indifferent access.
14
+
3
15
  + **1.0.0.pre.1** - _03/07/2017_
4
16
  - Implemented new presenter DSL.
5
17
  - Added controller helpers for presenting errors.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- brainstem (1.0.0.pre.1)
4
+ brainstem (1.0.0.pre)
5
5
  activerecord (>= 4.1)
6
6
  activesupport (>= 4.1)
7
7
 
data/README.md CHANGED
@@ -66,11 +66,11 @@ module Api
66
66
 
67
67
  # Specify the fields to be present in the returned JSON.
68
68
  fields do
69
- field :name, :string, "the Widget's name"
70
- field :legacy, :boolean, "true for legacy Widgets, false otherwise", via: :legacy?
71
- field :longform_description, :string, "feature-length description of this Widget", optional: true
72
- field :updated_at, :datetime, "the time of this Widget's last update"
73
- field :created_at, :datetime, "the time at which this Widget was created"
69
+ field :name, :string, info: "the Widget's name"
70
+ field :legacy, :boolean, info: "true for legacy Widgets, false otherwise", via: :legacy?
71
+ field :longform_description, :string, info: "feature-length description of this Widget", optional: true
72
+ field :updated_at, :datetime, info: "the time of this Widget's last update"
73
+ field :created_at, :datetime, info: "the time at which this Widget was created"
74
74
  end
75
75
 
76
76
  # Associations can be included by providing include=association_name in the URL.
@@ -78,8 +78,8 @@ module Api
78
78
  # columns on the model, otherwise the user must explicitly request associations
79
79
  # to avoid unnecessary loads.
80
80
  associations do
81
- association :features, Feature, "features associated with this Widget"
82
- association :location, Location, "the location of this Widget"
81
+ association :features, Feature, info: "features associated with this Widget"
82
+ association :location, Location, info: "the location of this Widget"
83
83
  end
84
84
  end
85
85
  end
@@ -119,6 +119,7 @@ The `Brainstem::ControllerMethods` concern provides:
119
119
  * `brainstem_model_name` which is inferred from your controller name or settable with `self.brainstem_model_name = :thing`.
120
120
  * `brainstem_present` and `brainstem_present_object` for presenting a scope of models or a single model.
121
121
  * `brainstem_model_error` and `brainstem_system_error` for presenting model and system error messages.
122
+ * Various methods for auto-documentation of your API.
122
123
 
123
124
  ### Controller Best Practices
124
125
 
@@ -164,7 +165,7 @@ module Api
164
165
  end
165
166
  ```
166
167
 
167
- ### Setup Rails to load Brainstem
168
+ ### Setup Rails to Load Brainstem
168
169
 
169
170
  To configure Brainstem for development and production, we do the following:
170
171
 
@@ -173,8 +174,9 @@ To configure Brainstem for development and production, we do the following:
173
174
  2) We setup an initializer in `config/initializers/brainstem.rb`, similar to the following:
174
175
 
175
176
  ```ruby
176
- # In order to support live code reload in the development environment, we register a `to_prepare` callback. This
177
- # runs once in production (before the first request) and whenever a file has changed in development.
177
+ # In order to support live code reload in the development environment, we
178
+ # register a `to_prepare` callback. This # runs once in production (before the
179
+ # first request) and whenever a file has changed in development.
178
180
  Rails.application.config.to_prepare do
179
181
  # Forget all Brainstem configuration.
180
182
  Brainstem.reset!
@@ -182,9 +184,11 @@ Rails.application.config.to_prepare do
182
184
  # Set the current default API namespace.
183
185
  Brainstem.default_namespace = :v1
184
186
 
185
- # (Optional) Load a default base helper into all presenters. You could use this to bring in a concept like `current_user`.
186
- # While not necessarily the best approach, something like http://stackoverflow.com/a/11670283 can currently be used to
187
- # access the requesting user inside of a Brainstem presenter. We hope to clean this up by allowing a user to be passed in
187
+ # (Optional) Load a default base helper into all presenters. You could use
188
+ # this to bring in a concept like `current_user`. # While not necessarily the
189
+ # best approach, something like http://stackoverflow.com/a/11670283 can
190
+ # currently be used to # access the requesting user inside of a Brainstem
191
+ # presenter. We hope to clean this up by allowing a user to be passed in #
188
192
  # when presenting in the future.
189
193
  module ApiHelper
190
194
  def current_user
@@ -269,6 +273,343 @@ Brainstem parses the request params and supports the following:
269
273
  keywords, such as `search`, `page`, `per_page`, `limit`, `offset`, `order`, `only`, or `include`.
270
274
  * Brainstem supports optional fields which will only be returned when requested, for example: `optional_fields=field1,field2`
271
275
 
276
+ --
277
+
278
+
279
+ ## The `brainstem` executable
280
+
281
+ The `brainstem` executable provided with the gem is at the moment used only to
282
+ generate API docs from the command line, but you can verify which commands are
283
+ available simply by running:
284
+
285
+ ```sh
286
+ bundle exec brainstem
287
+ ```
288
+
289
+ This will give you a list of all available commands. Additional help is
290
+ available for each command, and can be found by passing the command
291
+ the `help` flag, i.e.:
292
+
293
+ ```sh
294
+ bundle exec brainstem generate --help
295
+ ```
296
+
297
+ --
298
+
299
+
300
+ ## API Documentation
301
+
302
+ ### The `generate` command
303
+
304
+ Running `bundle exec brainstem generate [ARGS]` will generate the documentation
305
+ extracted from your properly annotated presenters and controllers.
306
+
307
+ Note that this does not, at present, *remove* existing docs that may be present
308
+ from a previous generation, so it is recommended that you use this executable as
309
+ part of a large shell script that empties your directory and regenerates over
310
+ top of it if you expect much churn.
311
+
312
+ ### Customizing behavior
313
+
314
+ While options can be passed on the command line, this can complicate the
315
+ invocation, especially when the desired settings are often specific to the
316
+ project and do not often change.
317
+
318
+ As a result, it is possible to specify options through an initializer in your
319
+ application that will be used in the absence of command-line flags. Thus,
320
+ configuration precedence is in the following order:
321
+
322
+ 1. Command-line flags;
323
+ 2. Initializer settings;
324
+ 3. Built-in defaults.
325
+
326
+ To see a list of the available command-line options, run `bundle exec brainstem
327
+ generate --help`.
328
+
329
+ To see a list of the available initializer settings, view
330
+ [lib/brainstem/api_docs.rb](./lib/brainstem/api_docs.rb). You can configure
331
+ these in your initializers just by setting them:
332
+
333
+ ```ruby
334
+ # config/initializers/brainstem.rb
335
+
336
+ Brainstem::ApiDocs.tap do |config|
337
+ config.write_path = "/path/to/output"
338
+ end
339
+ ```
340
+
341
+ ### Annotating an API
342
+
343
+ #### Presenters / Data Models
344
+
345
+ By and large, Presenters are self-documenting: simply using them as intended
346
+ will yield a panoply of data.
347
+
348
+ ##### Docstrings
349
+
350
+ All common methods that do not explicitly take a description take an `:info`
351
+ option, which allows for the specification of an explanatory documentation
352
+ string.
353
+
354
+ As a general rule of thumb, methods that are not used within a block tend to
355
+ accept `:info` strings, and those used within a block tend to have their own
356
+ `description` argument.
357
+
358
+ For example:
359
+
360
+ ```ruby
361
+ class MyPresenter < Brainstem::Presenter
362
+ sort_order :cost, info: "Sorts by cost" do |scope, direction|
363
+ scope.reorder("myobjects.cost #{direction}")
364
+ end
365
+ end
366
+ ```
367
+
368
+ The methods that take an `:info` option include:
369
+
370
+ - `sort_order`
371
+ - `filter`
372
+ - `association`
373
+ - `request/model`
374
+ - `field` &mdash; also displays the documentation of any condition set in its
375
+ `:if` option.
376
+
377
+ The following do not accept documentation:
378
+
379
+ - `default_sort_order`
380
+ - `preload`
381
+
382
+ ##### Nodoc
383
+
384
+ The following methods accept a `:nodoc` boolean option, which indicates that the
385
+ documentation should be suppressed for this particular entry:
386
+
387
+ - `association` &mdash; hides the association
388
+ - `field` &mdash; hides the field
389
+ - `sort_order` &mdash; hides the sort order
390
+ - `filter` &mdash; hides the filter
391
+ - `request` / `model` &mdash; causes the conditional not to be
392
+ listed on any field which specifies it
393
+
394
+ ##### Additional Documentables
395
+
396
+ In addition to the above, there are three additional methods in the DSL designed
397
+ primarily for documentation:
398
+
399
+ - `nodoc!` &mdash; within a presenter or the `brainstem_params` block within a controller, skips generating the documentation entirely. Useful for hidden or non-public endpoints.
400
+ - `title(str, options)` &mdash; used to specify an alternate title for the
401
+ Presenter.
402
+ - `nodoc: true` &mdash; forces fallback to the Presenter's constant
403
+ - `description(str, options)` &mdash; used to specify a description for the
404
+ Presenter.
405
+ - `nodoc: true` &mdash; displays no description
406
+
407
+ ##### Example
408
+
409
+ ```ruby
410
+ class PostsPresenter < Brainstem::Presenter
411
+ presents Post
412
+
413
+ # Hide the entire presenter
414
+ #
415
+ # nodoc!
416
+
417
+ # If we temporarily want to disable the custom title, and just display
418
+ # 'Posts', we can add a 'nodoc' option set to true.
419
+ #
420
+ # title "Blog Posts", nodoc: true
421
+
422
+ title "Blog Posts"
423
+
424
+ description <<-MARKDOWN.strip_heredoc
425
+ The blog post is the primary entity in the blog, which represents a single
426
+ post by one of our authors.
427
+ MARKDOWN
428
+
429
+ associations do
430
+ association :author, User, info: "the author of the post"
431
+
432
+ # Temporarily disable documenting this relationship as we revamp the
433
+ # editorial system:
434
+ association :editor, User, info: "the editor of the post", nodoc: true
435
+ end
436
+ end
437
+ ```
438
+
439
+ #### Controllers
440
+
441
+ The configuration for a controller takes place inside the `brainstem_params` block, e.g.:
442
+
443
+ ```ruby
444
+ class PostsController < ApiController
445
+ include Brainstem::Concerns::ControllerDSL
446
+
447
+ brainstem_params do
448
+ title "Posts"
449
+ end
450
+ end
451
+ ```
452
+
453
+ ##### Action Contexts
454
+
455
+ Configuration that is specified within the root level of the `brainstem_params`
456
+ block is applied to the entire controller, and every action within the
457
+ controller. This is referred to as the 'default' context, because it is used as
458
+ the default for all actions. This lets you specify common defaults for all
459
+ actions, as well as a title and description for the controller, which, along
460
+ with an annotation of `nodoc!`, are not inherited by the actions.
461
+
462
+ Each action has its own action context, and the documentation is smart enough
463
+ to know that what you want to document for the `index` action is likely not
464
+ what you'd like to document for the `show` action, but you are also likely to
465
+ have your `create` and `update` methods be very similar.
466
+
467
+ You can define an action context and place any configuration inside this
468
+ context, and it will keep the documentation isolated to that specific action:
469
+
470
+ ```ruby
471
+ brainstem_params do
472
+ valid :global_controller_param,
473
+ info: "A trivial example of a param that applies to all actions."
474
+
475
+ actions :index do
476
+ # This adds a `blog_id` param to just the `index` action.
477
+ valid :blog_id, info: "The id of the blog to which this post belongs"
478
+ end
479
+
480
+ actions :create, :update do
481
+ # This will add an `id` param to both `create` and `update` actions.
482
+ valid :id, info: "The id of the blog post"
483
+ end
484
+ end
485
+ ```
486
+
487
+ Action contexts, like the default context, are inherited from the parent
488
+ controller. So it is often possible to express common setup in the more
489
+ abstract controllers, like so:
490
+
491
+ ```ruby
492
+ class ApiController
493
+ brainstem_params do
494
+ actions :destroy do
495
+ presents nil
496
+ end
497
+ end
498
+ end
499
+
500
+ class PostsController << ApiController; end
501
+ ```
502
+
503
+ In this example, `PostsController` will list no presenter for its `destroy`
504
+ method as it inherits this from `ApiController`.
505
+
506
+ **It is important to specify everything at the most specific level possible.**
507
+ Action contexts have a higher priority than defaults, and will fall back to the
508
+ action context of the parent controller before they check the default of the
509
+ child controller. It's therefore recommended that your documentation be kept
510
+ in action contexts as much as possible.
511
+
512
+ ##### `title` / `description` / `nodoc!`
513
+
514
+ Any of these can be used inside an action context as well.
515
+
516
+ ```ruby
517
+ class BlogPostsController < ApiController
518
+ brainstem_params do
519
+
520
+ # Make the displayed title of this controller "Posts"
521
+ title "Posts"
522
+
523
+ # Fall back to 'BlogPostsController' for a title
524
+ title "Posts", nodoc: true
525
+
526
+ # Show description
527
+ description "Access blog posts through these endpoints."
528
+
529
+ # Hide description
530
+ description "...", nodoc: true
531
+
532
+ # Do not document this controller or any of its endpoints!
533
+ nodoc!
534
+
535
+ actions :index do
536
+ # Set the title of this action
537
+ title "Listing blog posts"
538
+ description "..."
539
+ end
540
+
541
+ actions :show do
542
+ # Do not display this action.
543
+ nodoc!
544
+ end
545
+
546
+ end
547
+ end
548
+ ```
549
+
550
+
551
+ ##### `valid` / `model_params`
552
+
553
+ ```ruby
554
+ class BlogPostsController < ApiController
555
+ brainstem_params do
556
+
557
+ # Add an `:category_id` param to all actions in this controller / children:
558
+ valid :category_id, info: "(required) the category's ID"
559
+
560
+ # Do not document this additional field.
561
+ valid :lang,
562
+ info: "(optional) the language of the requested post",
563
+ nodoc: true
564
+
565
+ actions :show do
566
+ # Declare a nested param under the `brainstem_model_name` root key,
567
+ # i.e. `params[:blog_post][:id]`):
568
+ model_params do |post|
569
+ post.valid :id, info: "(required) the id of the post"
570
+ end
571
+ end
572
+
573
+ actions :share do
574
+ # Declare a nested param with an explicit root key:, i.e. `params[:share][...]`
575
+ model_param :share do
576
+ # ...
577
+ end
578
+ end
579
+
580
+
581
+ def self.param_root
582
+ :widgets
583
+ end
584
+
585
+
586
+ actions :update do
587
+ # Declare a dynamic root key, i.e. `params[:widgets][:id]`
588
+ model_params(-> (controller_klass) { controller_class.param_root } do |p|
589
+ p.valid :id #, ...
590
+ end
591
+ end
592
+ end
593
+ end
594
+ ```
595
+
596
+ ##### `presents`
597
+
598
+ ```ruby
599
+ class BlogPostsController < ApiController
600
+ brainstem_params do
601
+ # Includes a link to the presenter for `BlogPost` in each action.
602
+ presents BlogPost
603
+ end
604
+ ```
605
+
606
+ ### Extending and Customizing the API Documentation
607
+
608
+ For more information on extending and customizing the API documentation, please
609
+ see the
610
+ [API Doc Generator developer documentation](./docs/api_doc_generator.markdown).
611
+
612
+
272
613
  --
273
614
 
274
615
  For more detailed examples, please see the rest of this README and our detailed
@@ -524,12 +865,15 @@ Brainstem provides a rich DSL for building presenters. This section details the
524
865
 
525
866
  ```ruby
526
867
  fields do
527
- field :name, :string, "the Widget's name"
528
- field :legacy, :boolean, "true for legacy Widgets, false otherwise",
868
+ field :name, :string, info: "the Widget's name"
869
+ field :legacy, :boolean,
870
+ info: "true for legacy Widgets, false otherwise",
529
871
  via: :legacy?
530
- field :dynamic_name, :string, "a formatted name for this Widget",
872
+ field :dynamic_name, :string,
873
+ info: "a formatted name for this Widget",
531
874
  dynamic: lambda { |widget| "This Widget's name is #{widget.name}" }
532
- field :longform_description, :string, "feature-length description of this Widget",
875
+ field :longform_description, :string,
876
+ info: "feature-length description of this Widget",
533
877
  optional: true
534
878
 
535
879
  # Fields can be nested
@@ -561,14 +905,16 @@ Brainstem provides a rich DSL for building presenters. This section details the
561
905
 
562
906
  ```ruby
563
907
  associations do
564
- association :features, Feature, "features associated with this Widget"
565
- association :location, Location, "the location of this Widget"
566
- association :previous_location, Location, "the Widget's previous location",
908
+ association :features, Feature, info: "features associated with this Widget"
909
+ association :location, Location, info: "the location of this Widget"
910
+ association :previous_location, Location,
911
+ info: "the Widget's previous location",
567
912
  dynamic: lambda { |widget| widget.previous_locations.first }
568
- association :associated_objects, :polymorphic, "a mixture of objects related to this Widget"
913
+ association :associated_objects, :polymorphic,
914
+ info: "a mixture of objects related to this Widget"
569
915
  end
570
916
  ```
571
-
917
+
572
918
  * `lookup` - Use this option to avoid N + 1 queries for Fields and Associations. The `lookup` lambda runs once when
573
919
  presenting and every presented model gets its assocation or value from the cache the `lookup` lambda generates. The
574
920
  `lookup` lambda takes in the presented models and should generate a cache containing the models' coresponding assocations
@@ -579,7 +925,8 @@ the `lookup` will be used.
579
925
 
580
926
  ```ruby
581
927
  associations do
582
- association :current_user_groups, Group, "the Groups for the current user",
928
+ association :current_user_groups, Group,
929
+ info: "the Groups for the current user",
583
930
  lookup: lambda { |models|
584
931
  Group.where(subject_id: models.map(&:id)
585
932
  .where(user_id: current_user.id)
@@ -595,12 +942,13 @@ the `lookup` will be used.
595
942
 
596
943
  ```ruby
597
944
  fields do
598
- field :current_user_post_count, Post, "count of Posts the current_user has for this model",
599
- lookup: lambda { |models|
945
+ field :current_user_post_count, Post,
946
+ info: "count of Posts the current_user has for this model",
947
+ lookup: lambda { |models|
600
948
  lookup = Post.where(subject_id: models.map(&:id)
601
949
  .where(user_id: current_user.id)
602
- .group_by { |post| post.subject_id }
603
-
950
+ .group_by { |post| post.subject_id }
951
+
604
952
  lookup
605
953
  },
606
954
  lookup_fetch: lambda { |lookup, model| lookup[model.id] }
@@ -617,24 +965,27 @@ the `lookup` will be used.
617
965
  conditionals do
618
966
  model :title_is_hello,
619
967
  lambda { |model| model.title == 'hello' },
620
- 'visible when the title is hello'
968
+ info: 'visible when the title is hello'
621
969
 
622
970
  request :user_is_bob,
623
971
  lambda { current_user == 'bob' }, # Assuming some sort of `helper` that provides `current_user`
624
- 'visible only to bob'
972
+ info: 'visible only to bob'
625
973
  end
626
974
 
627
975
  fields do
628
- field :hello_title, :string, 'the title, when it is exactly the word "hello"',
976
+ field :hello_title, :string,
977
+ info: 'the title, when it is exactly the word "hello"',
629
978
  dynamic: lambda { |model| model.title + " is the title" },
630
979
  if: :title_is_hello
631
980
 
632
- field :secret, :string, "a secret, via the secret_info model method, only visible to bob and when the model's title is hello",
981
+ field :secret, :string,
982
+ info: "a secret, via the secret_info model method, only visible to bob and when the model's title is hello",
633
983
  via: :secret_info,
634
984
  if: [:user_is_bob, :title_is_hello]
635
985
 
636
986
  with_options if: :user_is_bob do
637
- field :bob_title, :string, 'another name for the title, only visible to Bob',
987
+ field :bob_title, :string,
988
+ info: 'another name for the title, only visible to Bob',
638
989
  via: :title
639
990
  end
640
991
  end