keynote 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +73 -25
  3. data/{LICENSE → LICENSE.txt} +2 -6
  4. data/README.md +119 -47
  5. data/lib/generators/presenter_generator.rb +16 -24
  6. data/lib/keynote/cache.rb +1 -1
  7. data/lib/keynote/controller.rb +4 -5
  8. data/lib/keynote/core.rb +64 -0
  9. data/lib/keynote/helper.rb +4 -5
  10. data/lib/keynote/inline.rb +51 -109
  11. data/lib/keynote/presenter.rb +13 -19
  12. data/lib/keynote/railtie.rb +7 -24
  13. data/lib/keynote/rumble.rb +22 -13
  14. data/lib/keynote/testing/{minitest_rails.rb → minitest.rb} +1 -2
  15. data/lib/keynote/testing/rspec.rb +5 -5
  16. data/lib/keynote/testing/test_present_method.rb +2 -2
  17. data/lib/keynote/testing/test_unit.rb +1 -1
  18. data/lib/keynote/version.rb +2 -2
  19. data/lib/keynote.rb +7 -65
  20. metadata +68 -96
  21. data/.editorconfig +0 -14
  22. data/.gitignore +0 -18
  23. data/.travis.yml +0 -11
  24. data/.yardopts +0 -4
  25. data/Gemfile +0 -4
  26. data/Rakefile +0 -21
  27. data/keynote.gemspec +0 -37
  28. data/lib/generators/templates/keynote_mini_test_unit.rb +0 -11
  29. data/lib/keynote/testing/minitest_rails.rake +0 -7
  30. data/scenarios/rails31.docker-compose.yml +0 -15
  31. data/scenarios/rails31.dockerfile +0 -5
  32. data/scenarios/rails31.gemfile +0 -7
  33. data/scenarios/rails32.docker-compose.yml +0 -15
  34. data/scenarios/rails32.dockerfile +0 -5
  35. data/scenarios/rails32.gemfile +0 -6
  36. data/scenarios/rails40.docker-compose.yml +0 -15
  37. data/scenarios/rails40.dockerfile +0 -5
  38. data/scenarios/rails40.gemfile +0 -6
  39. data/scenarios/rails41.docker-compose.yml +0 -15
  40. data/scenarios/rails41.dockerfile +0 -5
  41. data/scenarios/rails41.gemfile +0 -6
  42. data/scenarios/rails42.docker-compose.yml +0 -15
  43. data/scenarios/rails42.dockerfile +0 -5
  44. data/scenarios/rails42.gemfile +0 -6
  45. data/scenarios/rails50.docker-compose.yml +0 -15
  46. data/scenarios/rails50.dockerfile +0 -5
  47. data/scenarios/rails50.gemfile +0 -6
  48. data/scenarios/rails51.docker-compose.yml +0 -15
  49. data/scenarios/rails51.dockerfile +0 -5
  50. data/scenarios/rails51.gemfile +0 -6
  51. data/scenarios.yml +0 -25
  52. data/spec/benchmarks.rb +0 -73
  53. data/spec/generator_spec.rb +0 -159
  54. data/spec/helper.rb +0 -90
  55. data/spec/inline_spec.rb +0 -157
  56. data/spec/keynote_spec.rb +0 -130
  57. data/spec/presenter_spec.rb +0 -179
  58. data/spec/railtie_spec.rb +0 -33
  59. data/spec/rumble_spec.rb +0 -271
  60. data/spec/test_case_spec.rb +0 -12
  61. /data/lib/generators/templates/{keynote_mini_test_spec.rb → keynote_mini_test_spec.rb.tt} +0 -0
  62. /data/lib/generators/templates/{keynote_test_unit.rb → keynote_mini_test_unit.rb.tt} +0 -0
  63. /data/lib/generators/templates/{keynote_presenter.rb → keynote_presenter.rb.tt} +0 -0
  64. /data/lib/generators/templates/{keynote_rspec.rb → keynote_rspec.rb.tt} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: bbd02a5e8d588001102132e7864b294e34290700
