keynote 1.1.1 → 2.0.1

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 +71 -27
  3. data/{LICENSE → LICENSE.txt} +2 -6
  4. data/README.md +120 -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 +21 -12
  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 +80 -94
  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 -277
  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: 64c6e356ea86e3651f4e24130d64721fa732e4c2
4
- data.tar.gz: f1f80b122aa7a00889387fe3c729154e511d21d9
2
+ SHA256:
3
+ metadata.gz: 6480d040e261aa0c6dc440cc03dfecee2412879cd3b22d9de14017a695db9498
4
+ data.tar.gz: 6184a50a865df219ac3c2b695f55e9ba0a42c101a207c1ca72c33478e5305c86
5
5
  SHA512:
6
- metadata.gz: 4de4ec39b7914dc0b09e3a845211b655fe173392082a1ad99ae4ea37241eb1c21c6a75c33a234379a2d476f24fe5b4c93ae3e3bfb3ae3221baeef0c9bb481c4a
7
- data.tar.gz: ba955f38dc0a98555a4cc271309ad247ddb62085cee8566a900cd976a63ac97d4cb2d1cfb92eaf1c887ad5a6a78597a9f3723e226eb96ca8e794c6f198c7d623
6
+ metadata.gz: 96cd541abbe0f0e34094950675247762228576a52aa6bafd10e94b72169d9b7a48cb39545f5953248236c461823cd063bd57d57283d761711a0d98a30afdac4a
7
+ data.tar.gz: ed283258c3774d6f093efab441f9adeb58e35e8b0a60d79b929ec383ab084e5e91bbfeadb7f868cfb601b8dd53640a5c4f22ac3eb7cc84985262ed5078f63c5d
data/CHANGELOG.md CHANGED
@@ -1,62 +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
+
1
28
  ## v1.1.1
2
- * Rumble: Fix passing `true` as an attribute value, which was broken by the
3
- escaping changes in v1.0.0. (@igas)
29
+
30
+ - Rumble: Fix passing `true` as an attribute value, which was broken by the
31
+ escaping changes in v1.0.0. [@igas][]
4
32
 
5
33
  ## v1.1.0
6
- * 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`
7
36
  value for an attribute.
8
- * 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`.
9
38
 
10
39
  ## v1.0.0
11
- * Add support for Rails 5.1.
12
- * Fix all Ruby warnings generated by Keynote itself.
13
- * 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
14
44
  is already marked as HTML-safe.
15
- * Rumble: Allow user to pass in a `data` hash to generate data attributes.
16
- * 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
17
47
  joined by spaces.
18
48
 
19
49
  ## v0.3.1
20
- * Add support for Rails 5.0. (@dra)
50
+
51
+ - Add support for Rails 5.0. [@dra][]
21
52
 
22
53
  ## v0.3.0
23
- * Drop support for Rails 3.0 and Ruby 1.9.2; add support for Rails 4.2.
24
- * Drop support for MiniTest::Rails versions older than 2.0; add support for 2.0
25
- 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][]
26
58
 
27
59
  ## v0.2.3
28
- * 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
29
62
  `Keynote.present` as an alternative to passing a symbol. This makes it less
30
63
  awkward to use namespaced presenters, but it does remove the possibility of
31
64
  defining a `StringPresenter` and using it with code like
32
65
  `k('some string').format_as_markdown`. It seems unlikely that anyone is
33
- actually doing that though. (@outpunk)
34
- * Update RSpec integration to not print deprecation warnings with RSpec 3.
35
- (@DarthSim)
66
+ actually doing that though. [@outpunk][]
67
+ - Update RSpec integration to not print deprecation warnings with RSpec 3.
68
+ [@DarthSim][]
36
69
 
37
70
  ## v0.2.2
38
- * 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
39
73
  Gemfile included rspec-rails but not the rspec gem itself.
40
- * 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.
41
75
 
42
76
  ## v0.2.1
43
- * 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,
44
79
  JRuby, Rails 3.0/3.1/3.2/4.0/4.1.
45
- * 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
46
81
  Keynote's RSpec integration from loading correctly.
47
82
 
48
83
  ## v0.2.0
49
- * 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
50
86
  templating in any language supported by Rails.
51
- * 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
52
88
  complete set of Rumble tag methods to the class.
53
- * 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
54
90
  symbols that have been passed into the `presents` method.
55
- * 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
56
92
  cases. Update test generators accordingly.
57
- * Update minitest-rails integration to be compatible with the newest
93
+ - Update minitest-rails integration to be compatible with the newest
58
94
  version of minitest-rails (on Rails 3.0, 3.1, 3.2, and 4.0).
59
95
 
60
96
  ## v0.1.3
