keynote 1.1.1 → 2.0.1
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +71 -27
- data/{LICENSE → LICENSE.txt} +2 -6
- data/README.md +120 -47
- data/lib/generators/presenter_generator.rb +16 -24
- data/lib/keynote/cache.rb +1 -1
- data/lib/keynote/controller.rb +4 -5
- data/lib/keynote/core.rb +64 -0
- data/lib/keynote/helper.rb +4 -5
- data/lib/keynote/inline.rb +51 -109
- data/lib/keynote/presenter.rb +13 -19
- data/lib/keynote/railtie.rb +7 -24
- data/lib/keynote/rumble.rb +21 -12
- data/lib/keynote/testing/{minitest_rails.rb → minitest.rb} +1 -2
- data/lib/keynote/testing/rspec.rb +5 -5
- data/lib/keynote/testing/test_present_method.rb +2 -2
- data/lib/keynote/testing/test_unit.rb +1 -1
- data/lib/keynote/version.rb +2 -2
- data/lib/keynote.rb +7 -65
- metadata +80 -94
- data/.editorconfig +0 -14
- data/.gitignore +0 -18
- data/.travis.yml +0 -11
- data/.yardopts +0 -4
- data/Gemfile +0 -4
- data/Rakefile +0 -21
- data/keynote.gemspec +0 -37
- data/lib/generators/templates/keynote_mini_test_unit.rb +0 -11
- data/lib/keynote/testing/minitest_rails.rake +0 -7
- data/scenarios/rails31.docker-compose.yml +0 -15
- data/scenarios/rails31.dockerfile +0 -5
- data/scenarios/rails31.gemfile +0 -7
- data/scenarios/rails32.docker-compose.yml +0 -15
- data/scenarios/rails32.dockerfile +0 -5
- data/scenarios/rails32.gemfile +0 -6
- data/scenarios/rails40.docker-compose.yml +0 -15
- data/scenarios/rails40.dockerfile +0 -5
- data/scenarios/rails40.gemfile +0 -6
- data/scenarios/rails41.docker-compose.yml +0 -15
- data/scenarios/rails41.dockerfile +0 -5
- data/scenarios/rails41.gemfile +0 -6
- data/scenarios/rails42.docker-compose.yml +0 -15
- data/scenarios/rails42.dockerfile +0 -5
- data/scenarios/rails42.gemfile +0 -6
- data/scenarios/rails50.docker-compose.yml +0 -15
- data/scenarios/rails50.dockerfile +0 -5
- data/scenarios/rails50.gemfile +0 -6
- data/scenarios/rails51.docker-compose.yml +0 -15
- data/scenarios/rails51.dockerfile +0 -5
- data/scenarios/rails51.gemfile +0 -6
- data/scenarios.yml +0 -25
- data/spec/benchmarks.rb +0 -73
- data/spec/generator_spec.rb +0 -159
- data/spec/helper.rb +0 -90
- data/spec/inline_spec.rb +0 -157
- data/spec/keynote_spec.rb +0 -130
- data/spec/presenter_spec.rb +0 -179
- data/spec/railtie_spec.rb +0 -33
- data/spec/rumble_spec.rb +0 -277
- data/spec/test_case_spec.rb +0 -12
- /data/lib/generators/templates/{keynote_mini_test_spec.rb → keynote_mini_test_spec.rb.tt} +0 -0
- /data/lib/generators/templates/{keynote_test_unit.rb → keynote_mini_test_unit.rb.tt} +0 -0
- /data/lib/generators/templates/{keynote_presenter.rb → keynote_presenter.rb.tt} +0 -0
- /data/lib/generators/templates/{keynote_rspec.rb → keynote_rspec.rb.tt} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6480d040e261aa0c6dc440cc03dfecee2412879cd3b22d9de14017a695db9498
|
4
|
+
data.tar.gz: 6184a50a865df219ac3c2b695f55e9ba0a42c101a207c1ca72c33478e5305c86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
3
|
-
|
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
|
-
|
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
|
-
|
37
|
+
- Rumble: Add support for `aria` attr hashes, behaving the same way as `data`.
|
9
38
|
|
10
39
|
## v1.0.0
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
16
|
-
|
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
|
-
|
50
|
+
|
51
|
+
- Add support for Rails 5.0. [@dra][]
|
21
52
|
|
22
53
|
## v0.3.0
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
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.
|
34
|
-
|
35
|
-
|
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
|
-
|
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
|
-
|
74
|
+
- Fix a bug in the generation of specs for zero-arg presenters.
|
41
75
|
|
42
76
|
## v0.2.1
|
43
|
-
|
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
|
-
|
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
|
-
|
84
|
+
|
85
|
+
- Add `Keynote::Inline`, a module that presenters can extend to enable inline
|
50
86
|
templating in any language supported by Rails.
|
51
|
-
|
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
|
-
|
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
|
-
|
91
|
+
- Add an implementation of the `present`/`k` method that's available in test
|
56
92
|
cases. Update test generators accordingly.
|
57
|
-
|
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
|
-
|
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
|
data/{LICENSE → LICENSE.txt}
RENAMED
@@ -1,9 +1,4 @@
|
|
1
|
-
Copyright (c)
|
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
|
-
|
1
|
+
[](https://rubygems.org/gems/keynote)
|
2
|
+
[](https://github.com/evilmartians/keynote/actions)
|
3
|
+
[](https://rubydoc.info/gems/keynote)
|
2
4
|
|
3
|
-
|
5
|
+
# Keynote
|
4
6
|
|
5
|
-
[!
|
6
|
-
|
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
|
-
```
|
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: {
|
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
|
-
|
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
|
-
```
|
82
|
+
```ruby
|
64
83
|
build_html do
|
65
84
|
div id: :content do
|
66
|
-
h1
|
85
|
+
h1 "Hello World", class: :main
|
67
86
|
end
|
68
87
|
end
|
69
88
|
```
|
70
89
|
|
71
90
|
Becomes:
|
72
91
|
|
73
|
-
```
|
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
|
-
|
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
|
-
|
175
|
-
=> 318
|
176
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
```
|
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
|
-
##
|
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
|
-
|
316
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/evilmartians/keynote](https://github.com/evilmartians/keynote).
|
234
317
|
|
235
|
-
|
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
|
-
|
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
|
-
|
246
|
-
generate`, although the Gemfiles in the `scenarios` directory need to be
|
247
|
-
maintained manually.
|
322
|
+
## License
|
248
323
|
|
249
|
-
|
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
|
-
[
|
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
|
-
#
|
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, :
|
8
|
+
argument :targets, type: :array, default: []
|
9
9
|
|
10
|
-
check_class_collision :
|
11
|
-
source_root File.expand_path(
|
10
|
+
check_class_collision suffix: "Presenter"
|
11
|
+
source_root File.expand_path("../templates", __FILE__)
|
12
12
|
|
13
13
|
def create_presenter_file
|
14
|
-
template
|
15
|
-
File.join(
|
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
|
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
|
24
|
+
template "keynote_mini_test_spec.rb", mini_test_path
|
30
25
|
else
|
31
|
-
template
|
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
|
-
|
41
|
-
|
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
|
-
|
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$/,
|
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
data/lib/keynote/controller.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
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(
|
11
|
-
|
12
|
-
|
13
|
-
alias k present
|
10
|
+
def present(...) = Keynote.present(view_context, ...)
|
11
|
+
|
12
|
+
alias_method :k, :present
|
14
13
|
end
|
15
14
|
end
|
data/lib/keynote/core.rb
ADDED
@@ -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
|
data/lib/keynote/helper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
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(
|
10
|
-
|
11
|
-
|
12
|
-
alias k present
|
9
|
+
def present(...) = Keynote.present(self, ...)
|
10
|
+
|
11
|
+
alias_method :k, :present
|
13
12
|
end
|
14
13
|
end
|