4
- data.tar.gz: d8db8a485b076d070774031959cecbc2f0b9fb68
2
+ SHA256:
3
+ metadata.gz: 961b8bbb609c798ba7dd9e9d2896132bc87856f2059724a3cf2be80596cd8be1
4
+ data.tar.gz: 3a242df538467281e4a5df928e4fc1eab7ffad18a715813b8abc86ec5a815565
5
5
  SHA512:
6
- metadata.gz: 2033a7f5c59e895ac0d8f31202591f02f8d4f5f750203b940696f029968a14c0f59d0d8bba990f7f3ef95bb39358605b961326b869b074366210411ef7b80c9a
7
- data.tar.gz: d683f2f2259fbff0ad2ab280ce5300093f25ed4e6bc68a13a5901a7d422fe0764a61dd50f6fb74de5babe3ed582772d47c224d16262218d9000f40a9506797e9
6
+ metadata.gz: 3575f94138d3ccf5a0f45dce0137d616dc79c967753b616f64e02152eb4ed3e5dca8ae91ace4f95206ae082d9a3591b5d39826d2ca7073045dc22331d5a27a2d
7
+ data.tar.gz: 24ed666d1ee71ebf9e14cee38faf41cf51ad6000260cd695ec3eabd9ab1095270d8588fcdc0cd9d3aff86bff1578864d6e52f92519974ef6717c2e421c883069
data/CHANGELOG.md CHANGED
@@ -1,58 +1,106 @@
1
+ # Change log
2
+
3
+ ## v2.0.0 (2025-01-10)
4
+
5
+ - Update the inline template API to pass source as string instead of parsing comments. [@palkan][]
6
+
7
+ ```rb
8
+ # BEFORE:
9
+ def method_with_a_template
10
+ a = "foo"
11
+
12
+ erb
13
+ # <div><%= a %></div>
14
+ end
15
+
16
+ # AFTER:
17
+ def method_with_a_template
18
+ a = "foo"
19
+
20
+ erb(a:) { "<div><%= a %></div>" }
21
+ end
22
+ ```
23
+
24
+ This change makes inline templates less magical, IDE-friendly, and much faster.
25
+
26
+ - **Ruby 3+** and **Rails 7+** are required. [@palkan][]
27
+
28
+ ## v1.1.1
29
+
30
+ - Rumble: Fix passing `true` as an attribute value, which was broken by the
31
+ escaping changes in v1.0.0. [@igas][]
32
+
1
33
  ## v1.1.0
2
- * Rumble: Fix bug in v1.0.0 that caused an exception if the user passed a `nil`
34
+
35
+ - Rumble: Fix bug in v1.0.0 that caused an exception if the user passed a `nil`
3
36
  value for an attribute.
4
- * Rumble: Add support for `aria` attr hashes, behaving the same way as `data`.
37
+ - Rumble: Add support for `aria` attr hashes, behaving the same way as `data`.
5
38
 
6
39
  ## v1.0.0
7
- * Add support for Rails 5.1.
8
- * Fix all Ruby warnings generated by Keynote itself.
9
- * Rumble: Always escape quotation marks in HTML attributes, even if the string
40
+
41
+ - Add support for Rails 5.1.
42
+ - Fix all Ruby warnings generated by Keynote itself.
43
+ - Rumble: Always escape quotation marks in HTML attributes, even if the string
10
44
  is already marked as HTML-safe.
11
- * Rumble: Allow user to pass in a `data` hash to generate data attributes.
12
- * Rumble: Allow user to pass in an array value for an attribute, which will be
45
+ - Rumble: Allow user to pass in a `data` hash to generate data attributes.
46
+ - Rumble: Allow user to pass in an array value for an attribute, which will be
13
47
  joined by spaces.
14
48
 
