detaso-oprah 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +18 -0
- data/CHANGELOG.md +39 -0
- data/CONTRIBUTING.md +86 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +314 -0
- data/Rakefile +5 -0
- data/lib/oprah/controller_helpers.rb +109 -0
- data/lib/oprah/presenter.rb +149 -0
- data/lib/oprah/railtie.rb +27 -0
- data/lib/oprah/test_helpers.rb +47 -0
- data/lib/oprah/version.rb +4 -0
- data/lib/oprah.rb +43 -0
- data/oprah.gemspec +31 -0
- data/tasks/bundler.rb +5 -0
- data/tasks/console.rb +35 -0
- data/tasks/minitest.rb +8 -0
- data/tasks/yard.rb +16 -0
- data/test/controllers/posts_controller_test.rb +10 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/posts_controller.rb +5 -0
- data/test/dummy/app/mailers/application_mailer.rb +2 -0
- data/test/dummy/app/mailers/post_mailer.rb +8 -0
- data/test/dummy/app/models/post.rb +2 -0
- data/test/dummy/app/presenters/post_presenter.rb +5 -0
- data/test/dummy/app/views/post_mailer/notification.html.erb +3 -0
- data/test/dummy/app/views/posts/show.html.erb +3 -0
- data/test/dummy/config/database.yml +6 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/init.rb +29 -0
- data/test/dummy/tmp/.gitkeep +0 -0
- data/test/helper.rb +84 -0
- data/test/mailers/post_mailer_test.rb +13 -0
- data/test/oprah/controller_helpers_test.rb +65 -0
- data/test/oprah/oprah_test.rb +17 -0
- data/test/oprah/presenter_test.rb +182 -0
- data/test/oprah/railtie_test.rb +19 -0
- metadata +226 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1ee902d46e66b0a39b778241c9d18a8202dab24713ffaf4389b9ba3e43da831c
|
4
|
+
data.tar.gz: 8a611ae249feb8c39c849201cd463cd269b3f532de9f7fcdac8f5fe8fc296b07
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d42a4b5ca87c66396eab35e4f6a53f75078a2e6fd1b4ac48ab91161d63ec727ea3395047ca6b348b9be1d2e6194a635690a92c1df1252284db277251b31b3069
|
7
|
+
data.tar.gz: bd2947f1f69df130f0c96101a08ff3ee4a982509ad7c6285f039961a7c1a6e0977ba791552d85ff51279b9b9ac12e873f3f635d78450b2a95dff5f783e0cd72b
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
language: ruby
|
2
|
+
sudo: false
|
3
|
+
cache: bundler
|
4
|
+
script: bundle exec rake test
|
5
|
+
rvm:
|
6
|
+
- 2.3.1
|
7
|
+
matrix:
|
8
|
+
global:
|
9
|
+
- BUNDLE_JOBS=4
|
10
|
+
before_install:
|
11
|
+
- bundle install --retry=3
|
12
|
+
before_update:
|
13
|
+
- bundle update
|
14
|
+
notifications:
|
15
|
+
email: false
|
16
|
+
addons:
|
17
|
+
code_climate:
|
18
|
+
repo_token: 3d9c9c681c7be79695156ecbf9978ada542e60b726a7ba728866dee6f95f3ccd
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
0.3.0
|
2
|
+
-----
|
3
|
+
|
4
|
+
- Presenter now inherits from SimpleDelegator
|
5
|
+
- Support for anonymous ancestors [#9]
|
6
|
+
|
7
|
+
|
8
|
+
0.2.1
|
9
|
+
-----
|
10
|
+
|
11
|
+
- Support for ActionMailer
|
12
|
+
|
13
|
+
0.2.0
|
14
|
+
-----
|
15
|
+
|
16
|
+
- Replace `Oprah::Cache` with `ActiveSupport::Cache::MemoryStore` [#3]
|
17
|
+
|
18
|
+
0.1.3
|
19
|
+
-----
|
20
|
+
|
21
|
+
- Presenters can now be specified using the `only:` keyword argument, which
|
22
|
+
takes either a Class or an Array of classes
|
23
|
+
- Replace repeated method default arguments with splats
|
24
|
+
- Add assertions to TestHelper
|
25
|
+
- Delegate to most recent view context in presenters created from within Rails
|
26
|
+
controllers [#1]
|
27
|
+
- Add `#present` and `#present_many` methods to Presenter [#2]
|
28
|
+
|
29
|
+
0.1.2
|
30
|
+
-----
|
31
|
+
|
32
|
+
- Explicitly rescue `NameError` in `Cache#presenter_classes_for`
|
33
|
+
- Add `Oprah::TestHelpers`
|
34
|
+
- Delegate `#to_s` and `#inspect` to the presented object
|
35
|
+
|
36
|
+
0.1.1
|
37
|
+
-----
|
38
|
+
|
39
|
+
- Initial public release
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
When contributing to this repository, please first discuss the change you wish
|
4
|
+
to make via issue, email, or any other method with the owners of this repository
|
5
|
+
before making a change.
|
6
|
+
|
7
|
+
Please note we have a code of conduct, please follow it in all your interactions
|
8
|
+
with the project.
|
9
|
+
|
10
|
+
## Pull Request Process
|
11
|
+
|
12
|
+
If you'd like to contribute to Oprah, start by forking the repository on GitHub:
|
13
|
+
|
14
|
+
http://github.com/endofunky/oprah
|
15
|
+
|
16
|
+
To get all of the dependencies, install the gem first. The best way to get your
|
17
|
+
changes merged back into core is as follows:
|
18
|
+
|
19
|
+
- If you are about to add a larger feature, open an issue on the GitHub issue
|
20
|
+
tracker to discuss your ideas first. If whatever you're about to implement is
|
21
|
+
already in the issue tracker, please let us know that you picked it up.
|
22
|
+
|
23
|
+
- Clone down your fork.
|
24
|
+
|
25
|
+
- Create a thoughtfully named topic branch to contain your change.
|
26
|
+
|
27
|
+
- Write some code.
|
28
|
+
|
29
|
+
- Add tests and make sure everything still passes by running bundle exec rake.
|
30
|
+
This is mandatory for pull requests to be accepted.
|
31
|
+
|
32
|
+
- If you are adding new functionality, document it!
|
33
|
+
|
34
|
+
- Do not change the version number.
|
35
|
+
|
36
|
+
- If necessary, rebase your commits into logical chunks, without errors.
|
37
|
+
|
38
|
+
- Push the branch up to GitHub.
|
39
|
+
|
40
|
+
- Send a pull request to the endofunky/oprah project.
|
41
|
+
|
42
|
+
## Contributor Code of Conduct
|
43
|
+
|
44
|
+
As contributors and maintainers of this project, and in the interest of
|
45
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
46
|
+
contribute through reporting issues, posting feature requests, updating
|
47
|
+
documentation, submitting pull requests or patches, and other activities.
|
48
|
+
|
49
|
+
We are committed to making participation in this project a harassment-free
|
50
|
+
experience for everyone, regardless of level of experience, gender, gender
|
51
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
52
|
+
body size, race, ethnicity, age, religion, or nationality.
|
53
|
+
|
54
|
+
Examples of unacceptable behavior by participants include:
|
55
|
+
|
56
|
+
- The use of sexualized language or imagery
|
57
|
+
|
58
|
+
- Personal attacks
|
59
|
+
|
60
|
+
- Trolling or insulting/derogatory comments
|
61
|
+
|
62
|
+
- Public or private harassment
|
63
|
+
|
64
|
+
- Publishing other's private information, such as physical or electronic
|
65
|
+
addresses, without explicit permission
|
66
|
+
|
67
|
+
- Other unethical or unprofessional conduct.
|
68
|
+
|
69
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
70
|
+
reject comments, commits, code, wiki edits, issues, and other contributions that
|
71
|
+
are not aligned to this Code of Conduct. By adopting this Code of Conduct,
|
72
|
+
project maintainers commit themselves to fairly and consistently applying these
|
73
|
+
principles to every aspect of managing this project. Project maintainers who do
|
74
|
+
not follow or enforce the Code of Conduct may be permanently removed from the
|
75
|
+
project team.
|
76
|
+
|
77
|
+
This code of conduct applies both within project spaces and in public spaces
|
78
|
+
when an individual is representing the project or its community.
|
79
|
+
|
80
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
81
|
+
reported by opening an issue or contacting one or more of the project
|
82
|
+
maintainers.
|
83
|
+
|
84
|
+
This Code of Conduct is adapted from the
|
85
|
+
[Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
|
86
|
+
available at http://contributor-covenant.org/version/1/2/0/
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2016 Tobias Svensson <tob@tobiassvensson.co.uk>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,314 @@
|
|
1
|
+
# Oprah
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/oprah)
|
4
|
+
[](https://travis-ci.org/endofunky/oprah)
|
5
|
+
[](https://codeclimate.com/github/endofunky/oprah)
|
6
|
+
[](https://gemnasium.com/github.com/endofunky/oprah)
|
7
|
+
|
8
|
+
Opinionated presenters for Rails 5 - without the cruft.
|
9
|
+
|
10
|
+
## Table of Contents
|
11
|
+
|
12
|
+
* [Overview](#overview)
|
13
|
+
* [Installation](#installation)
|
14
|
+
* [Getting started](#getting-started)
|
15
|
+
+ [ActionController integration](#actioncontroller-integration)
|
16
|
+
+ [ActionMailer integration](#actionmailer-integration)
|
17
|
+
* [Collections](#collections)
|
18
|
+
* [Associations](#associations)
|
19
|
+
* [Composition](#composition)
|
20
|
+
+ [Performance](#performance)
|
21
|
+
+ [Ordering](#ordering)
|
22
|
+
+ [Choosing presenters](#choosing-presenters)
|
23
|
+
* [Testing](#testing)
|
24
|
+
* [API Documentation](#api-documentation)
|
25
|
+
* [Contributing](#contributing)
|
26
|
+
* [License](#license)
|
27
|
+
* [Author](#author)
|
28
|
+
|
29
|
+
## Overview
|
30
|
+
|
31
|
+
If you've ever worked on a sufficiently large Rails application you've probably
|
32
|
+
experienced the Rails helper mess first hand. Helper methods are annoying to
|
33
|
+
locate, hard to test and not terribly expressive.
|
34
|
+
|
35
|
+
So why another presenter/decorator library? Oprah was written with a few simple
|
36
|
+
goals in mind only covered partially (or not at all) by other gems:
|
37
|
+
|
38
|
+
- Thin, lightweight layer over Ruby's `SimpleDelegator`
|
39
|
+
- Presenters should be easy to test
|
40
|
+
- Avoid monkey patching, where possible :monkey::gun:
|
41
|
+
- Embrace convention over configuration
|
42
|
+
- First-class support for composition (modules and concerns)
|
43
|
+
|
44
|
+
## Installation
|
45
|
+
|
46
|
+
Add this line to your application's Gemfile:
|
47
|
+
|
48
|
+
``` ruby
|
49
|
+
gem 'oprah'
|
50
|
+
```
|
51
|
+
|
52
|
+
And then execute:
|
53
|
+
|
54
|
+
```
|
55
|
+
$ bundle
|
56
|
+
```
|
57
|
+
|
58
|
+
## Getting started
|
59
|
+
|
60
|
+
Oprah expects a single presenter for each of your classes or modules. If your
|
61
|
+
model is called `User` it will look for a class called `UserPresenter`:
|
62
|
+
|
63
|
+
``` ruby
|
64
|
+
class User
|
65
|
+
def first_name
|
66
|
+
"John"
|
67
|
+
end
|
68
|
+
|
69
|
+
def last_name
|
70
|
+
"Doe"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class UserPresenter < Oprah::Presenter
|
75
|
+
def name
|
76
|
+
"#{first_name} #{last_name}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
Oprah will figure out the presenters by itself so you don't have to instantiate
|
82
|
+
your presenter classes directly:
|
83
|
+
|
84
|
+
``` ruby
|
85
|
+
presenter = Oprah.present(User.new)
|
86
|
+
|
87
|
+
presenter.name
|
88
|
+
# => "John Doe"
|
89
|
+
|
90
|
+
```
|
91
|
+
|
92
|
+
Of course, all the regular methods on your model are still accessible:
|
93
|
+
|
94
|
+
``` ruby
|
95
|
+
presenter.first_name
|
96
|
+
# => "John"
|
97
|
+
```
|
98
|
+
|
99
|
+
If you *DO* want to use a specific presenter, you can simply instantiate it
|
100
|
+
yourself:
|
101
|
+
|
102
|
+
``` ruby
|
103
|
+
SomeOtherPresenter.new(User.new)
|
104
|
+
```
|
105
|
+
|
106
|
+
### ActionController integration
|
107
|
+
|
108
|
+
Now, where do we put our presenters? Ideally, you'd want to expose them in your
|
109
|
+
controller. Oprah avoids monkey patching and generally it's good to be aware of
|
110
|
+
what's going on, even if that means to be (at least a little bit) explicit.
|
111
|
+
|
112
|
+
Here's how you can use Oprah presenters from your controller:
|
113
|
+
|
114
|
+
``` ruby
|
115
|
+
class UsersController < ApplicationController
|
116
|
+
def show
|
117
|
+
@user = present User.find(params[:id])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
This will also take care of passing the correct view context to the presenter,
|
123
|
+
which you can access with the `#view_context` (or shorter, `#h`) instance
|
124
|
+
method.
|
125
|
+
|
126
|
+
### ActionMailer integration
|
127
|
+
|
128
|
+
Oprah will make the same helpers you have in ActionController available to
|
129
|
+
ActionMailer:
|
130
|
+
|
131
|
+
``` ruby
|
132
|
+
class UserMailer < ApplicationMailer
|
133
|
+
default from: 'notifications@example.com'
|
134
|
+
|
135
|
+
def welcome_email(user)
|
136
|
+
@user = present user
|
137
|
+
mail(to: @user.email, subject: 'Welcome to My Awesome Site')
|
138
|
+
end
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
## Collections
|
143
|
+
|
144
|
+
Oprah has basic support for collections with `.present_many`. It will simply
|
145
|
+
apply it's `.present` behavior to each object in the given collection:
|
146
|
+
|
147
|
+
``` ruby
|
148
|
+
users = [User.new, User.new]
|
149
|
+
presenters = Oprah.present_many(users)
|
150
|
+
|
151
|
+
presenters.first.kind_of?(UserPresenter)
|
152
|
+
# => true
|
153
|
+
|
154
|
+
presenters.last.kind_of?(UserPresenter)
|
155
|
+
# => true
|
156
|
+
```
|
157
|
+
|
158
|
+
Of course, this works in controllers, too:
|
159
|
+
|
160
|
+
``` ruby
|
161
|
+
class UserController < ApplicationController
|
162
|
+
def index
|
163
|
+
@users = present_many User.all
|
164
|
+
end
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
## Associations
|
169
|
+
|
170
|
+
You can also automatically use presenters for your associations using the
|
171
|
+
`#presents_one` and `#presents_many` macros. Let's say you have the following
|
172
|
+
`Project` model:
|
173
|
+
|
174
|
+
``` ruby
|
175
|
+
class Project
|
176
|
+
has_many :users
|
177
|
+
has_one :owner, class_name: "User"
|
178
|
+
end
|
179
|
+
```
|
180
|
+
|
181
|
+
Oprah lets you easily wrap the associated objects:
|
182
|
+
|
183
|
+
``` ruby
|
184
|
+
class ProjectPresenter < Oprah::Presenter
|
185
|
+
presents_many :users
|
186
|
+
presents_one :owner
|
187
|
+
end
|
188
|
+
```
|
189
|
+
|
190
|
+
Note that you don't need to explicitly state the association class.
|
191
|
+
|
192
|
+
## Composition
|
193
|
+
|
194
|
+
Let's say you extraced some behaviour out of your model into a reusable module (or
|
195
|
+
`ActiveSupport::Concern`). Oprah lets you write a single, separate presenter for
|
196
|
+
this module and automatically chains it to your "main presenter" by walking up the
|
197
|
+
ancestor chain of the given object.
|
198
|
+
|
199
|
+
Let's say we want to mix a shared `Describable` module into our `User` class from
|
200
|
+
above and render the description to HTML:
|
201
|
+
|
202
|
+
|
203
|
+
``` ruby
|
204
|
+
module Describable
|
205
|
+
def description
|
206
|
+
"*AWESOME*"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
class User
|
211
|
+
include Describable
|
212
|
+
end
|
213
|
+
|
214
|
+
class DescribablePresenter < Oprah::Presenter
|
215
|
+
def description
|
216
|
+
Kramdown::Document.new(object.description).to_html
|
217
|
+
end
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
You can now access the methods of both, `UserPresenter` *and*
|
222
|
+
`DescribablePresenter`:
|
223
|
+
|
224
|
+
``` ruby
|
225
|
+
presenter = Oprah.present(User.new)
|
226
|
+
|
227
|
+
presenter.description
|
228
|
+
=> "<p><em>AWESOME</em></p>\n"
|
229
|
+
|
230
|
+
presenter.name
|
231
|
+
# => John Doe
|
232
|
+
```
|
233
|
+
|
234
|
+
### Performance
|
235
|
+
|
236
|
+
Of course, looking up all the presenters would imply a performance issue. But
|
237
|
+
don't worry, Oprah caches all matching presenters for a class (and busts it's
|
238
|
+
cache on code reloads for a smooth development experience).
|
239
|
+
|
240
|
+
### Ordering
|
241
|
+
|
242
|
+
Oprah walks your object's ancestor chain in reverse. For example, you'd be
|
243
|
+
able to access the methods exposed by the `DescribablePresenter` from your
|
244
|
+
`UserPresenter`. You can even use `super`:
|
245
|
+
|
246
|
+
``` ruby
|
247
|
+
class DescribablePresenter < Oprah::Presenter
|
248
|
+
def baz
|
249
|
+
"foo"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
class UserPresenter < Oprah::Presenter
|
254
|
+
def baz
|
255
|
+
super + "bar"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
Oprah.present(User.new).baz
|
260
|
+
# => "foobar"
|
261
|
+
```
|
262
|
+
|
263
|
+
### Choosing presenters
|
264
|
+
|
265
|
+
When presenting an object you can optionally choose which presenter classes
|
266
|
+
to use:
|
267
|
+
|
268
|
+
``` ruby
|
269
|
+
Oprah.present(User.new, only: DescribablePresenter)
|
270
|
+
```
|
271
|
+
|
272
|
+
This parameter takes either a single presenter or an `Array` of presenters.
|
273
|
+
The presenter(s) given need to match the object's class or one of it's
|
274
|
+
ancestors. Non-matching presenters given will be ignored.
|
275
|
+
|
276
|
+
## Testing
|
277
|
+
|
278
|
+
Testing presenters is as simple as testing a regular class. Oprah also
|
279
|
+
provides couple of helpers to make it even easier:
|
280
|
+
|
281
|
+
``` ruby
|
282
|
+
class UserPresenterTest < Minitest::Test
|
283
|
+
include Oprah::TestHelpers
|
284
|
+
|
285
|
+
def setup
|
286
|
+
@presenter = present User.new
|
287
|
+
end
|
288
|
+
|
289
|
+
def test_presented
|
290
|
+
assert_presented @presenter
|
291
|
+
end
|
292
|
+
|
293
|
+
def test_name
|
294
|
+
assert_equal "John Doe", @presenter.name
|
295
|
+
end
|
296
|
+
end
|
297
|
+
```
|
298
|
+
|
299
|
+
## API Documentation
|
300
|
+
|
301
|
+
Comprehensive API Documentation is available at
|
302
|
+
[rubydoc.info](http://www.rubydoc.info/gems/oprah).
|
303
|
+
|
304
|
+
## Contributing
|
305
|
+
|
306
|
+
Please check out our [contributing guidelines](CONTRIBUTING.md).
|
307
|
+
|
308
|
+
## License
|
309
|
+
|
310
|
+
Released under the MIT license. See the LICENSE file for details.
|
311
|
+
|
312
|
+
## Author
|
313
|
+
|
314
|
+
Tobias Svensson, [@endofunky](https://twitter.com/endofunky), [http://github.com/endofunky](http://github.com/endofunky)
|
data/Rakefile
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
module Oprah
|
2
|
+
# Helpers that will be mixed into `ActionController::Base` and
|
3
|
+
# `ActionMailer::Base` by the {Oprah::Railtie}.
|
4
|
+
module ControllerHelpers
|
5
|
+
# A proxy class to delegate method calls to view contexts in presenters
|
6
|
+
# to the most recently created view context by
|
7
|
+
# {ControllerHelpers#view_context}.
|
8
|
+
#
|
9
|
+
# `ViewContextProxy` objects are automatically created in
|
10
|
+
# {ControllerHelpers#present} and {ControllerHelpers#present_many} and
|
11
|
+
# shouldn't have to be created manually.
|
12
|
+
#
|
13
|
+
# @since 0.1.3
|
14
|
+
class ViewContextProxy < ActiveSupport::ProxyObject
|
15
|
+
# @param [ActionController::Base] controller
|
16
|
+
# The controller to delegate to.
|
17
|
+
def initialize(controller)
|
18
|
+
@controller = controller
|
19
|
+
end
|
20
|
+
|
21
|
+
# Delegates all method calls to the `ActionView::Base` returned from
|
22
|
+
# {ControllerHelpers#oprah_view_context}.
|
23
|
+
def method_missing(meth, *args, &block)
|
24
|
+
@controller.oprah_view_context.__send__(meth, *args, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
extend ActiveSupport::Concern
|
29
|
+
|
30
|
+
included do
|
31
|
+
helper_method :present
|
32
|
+
helper_method :present_many
|
33
|
+
end
|
34
|
+
|
35
|
+
# Presents a single object.
|
36
|
+
#
|
37
|
+
# Will pass the view context returned from {#oprah_view_context} to the
|
38
|
+
# presenter by default. This can be overridden.
|
39
|
+
#
|
40
|
+
# @see Presenter.present
|
41
|
+
def present(*args, **kwargs, &block)
|
42
|
+
kwargs = {
|
43
|
+
view_context: oprah_view_context_proxy
|
44
|
+
}.merge(kwargs)
|
45
|
+
|
46
|
+
Presenter.present(*args, **kwargs, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Presents a collection of objects.
|
50
|
+
#
|
51
|
+
# Will pass the view context returned from {#oprah_view_context} to the
|
52
|
+
# presenter by default. This can be overridden.
|
53
|
+
#
|
54
|
+
# @see Presenter.present_many
|
55
|
+
def present_many(*args, **kwargs, &block)
|
56
|
+
kwargs = {
|
57
|
+
view_context: oprah_view_context_proxy
|
58
|
+
}.merge(kwargs)
|
59
|
+
|
60
|
+
Presenter.present_many(*args, **kwargs, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
# The view context automatically passed to objects presented from this
|
64
|
+
# controller.
|
65
|
+
#
|
66
|
+
# You can override this method pass a custom view context to all
|
67
|
+
# presented objects from the controller scope.
|
68
|
+
#
|
69
|
+
# @see #oprah_view_context=
|
70
|
+
# @return [ActionView::Base]
|
71
|
+
def oprah_view_context
|
72
|
+
@oprah_view_context || view_context
|
73
|
+
end
|
74
|
+
|
75
|
+
# Assigns the view context returned from {#oprah_view_context}.
|
76
|
+
#
|
77
|
+
# You can override this method pass a custom view context to all
|
78
|
+
# presented objects from the controller scope.
|
79
|
+
#
|
80
|
+
# @since 0.1.3
|
81
|
+
# @see #oprah_view_context
|
82
|
+
# @param [ActionView::Base] view_context The view context to assign
|
83
|
+
# @return [ActionView::Base]
|
84
|
+
def oprah_view_context=(view_context)
|
85
|
+
@oprah_view_context = view_context
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns an instance of a view class and sets the current view context
|
89
|
+
# returned by {#oprah_view_context}.
|
90
|
+
#
|
91
|
+
# If you override this method in your controller ensure you keep Oprah's
|
92
|
+
# view context updated using {#oprah_view_context=}.
|
93
|
+
#
|
94
|
+
# @since 0.1.3
|
95
|
+
# @see http://api.rubyonrails.org/classes/ActionView/Rendering.html#method-i-view_context
|
96
|
+
# Rails API Documentation
|
97
|
+
# @return [ActionView::Base]
|
98
|
+
def view_context
|
99
|
+
self.oprah_view_context = super
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
# @since 0.1.3
|
105
|
+
def oprah_view_context_proxy
|
106
|
+
@oprah_view_context_proxy ||= ViewContextProxy.new(self)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|