61
- * 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
62
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,11 @@
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)
3
+ [![Docs](https://img.shields.io/badge/docs-link-blue.svg)](https://rubydoc.info/gems/keynote)
2
4
 
3
- *Flexible presenters for Rails.*
5
+ # Keynote
4
6
 
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)
7
+ > [!TIP]
8
+ > Flexible presenters for Rails.
7
9
 
8
10
  A presenter is an object that encapsulates view logic. Like Rails helpers,
9
11
  presenters help you keep complex logic out of your templates.
@@ -11,16 +13,30 @@ presenters help you keep complex logic out of your templates.
11
13
  Keynote provides a consistent interface for defining and instantiating
12
14
  presenters.
13
15
 
16
+ ## Requirements
17
+
18
+ - Ruby >= 3.0.0
19
+ - Rails >= 7.0
20
+
21
+ For older Ruby and Rails versions, you can use Keynote <2.0.
22
+
14
23
  ## Usage
15
24
 
25
+ Add Keynote to your Gemfile:
26
+
27
+ ```ruby
28
+ gem "keynote", "~> 2.0"
29
+ ```
30
+
31
+ Don't forget to run `bundle install`.
32
+
16
33
  ### The basic idea
17
34
 
18
35
  A simple case is making a presenter that's named after a model class and holds
19
36
  helper methods related to that model.
20
37
 
21
- ``` ruby
38
+ ```ruby
22
39
  # app/presenters/user_presenter.rb
23
-
24
40
  class UserPresenter < Keynote::Presenter
25
41
  presents :user
26
42
 
@@ -29,7 +45,7 @@ class UserPresenter < Keynote::Presenter
29
45
  end
30
46
 
31
47
  def profile_link
32
- link_to user, display_name, data: { user_id: user.id }
48
+ link_to user, display_name, data: {user_id: user.id}
33
49
  end
34
50
  end
35
51
  ```
@@ -55,22 +71,25 @@ Keynote looks for a class called `UserPresenter`.
55
71
 
56
72
  ### Generating HTML
57
73
 
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)
74
+ To make it easier to generate slightly more complex chunks of HTML, Keynote provides several ways to generate HTML fragments.
75
+
76
+ #### Using `build_html`
77
+
78
+ Keynote includes a modified version of Magnus Holm's [Rumble](https://github.com/judofyr/rumble)
60
79
  library. Rumble gives us a simple block-based syntax for generating HTML
61
80
  fragments. Here's a small example:
62
81
 
63
- ``` ruby
82
+ ```ruby
64
83
  build_html do
65
84
  div id: :content do
66
- h1 'Hello World', class: :main
85
+ h1 "Hello World", class: :main
67
86
  end
68
87
  end
69
88
  ```
70
89
 
71
90
  Becomes:
72
91
 
73
- ``` html
92
+ ```html
74
93
  <div id="content">
75
94
  <h1 class="main">Hello World</h1>
76
95
  </div>
@@ -81,6 +100,32 @@ to the `build_html` method. The `build_html` method returns a safe string. See
81
100
  [the documentation for `Keynote::Rumble`](http://rubydoc.info/gems/keynote/Keynote/Rumble)
82
101
  for more information.
83
102
 
103
+ #### Using inlined partials
104
+
105
+ 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.
106
+
107
+ ```ruby
108
+ # app/presenters/user_presenter.rb
109
+ class UserPresenter < Keynote::Presenter
110
+ presents :user
111
+
112
+ include Keynote::Inline
113
+ # To user Haml or Slim, enabled them explicitly
114
+ # inline :haml, :slim
115
+
116
+ def profile_link
117
+ erb do
118
+ <<~ERB
119
+ <div class="profile_link">
120
+ <%= link_to user, display_name, data: { user_id: user.id } %>
121
+ <i class="fa-user"></i>
122
+ </div>
123
+ ERB
124
+ end
125
+ end
126
+ end
127
+ ```
128
+
84
129
  ### A more complex example
85
130
 
86
131
  Let's add to our original example by introducing a named presenter. In addition
@@ -158,33 +203,76 @@ end
158
203
  You can also generate prefixed methods like `user_first_name` by passing
159
204
  `prefix: true` to the `delegate` method.
160
205
 
206
+ ## Testing
207
+
208
+ Testing a Keynote presenter is similar to using it in views or controllers. You
209
+ can test presenters with RSpec, Test::Unit, MiniTest, or MiniTest::Unit.
210
+
211
+ ### RSpec
212
+
213
+ Your test files should be in `spec/presenters` or labeled with
214
+ [`type: :presenter` metadata].
215
+
216
+ Here's an example:
217
+
218
+ ```ruby
219
+ # spec/presenters/user_presenter_spec.rb
220
+
221
+ RSpec.describe UserPresenter do
222
+ describe "#display_name" do
223
+ it "returns the name of the user" do
224
+ user = User.new(first_name: "Alice", last_name: "Smith")
225
+
226
+ expect(present(user).display_name).to eq("Alice Smith")
227
+ end
228
+ end
229
+ end
230
+ ```
231
+
232
+ ### MiniTest
233
+
234
+ Your test classes should inherit from Keynote::TestCase.
235
+
236
+ ```ruby
237
+ class UserPresenterTest < Keynote::TestCase
238
+ setup do
239
+ user = User.new(first_name: "Alice", last_name: "Smith")
240
+ @presenter = present(user)
241
+ end
242
+
243
+ test "display name" do
244
+ assert_equal @presenter.display_name, "Alice Smith"
245
+ end
246
+ end
247
+ ```
248
+
161
249
  ## Rationale
162
250
 
163
- ### Why use presenters or decorators at all?
251
+ ### Why use presenters or decorators at all
164
252
 
165
253
  The main alternative is to use helpers. Helpers are fine for many use cases --
166
254
  Rails' built-in tag and form helpers are great. They have some drawbacks,
167
255
  though:
168
256
 
169
- * Every helper method you write gets mixed into the same view object as the
257
+ - Every helper method you write gets mixed into the same view object as the
170
258
  built-in Rails helpers, URL generators, and all the other junk that comes
171
259
  along with `ActionView::Base`. In a freshly-generated Rails project:
172
260
 
173
261
  ```ruby
174
- >> ApplicationController.new.view_context.public_methods.count
175
- => 318
176
- >> ApplicationController.new.view_context.private_methods.count
177
- => 119
262
+ ApplicationController.new.view_context.public_methods.count
263
+ # => 318
264
+ ApplicationController.new.view_context.private_methods.count
265
+ # => 119
178
266
  ```
179
267
 
180
- * Helpers can't have state that isn't "global" relative to the view, which
268
+ - Helpers can't have state that isn't "global" relative to the view, which
181
269
  can make it hard to write helpers that work together.
182
270
 
183
- * By default, every helper is available in every view. This makes it difficult
271
+ - By default, every helper is available in every view. This makes it difficult
184
272
  to set boundaries between different parts of your app and organize your view
185
273
  code cleanly.
186
274
 
187
- ### Why not use decorators?
275
+ ### Why not use decorators
188
276
 
189
277
  The biggest distinction between Keynote and similar libraries like [Draper] and
190
278
  [DisplayCase] is that Keynote presenters aren't decorators – undefined method
@@ -193,17 +281,17 @@ calls don't fall through to an underlying model.
193
281
  Applying the Decorator pattern to generating views is a reasonable thing to do.
194
282
  However, this practice also has some downsides.
195
283
 
196
- * Decorators make the most sense when there's exactly one object that's
284
+ - Decorators make the most sense when there's exactly one object that's
197
285
  relevant to the methods you want to encapsulate. They're less helpful when
198
286
  you want to do things like define a class whose responsibility is to help
199
287
  render a specific part of your user interface, which may involve bringing in
200
288
  data from multiple models or collections.
201
289
 
202
- * When reading code that uses decorators, it often isn't obvious if a given
290
+ - When reading code that uses decorators, it often isn't obvious if a given
203
291
  method is defined on the decorator or the underlying model, especially when
204
292
  the decorator is applied in the controller instead of the view.
205
293
 
206
- * Passing decorated models between controllers and views can make it unclear
294
+ - Passing decorated models between controllers and views can make it unclear
207
295
  whether a view (especially a nested partial) depends on a model having some
208
296
  specific decorator applied to it. This makes refactoring view and decorator
209
297
  code harder than it needs to be.
@@ -214,7 +302,7 @@ Keynote doesn't automatically generate presenters when you generate models or
214
302
  resources. To generate a presenter, you can use the `presenter` generator,
215
303
  like so:
216
304
 
217
- ``` bash
305
+ ```sh
218
306
  $ rails g presenter FooBar foo bar
219
307
  create app/presenters/foo_bar_presenter.rb
220
308
  create spec/presenters/foo_bar_presenter_spec.rb
@@ -223,34 +311,19 @@ $ rails g presenter FooBar foo bar
223
311
  That project uses RSpec, but the generator can also create test files for
224
312
  Test::Unit or MiniTest::Rails if applicable.
225
313
 
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.
314
+ ## Contributing
232
315
 
233
- ## Development
316
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/evilmartians/keynote](https://github.com/evilmartians/keynote).
234
317
 
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).
318
+ For gem development, clone the repo and run `bundle install` to install the dependencies. Then, run `bundle exec rake` to run the tests.
237
319
 
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
- ```
320
+ (Optionally) Run `bundle exec lefthook install` to configure git hooks (so you never miss linter complaints before opening a PR).
244
321
 
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.
322
+ ## License
248
323
 
249
- Feel free to submit pull requests according to the usual conventions for Ruby
250
- projects.
324
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
251
325
 
252
326
  [DisplayCase]: https://github.com/objects-on-rails/display-case
253
327
  [Draper]: https://github.com/drapergem/draper
254
328
  [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
329
+ [`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