15
49
  ## v0.3.1
16
- * Add support for Rails 5.0. (@dra)
50
+
51
+ - Add support for Rails 5.0. [@dra][]
17
52
 
18
53
  ## v0.3.0
19
- * Drop support for Rails 3.0 and Ruby 1.9.2; add support for Rails 4.2.
20
- * Drop support for MiniTest::Rails versions older than 2.0; add support for 2.0
21
- and higher. (@kirs)
54
+
55
+ - Drop support for Rails 3.0 and Ruby 1.9.2; add support for Rails 4.2.
56
+ - Drop support for MiniTest::Rails versions older than 2.0; add support for 2.0
57
+ and higher. [@kirs][]
22
58
 
23
59
  ## v0.2.3
24
- * Allow user to pass the string version of the presenter name into
60
+
61
+ - Allow user to pass the string version of the presenter name into
25
62
  `Keynote.present` as an alternative to passing a symbol. This makes it less
26
63
  awkward to use namespaced presenters, but it does remove the possibility of
27
64
  defining a `StringPresenter` and using it with code like
28
65
  `k('some string').format_as_markdown`. It seems unlikely that anyone is
29
- actually doing that though. (@outpunk)
30
- * Update RSpec integration to not print deprecation warnings with RSpec 3.
31
- (@DarthSim)
66
+ actually doing that though. [@outpunk][]
67
+ - Update RSpec integration to not print deprecation warnings with RSpec 3.
68
+ [@DarthSim][]
32
69
 
33
70
  ## v0.2.2
34
- * Fix another RSpec integration bug, which happened in cases where the app's
71
+
72
+ - Fix another RSpec integration bug, which happened in cases where the app's
35
73
  Gemfile included rspec-rails but not the rspec gem itself.
36
- * Fix a bug in the generation of specs for zero-arg presenters.
74
+ - Fix a bug in the generation of specs for zero-arg presenters.
37
75
 
38
76
  ## v0.2.1
39
- * Update configuration to test across MRI 1.9.2/1.9.3/2.0.0/2.1.0, Rubinius,
77
+
78
+ - Update configuration to test across MRI 1.9.2/1.9.3/2.0.0/2.1.0, Rubinius,
40
79
  JRuby, Rails 3.0/3.1/3.2/4.0/4.1.
41
- * Fix issue #6, in which the order of dependencies in the Gemfile could keep
80
+ - Fix issue #6, in which the order of dependencies in the Gemfile could keep
42
81
  Keynote's RSpec integration from loading correctly.
43
82
 
44
83
  ## v0.2.0
45
- * Add `Keynote::Inline`, a module that presenters can extend to enable inline
84
+
85
+ - Add `Keynote::Inline`, a module that presenters can extend to enable inline
46
86
  templating in any language supported by Rails.
47
- * Presenters now have a `use_html_5_tags` class method that adds a more
87
+ - Presenters now have a `use_html_5_tags` class method that adds a more
48
88
  complete set of Rumble tag methods to the class.
49
- * Add `object_names` class method to presenters, returning an array of the
89
+ - Add `object_names` class method to presenters, returning an array of the
50
90
  symbols that have been passed into the `presents` method.
51
- * Add an implementation of the `present`/`k` method that's available in test
91
+ - Add an implementation of the `present`/`k` method that's available in test
52
92
  cases. Update test generators accordingly.
53
- * Update minitest-rails integration to be compatible with the newest
93
+ - Update minitest-rails integration to be compatible with the newest
54
94
  version of minitest-rails (on Rails 3.0, 3.1, 3.2, and 4.0).
55
95
 
56
96
  ## v0.1.3
57
- * Add block form of `present`. If you pass a block into a `present` call, it
97
+
98
+ - Add block form of `present`. If you pass a block into a `present` call, it
58
99
  yields the presenter.
