brainstem 1.0.0.pre.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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