100
+
101
+ [@palkan]: https://github.com/palkan
102
+ [@igas]: https://github.com/igas
103
+ [@dra]: https://github.com/dra
104
+ [@kirs]: https://github.com/kirs
105
+ [@outpunk]: https://github.com/outpunk
106
+ [@DarthSim]: https://github.com/DarthSim
@@ -1,9 +1,4 @@
1
- Copyright (c) 2012 Ryan Fitzgerald
2
-
3
- Includes a modified version of Rumble, which is (c) 2011 Magnus Holm.
4
-
5
- Some Rails integration code inspired by Draper, which is (c) 2011-2012 Jeff
6
- Casimir and other contributors.
1
+ Copyright (c) 2025 Ryan Fitzgerald
7
2
 
8
3
  MIT License
9
4
 
@@ -25,3 +20,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
- # Keynote
1
+ [![Gem Version](https://badge.fury.io/rb/keynote.svg)](https://rubygems.org/gems/keynote)
2
+ [![Build](https://github.com/evilmartians/keynote/workflows/Build/badge.svg)](https://github.com/evilmartians/keynote/actions)
2
3
 
3
- *Flexible presenters for Rails.*
4
+ # Keynote
4
5
 
5
- [![Travis CI](https://api.travis-ci.org/rf-/keynote.png)](https://travis-ci.org/rf-/keynote/builds)
6
- [![Code Climate](https://codeclimate.com/github/rf-/keynote.png)](https://codeclimate.com/github/rf-/keynote)
6
+ > [!TIP]
7
+ > Flexible presenters for Rails.
7
8
 
8
9
  A presenter is an object that encapsulates view logic. Like Rails helpers,
9
10
  presenters help you keep complex logic out of your templates.
@@ -11,16 +12,30 @@ presenters help you keep complex logic out of your templates.
11
12
  Keynote provides a consistent interface for defining and instantiating
12
13
  presenters.
13
14
 
15
+ ## Requirements
16
+
17
+ - Ruby >= 3.0.0
18
+ - Rails >= 7.0
19
+
20
+ For older Ruby and Rails versions, you can use Keynote <2.0.
21
+
14
22
  ## Usage
15
23
 
24
+ Add Keynote to your Gemfile:
25
+
26
+ ```ruby
27
+ gem "keynote", "~> 2.0"
28
+ ```
29
+
30
+ Don't forget to run `bundle install`.
31
+
16
32
  ### The basic idea
17
33
 
18
34
  A simple case is making a presenter that's named after a model class and holds
19
35
  helper methods related to that model.
20
36
 
21
- ``` ruby
37
+ ```ruby
22
38
  # app/presenters/user_presenter.rb
23
-
24
39
  class UserPresenter < Keynote::Presenter
25
40
  presents :user
26
41
 
@@ -29,7 +44,7 @@ class UserPresenter < Keynote::Presenter
29
44
  end
30
45
 
31
46
  def profile_link
32
- link_to user, display_name, data: { user_id: user.id }
47
+ link_to user, display_name, data: {user_id: user.id}
33
48
  end
34
49
  end
35
50
  ```
@@ -55,22 +70,25 @@ Keynote looks for a class called `UserPresenter`.
55
70
 
56
71
  ### Generating HTML
57
72
 
58
- To make it easier to generate slightly more complex chunks of HTML, Keynote
59
- includes a modified version of Magnus Holm's [Rumble](https://github.com/judofyr/rumble)
73
+ To make it easier to generate slightly more complex chunks of HTML, Keynote provides several ways to generate HTML fragments.
74
+
75
+ #### Using `build_html`
76
+
77
+ Keynote includes a modified version of Magnus Holm's [Rumble](https://github.com/judofyr/rumble)
60
78
  library. Rumble gives us a simple block-based syntax for generating HTML
61
79
  fragments. Here's a small example:
62
80
 
63
- ``` ruby
81
+ ```ruby
64
82
  build_html do
65
83
  div id: :content do
66
- h1 'Hello World', class: :main
84
+ h1 "Hello World", class: :main
67
85
  end
68
86
  end
69
87
  ```
70
88
 
71
89
  Becomes:
72
90
 
73
- ``` html
91
+ ```html
74
92
  <div id="content">
75
93
  <h1 class="main">Hello World</h1>
76
94
  </div>
@@ -81,6 +99,32 @@ to the `build_html` method. The `build_html` method returns a safe string. See
81
99
  [the documentation for `Keynote::Rumble`](http://rubydoc.info/gems/keynote/Keynote/Rumble)
82
100
  for more information.
83
101
 
102
+ #### Using inlined partials
103
+
104
+ You can extend your presenter class with the `Keynote::Inline` module to enable inline templating in any template language supported by Rails. This is useful for small, self-contained templates that don't need to be extracted into separate files.
105
+
106
+ ```ruby
107
+ # app/presenters/user_presenter.rb
108
+ class UserPresenter < Keynote::Presenter
109
+ presents :user
110
+
111
+ include Keynote::Inline
112
+ # To user Haml or Slim, enabled them explicitly
113
+ # inline :haml, :slim
114
+
115
+ def profile_link
116
+ erb do
117
+ <<~ERB
118
+ <div class="profile_link">
119
+ <%= link_to user, display_name, data: { user_id: user.id } %>
120
+ <i class="fa-user"></i>
121
+ </div>
122
+ ERB
123
+ end
124
+ end
125
+ end
126
+ ```
127
+
84
128
  ### A more complex example
85
129
 
86
130
  Let's add to our original example by introducing a named presenter. In addition
@@ -158,33 +202,76 @@ end
158
202
  You can also generate prefixed methods like `user_first_name` by passing
159
203
  `prefix: true` to the `delegate` method.
160
204
 
205
+ ## Testing
206
+
207
+ Testing a Keynote presenter is similar to using it in views or controllers. You
208
+ can test presenters with RSpec, Test::Unit, MiniTest, or MiniTest::Unit.
209
+
210
+ ### RSpec
211
+
212
+ Your test files should be in `spec/presenters` or labeled with
213
+ [`type: :presenter` metadata].
214
+
215
+ Here's an example:
216
+
217
+ ```ruby
218
+ # spec/presenters/user_presenter_spec.rb
219
+
220
+ RSpec.describe UserPresenter do
221
+ describe "#display_name" do
222
+ it "returns the name of the user" do
223
+ user = User.new(first_name: "Alice", last_name: "Smith")
224
+
225
+ expect(present(user).display_name).to eq("Alice Smith")
226
+ end
227
+ end
228
+ end
229
+ ```
230
+
231
+ ### MiniTest
232
+
233
+ Your test classes should inherit from Keynote::TestCase.
234
+
235
+ ```ruby
236
+ class UserPresenterTest < Keynote::TestCase
237
+ setup do
238
+ user = User.new(first_name: "Alice", last_name: "Smith")
239
+ @presenter = present(user)
240
+ end
241
+
242
+ test "display name" do
243
+ assert_equal @presenter.display_name, "Alice Smith"
244
+ end
245
+ end
246
+ ```
247
+
161
248
  ## Rationale
162
249
 
163
- ### Why use presenters or decorators at all?
250
+ ### Why use presenters or decorators at all
164
251
 
165
252
  The main alternative is to use helpers. Helpers are fine for many use cases --
166
253
  Rails' built-in tag and form helpers are great. They have some drawbacks,
167
254
  though:
168
255
 
169
- * Every helper method you write gets mixed into the same view object as the
256
+ - Every helper method you write gets mixed into the same view object as the
170
257
  built-in Rails helpers, URL generators, and all the other junk that comes
171
258
  along with `ActionView::Base`. In a freshly-generated Rails project:
172
259
 
173
260
  ```ruby
174
- >> ApplicationController.new.view_context.public_methods.count
175
- => 318
176
- >> ApplicationController.new.view_context.private_methods.count
177
- => 119
261
+ ApplicationController.new.view_context.public_methods.count
262
+ # => 318
263
+ ApplicationController.new.view_context.private_methods.count
264
+ # => 119
178
265
  ```
179
266
 
180
- * Helpers can't have state that isn't "global" relative to the view, which
267
+ - Helpers can't have state that isn't "global" relative to the view, which
181
268
  can make it hard to write helpers that work together.
182
269
 
183
- * By default, every helper is available in every view. This makes it difficult
270
+ - By default, every helper is available in every view. This makes it difficult
184
271
  to set boundaries between different parts of your app and organize your view
185
272
  code cleanly.
186
273
 
187
- ### Why not use decorators?
274
+ ### Why not use decorators
188
275
 
189
276
  The biggest distinction between Keynote and similar libraries like [Draper] and
190
277
  [DisplayCase] is that Keynote presenters aren't decorators – undefined method
@@ -193,17 +280,17 @@ calls don't fall through to an underlying model.
193
280
  Applying the Decorator pattern to generating views is a reasonable thing to do.
194
281
  However, this practice also has some downsides.
195
282
 
196
- * Decorators make the most sense when there's exactly one object that's
283
+ - Decorators make the most sense when there's exactly one object that's
197
284
  relevant to the methods you want to encapsulate. They're less helpful when
198
285
  you want to do things like define a class whose responsibility is to help
199
286
  render a specific part of your user interface, which may involve bringing in
200
287
  data from multiple models or collections.
201
288
 
202
- * When reading code that uses decorators, it often isn't obvious if a given
289
+ - When reading code that uses decorators, it often isn't obvious if a given
203
290
  method is defined on the decorator or the underlying model, especially when
204
291
  the decorator is applied in the controller instead of the view.
205
292
 
206
- * Passing decorated models between controllers and views can make it unclear
293
+ - Passing decorated models between controllers and views can make it unclear
207
294
  whether a view (especially a nested partial) depends on a model having some
208
295
  specific decorator applied to it. This makes refactoring view and decorator
209
296
  code harder than it needs to be.
@@ -214,7 +301,7 @@ Keynote doesn't automatically generate presenters when you generate models or
214
301
  resources. To generate a presenter, you can use the `presenter` generator,
215
302
  like so:
216
303
 
217
- ``` bash
304
+ ```sh
218
305
  $ rails g presenter FooBar foo bar
219
306
  create app/presenters/foo_bar_presenter.rb
220
307
  create spec/presenters/foo_bar_presenter_spec.rb
@@ -223,34 +310,19 @@ $ rails g presenter FooBar foo bar
223
310
  That project uses RSpec, but the generator can also create test files for
224
311
  Test::Unit or MiniTest::Rails if applicable.
225
312
 
226
- ## Compatibility
227
-
228
- Keynote is supported on Rails 3.1 through 5.1. Keynote presenters are testable
229
- with Test::Unit, RSpec, and MiniTest::Rails (>= 2.0).
230
-
231
- If you find problems with any of the above integrations, please open an issue.
313
+ ## Contributing
232
314
 
233
- ## Development
315
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/evilmartians/keynote](https://github.com/evilmartians/keynote).
234
316
 
235
- This repo uses [Roadshow] to generate a [Docker Compose] file for each
236
- supported version of Rails (with a compatible version of Ruby for each one).
317
+ For gem development, clone the repo and run `bundle install` to install the dependencies. Then, run `bundle exec rake` to run the tests.
237
318
 
238
- To run specs across all versions, you can either [get the Roadshow tool] and
239
- run `roadshow run`, or use Docker Compose directly:
240
-
241
- ```
242
- $ for fn in scenarios/*.docker-compose-yml; do docker-compose -f $fn run --rm scenario; done
243
- ```
319
+ (Optionally) Run `bundle exec lefthook install` to configure git hooks (so you never miss linter complaints before opening a PR).
244
320
 
245
- To update the set of scenarios, edit `scenarios.yml` and run `roadshow
246
- generate`, although the Gemfiles in the `scenarios` directory need to be
247
- maintained manually.
321
+ ## License
248
322
 
249
- Feel free to submit pull requests according to the usual conventions for Ruby
250
- projects.
323
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
251
324
 
252
325
  [DisplayCase]: https://github.com/objects-on-rails/display-case
253
326
  [Draper]: https://github.com/drapergem/draper
254
327
  [Roadshow]: https://github.com/rf-/roadshow
255
- [Docker Compose]: https://docs.docker.com/compose/
256
- [get the Roadshow tool]: https://github.com/rf-/roadshow/releases
328
+ [`type: :presenter` metadata]: https://relishapp.com/rspec/rspec-rails/docs/directory-structure
@@ -1,34 +1,29 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Rails::Generators
4
4
  class PresenterGenerator < Rails::Generators::NamedBase
5
5
  desc "This generator creates a Keynote::Presenter subclass in " \
6
6
  "app/presenters."
7
7
 
8
- argument :targets, :type => :array, :default => []
8
+ argument :targets, type: :array, default: []
9
9
 
10
- check_class_collision :suffix => 'Presenter'
11
- source_root File.expand_path('../templates', __FILE__)
10
+ check_class_collision suffix: "Presenter"
11
+ source_root File.expand_path("../templates", __FILE__)
12
12
 
13
13
  def create_presenter_file
14
- template 'keynote_presenter.rb',
15
- File.join('app/presenters', class_path, "#{file_name}_presenter.rb")
14
+ template "keynote_presenter.rb",
15
+ File.join("app/presenters", class_path, "#{file_name}_presenter.rb")
16
16
  end
17
17
 
18
18
  def create_test_file
19
19
  case Rails.application.config.generators.rails[:test_framework]
20
20
  when :rspec
21
- template 'keynote_rspec.rb', rspec_path
22
- when :test_unit
23
- # In Rails 4 this is kind of a weird place to generate tests into.
24
- # Unfortunately it isn't really fixable without changing the Rails
25
- # test tasks, so that's a TODO.
26
- template 'keynote_test_unit.rb', test_unit_path
21
+ template "keynote_rspec.rb", rspec_path
27
22
  when :mini_test
28
23
  if Rails.application.config.generators.mini_test[:spec]
29
- template 'keynote_mini_test_spec.rb', mini_test_path
24
+ template "keynote_mini_test_spec.rb", mini_test_path
30
25
  else
31
- template 'keynote_mini_test_unit.rb', mini_test_path
26
+ template "keynote_mini_test_unit.rb", mini_test_path
32
27
  end
33
28
  end
34
29
  end
@@ -37,29 +32,26 @@ module Rails::Generators
37
32
 
38
33
  def rspec_path
39
34
  File.join(
40
- 'spec/presenters', class_path, "#{file_name}_presenter_spec.rb")
41
- end
42
-
43
- def test_unit_path
44
- File.join(
45
- 'test/unit/presenters', class_path, "#{file_name}_presenter_test.rb")
35
+ "spec/presenters", class_path, "#{file_name}_presenter_spec.rb"
36
+ )
46
37
  end
47
38
 
48
39
  def mini_test_path
49
40
  File.join(
50
- 'test/presenters', class_path, "#{file_name}_presenter_test.rb")
41
+ "test/presenters", class_path, "#{file_name}_presenter_test.rb"
42
+ )
51
43
  end
52
44
 
53
45
  def presenter_name_and_target_list
54
- [presenter_name, *target_names].join(', ')
46
+ [presenter_name, *target_names].join(", ")
55
47
  end
56
48
 
57
49
  def target_list
58
- target_names.join(', ')
50
+ target_names.join(", ")
59
51
  end
60
52
 
61
53
  def presenter_name
62
- class_name.sub(/Presenter$/, '').underscore.to_sym.inspect
54
+ class_name.sub(/Presenter$/, "").underscore.to_sym.inspect
63
55
  end
64
56
 
65
57
  def target_names
data/lib/keynote/cache.rb CHANGED
@@ -1,4 +1,4 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Keynote
4
4
  # `Keynote::Cache` memoizes presenter instances, reducing the overhead of
@@ -1,4 +1,4 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Keynote
4
4
  # `Keynote::Controller` is mixed into `ActionController::Base` and
@@ -7,9 +7,8 @@ module Keynote
7
7
  module Controller
8
8
  # Instantiate a presenter.
9
9
  # @see Keynote.present
10
- def present(*objects, &blk)
11
- Keynote.present(view_context, *objects, &blk)
12
- end
13
- alias k present
10
+ def present(...) = Keynote.present(view_context, ...)
11
+
12
+ alias_method :k, :present
14
13
  end
15
14
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Keynote is a library for defining and instantiating presenters,
4
+ # objects that encapsulate view logic.
5
+ #
6
+ # @see file:README.md
7
+ module Keynote
8
+ class << self
9
+ # Create or retrieve a presenter wrapping zero or more objects.
10
+ # If a block is given, yield the presenter into it.
11
+ #
12
+ # The first parameter is a Rails view context, but you'll usually access
13
+ # this method through `Keynote::Helper#present`,
14
+ # `Keynote::Controller#present`, or `Keynote::Presenter#present`, all of
15
+ # which handle the view context parameter automatically.
16
+ #
17
+ # @see Keynote::Helper#present
18
+ # @see Keynote::Controller#present
19
+ # @see Keynote::Presenter#present
20
+ #
21
+ # @overload present(view, *objects)
22
+ # Return a presenter wrapping the given objects. The type of the
23
+ # presenter will be inferred from the type of the first object.
24
+ # @example
25
+ # present(view, MyModel.new) # => #<MyModelPresenter:0x0001>
26
+ # @param [ActionView::Base] view
27
+ # @param [Array] objects
28
+ # @return [Keynote::Presenter]
29
+ #
30
+ # @overload present(view, presenter_name, *objects)
31
+ # Return a presenter wrapping the given objects. The type of the
32
+ # presenter is specified in underscore form by the first parameter.
33
+ # @example
34
+ # present(view, :foo_bar, MyModel.new) # => #<FooBarPresenter:0x0002>
35
+ # @param [ActionView::Base] view
36
+ # @param [Symbol, String] presenter_name
37
+ # @param [Array] objects
38
+ # @return [Keynote::Presenter]
39
+ #
40
+ def present(view, *objects)
41
+ name = if objects[0].is_a?(Symbol) || objects[0].is_a?(String)
42
+ objects.shift
43
+ else
44
+ presenter_name_from_object(objects[0])
45
+ end
46
+
47
+ Cache.fetch(name, view, *objects) do
48
+ presenter_from_name(name).new(view, *objects).tap do |presenter|
49
+ yield presenter if block_given?
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def presenter_name_from_object(object)
57
+ object.class.to_s.underscore
58
+ end
59
+
60
+ def presenter_from_name(name)
61
+ "#{name.to_s.camelize}Presenter".constantize
62
+ end
63
+ end
64
+ end
@@ -1,4 +1,4 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Keynote
4
4
  # `Keynote::Helper` is mixed into `ActionView::Base`, providing a `present`
@@ -6,9 +6,8 @@ module Keynote
6
6
  module Helper
7
7
  # Instantiate a presenter.
8
8
  # @see Keynote.present
9
- def present(*objects, &blk)
10
- Keynote.present(self, *objects, &blk)
11
- end
12
- alias k present
9
+ def present(...) = Keynote.present(self, ...)
10
+
11
+ alias_method :k, :present
13
12
  end
14
13
  end