pres 0.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 +7 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +230 -0
- data/Rakefile +10 -0
- data/lib/pres/presenter.rb +14 -0
- data/lib/pres/presents.rb +31 -0
- data/lib/pres/version.rb +3 -0
- data/lib/pres.rb +4 -0
- data/test/presenter_test.rb +22 -0
- data/test/presents_test.rb +54 -0
- data/test/test_helper.rb +23 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 679fb7c90be5b08c135e46d8da2e64f94c3be04d
|
4
|
+
data.tar.gz: 005d0c7bd07a446107f2dd09c235f05eb6d3aa56
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2bd353785c1572705fcd30ab41c6a240b80549de720e3a2d6444a9ef4f19fda8714d0d3b5180fce3318f55e30be09d7a68e9e71c395645199a5b84f71871d203
|
7
|
+
data.tar.gz: 41634e73d39c0836589804163e0e19c1eedaf869931c19dcdcfdfdd9aeca70737d98c770a6634b8f3ddc8752cb325d2720442a543bf068a50ae71cce34125cce
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Neighborland, Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
# Pres: A Simple Rails Presenter
|
2
|
+
|
3
|
+
## What?
|
4
|
+
|
5
|
+
A Presenter is a rendering class that wraps a model. Presenters are an
|
6
|
+
alternative to an unorganized mass of helper methods in your Rails application.
|
7
|
+
|
8
|
+
The `pres` gem is a lightweight presenter solution.
|
9
|
+
|
10
|
+
## How and Why?
|
11
|
+
|
12
|
+
Decorators add methods to a model. `pres` does not do that. `pres` encourages you
|
13
|
+
to whitelist model methods (via delegation).
|
14
|
+
|
15
|
+
Other presenter libraries mix in all the methods from the Rails ViewContext to
|
16
|
+
make it easy to call those methods in the Presenter class. This causes method
|
17
|
+
bloat. `pres` instead injects the ViewContext as a dependency into the
|
18
|
+
Presenter class, and uses `method_missing` to delegate to those methods.
|
19
|
+
|
20
|
+
## Install
|
21
|
+
|
22
|
+
Add it to your Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem "pres"
|
26
|
+
```
|
27
|
+
|
28
|
+
Include the `Presents` module:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
class ApplicationController
|
32
|
+
include Presents
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Add `app/presenters` to your application's autoload paths in `application.rb`:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
config.autoload_paths += %W( #{ config.root }/app/presenters )
|
40
|
+
```
|
41
|
+
|
42
|
+
#### Example Usage
|
43
|
+
|
44
|
+
Create a presenter class in `app/presenters`:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
class DogePresenter < Presenter
|
48
|
+
# explicitly delegate methods to the model
|
49
|
+
delegate :name, to: :object
|
50
|
+
|
51
|
+
def know_your_meme_link
|
52
|
+
# Rails helpers are available via the view context
|
53
|
+
link_to "Know your meme", "http://knowyourmeme.com/memes/doge"
|
54
|
+
end
|
55
|
+
|
56
|
+
def name_header
|
57
|
+
# object is the Doge
|
58
|
+
content_tag(:h1, objec†.name)
|
59
|
+
end
|
60
|
+
|
61
|
+
def signed_in_status
|
62
|
+
# controller methods are accessible via the view context
|
63
|
+
if signed_in?
|
64
|
+
"Signed in"
|
65
|
+
else
|
66
|
+
"Signed out"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
Wrap your model object in your controller with `present`:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
class DogesController
|
76
|
+
def show
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def doge
|
82
|
+
@doge ||= present(Doge.find(params[:id]))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
Use the presenter object in `doges/show.haml.html`
|
88
|
+
|
89
|
+
```haml
|
90
|
+
= doge.name_header
|
91
|
+
.status
|
92
|
+
You are #{ doge.signed_in_status }
|
93
|
+
.links
|
94
|
+
.meme-link= doge.know_your_meme_link
|
95
|
+
```
|
96
|
+
|
97
|
+
#### Collection Example
|
98
|
+
|
99
|
+
Create a presenter class in `app/presenters`:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
class DogePresenter < Presenter
|
103
|
+
# same as above
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
Wrap your model object in your controller with `present`:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
class DogesController
|
111
|
+
def index
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def doges
|
117
|
+
@doges ||= present(Doge.all)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
Use the presenter objects in `doges/index.haml.html`
|
123
|
+
|
124
|
+
```haml
|
125
|
+
This renders "doges/_doge.html.haml" for each item, as usual:
|
126
|
+
= render @doges
|
127
|
+
|
128
|
+
Or use each:
|
129
|
+
- doges.each do |doge|
|
130
|
+
= doge.name_header
|
131
|
+
```
|
132
|
+
|
133
|
+
#### Present with options
|
134
|
+
|
135
|
+
Use keyword arguements (or an options hash) to pass additional options to a
|
136
|
+
Presenter:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
class UserPresenter
|
140
|
+
def initialize(object, view_context, cool: false)
|
141
|
+
super
|
142
|
+
@cool = cool
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
user = User.new
|
147
|
+
present(user, cool: true)
|
148
|
+
=> #<UserPresenter object: #<User> ...>
|
149
|
+
```
|
150
|
+
|
151
|
+
#### Render a custom Presenter
|
152
|
+
|
153
|
+
By default, a presenter class corresponding to the model class name is
|
154
|
+
constructed. To specify a different class, pass the `presenter:` key, followed
|
155
|
+
by any additional arguments:
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
user = User.new
|
159
|
+
present(user, presenter: NiceUserPresenter, cool: true)
|
160
|
+
=> #<NiceUserPresenter object: #<User> ...>
|
161
|
+
```
|
162
|
+
|
163
|
+
#### Render a collection
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
present(User.first(5))
|
167
|
+
=> [#<UserPresenter object: #<User> ...>]
|
168
|
+
```
|
169
|
+
|
170
|
+
#### Creating presenters in views
|
171
|
+
|
172
|
+
You should create presenters in your controllers. If you would like to create
|
173
|
+
a presenter in your view code, make the `presents` method visible to your views:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
class ApplicationController
|
177
|
+
include Presents
|
178
|
+
helper_method :present
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
## More Goodness
|
183
|
+
|
184
|
+
#### Presenters are objects
|
185
|
+
|
186
|
+
You can mix in common methods. Move everything in `application_helper.rb` to
|
187
|
+
`app/presenters/shared`:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
module Shared
|
191
|
+
def logout_link
|
192
|
+
# whatever
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
class DogePresenter < Presenter
|
197
|
+
include Shared
|
198
|
+
end
|
199
|
+
```
|
200
|
+
|
201
|
+
You can override methods without resorting to convoluted method names:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
class DogePresenter < Presenter
|
205
|
+
include Shared
|
206
|
+
|
207
|
+
def logout_link
|
208
|
+
# whoa this one is different!
|
209
|
+
end
|
210
|
+
end
|
211
|
+
```
|
212
|
+
|
213
|
+
#### Presenters can create other presenters
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
class DogePresenter < Presenter
|
217
|
+
def cats
|
218
|
+
present(object.cats)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
```
|
222
|
+
|
223
|
+
```haml
|
224
|
+
= render doge.cats
|
225
|
+
```
|
226
|
+
|
227
|
+
## References
|
228
|
+
|
229
|
+
* http://nithinbekal.com/posts/rails-presenters/
|
230
|
+
* https://github.com/drapergem/draper
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Base Presenter class
|
2
|
+
# Construct with object, view_context, and optional options
|
3
|
+
class Presenter < Struct.new(:object, :view_context, :options)
|
4
|
+
delegate :id, :to_partial_path, to: :object
|
5
|
+
|
6
|
+
# Send missing symbols to view_context
|
7
|
+
def method_missing(symbol, *args, &block)
|
8
|
+
view_context.send(symbol, *args, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def respond_to?(symbol, _ = false)
|
12
|
+
super || view_context.respond_to?(symbol, true)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Presents
|
2
|
+
private
|
3
|
+
|
4
|
+
# Wrap an object or collection of objects with a presenter class.
|
5
|
+
#
|
6
|
+
# object - a ruby class
|
7
|
+
# presenter - a Presenter class (optional)
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# user = User.new
|
12
|
+
# present(user, cool: true)
|
13
|
+
# => #<UserPresenter object: #<User> ...>
|
14
|
+
#
|
15
|
+
# user = User.new
|
16
|
+
# present(user, presenter: NiceUserPresenter, cool: true)
|
17
|
+
# => #<NiceUserPresenter object: #<User> ...>
|
18
|
+
#
|
19
|
+
# present([user])
|
20
|
+
# => [#<UserPresenter object: #<User> ...>]
|
21
|
+
#
|
22
|
+
# Returns a new Presenter object or array of new Presenter objects
|
23
|
+
def present(object, presenter: nil, **args)
|
24
|
+
if object.respond_to?(:to_ary)
|
25
|
+
object.map { |item| present(item, presenter: presenter, **args) }
|
26
|
+
else
|
27
|
+
presenter ||= Object.const_get("#{ object.class.name }Presenter")
|
28
|
+
presenter.new(object, view_context, **args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/pres/version.rb
ADDED
data/lib/pres.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe Presenter do
|
4
|
+
it "delegates to view_context" do
|
5
|
+
view_context = FakeViewContext.new
|
6
|
+
presenter = Presenter.new(nil, view_context)
|
7
|
+
assert presenter.respond_to?(:current_user)
|
8
|
+
assert presenter.respond_to?(:link_to)
|
9
|
+
view_context.expects(:link_to)
|
10
|
+
presenter.link_to "something"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "is constructed without options" do
|
14
|
+
assert Presenter.new(nil, nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "is constructed with options" do
|
18
|
+
presenter = Presenter.new(nil, nil, something: 42, secrets: "none")
|
19
|
+
assert_equal 42, presenter.options[:something]
|
20
|
+
assert_equal "none", presenter.options[:secrets]
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe Presents do
|
4
|
+
class Doge
|
5
|
+
end
|
6
|
+
|
7
|
+
class DogePresenter < Presenter
|
8
|
+
end
|
9
|
+
|
10
|
+
class VeryDogePresenter < Presenter
|
11
|
+
end
|
12
|
+
|
13
|
+
class FakeController
|
14
|
+
include Presents
|
15
|
+
|
16
|
+
def wrap(object)
|
17
|
+
present(object)
|
18
|
+
end
|
19
|
+
|
20
|
+
def very_wrap(object)
|
21
|
+
present(object, presenter: VeryDogePresenter)
|
22
|
+
end
|
23
|
+
|
24
|
+
def view_context
|
25
|
+
FakeViewContext.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:controller) { FakeController.new }
|
30
|
+
|
31
|
+
it "creates the default presenter" do
|
32
|
+
presenter = controller.wrap(Doge.new)
|
33
|
+
assert presenter.is_a?(DogePresenter)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "creates the specified presenter" do
|
37
|
+
presenter = controller.very_wrap(Doge.new)
|
38
|
+
assert presenter.is_a?(VeryDogePresenter)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "creates an array of default presenters" do
|
42
|
+
presenters = controller.wrap([Doge.new, Doge.new])
|
43
|
+
assert presenters.is_a?(Array)
|
44
|
+
assert_equal 2, presenters.size
|
45
|
+
assert presenters[0].is_a?(DogePresenter)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "creates an array of specified presenters" do
|
49
|
+
presenters = controller.very_wrap([Doge.new, Doge.new])
|
50
|
+
assert presenters.is_a?(Array)
|
51
|
+
assert_equal 2, presenters.size
|
52
|
+
assert presenters[0].is_a?(VeryDogePresenter)
|
53
|
+
end
|
54
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
if ENV["TRAVIS"]
|
2
|
+
require "coveralls"
|
3
|
+
Coveralls.wear!
|
4
|
+
end
|
5
|
+
|
6
|
+
require "minitest/autorun"
|
7
|
+
require "mocha/mini_test"
|
8
|
+
require "byebug" if ENV["BYEBUG"]
|
9
|
+
require "pres"
|
10
|
+
|
11
|
+
class FakeViewContext
|
12
|
+
# An example of a method mixed into the view_context
|
13
|
+
def current_user
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# An example of a private method provided by the view_context
|
20
|
+
def link_to(*_)
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pres
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tee Parham
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mocha
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.4'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.4'
|
83
|
+
description: A Simple Rails Presenter base class and controller helper
|
84
|
+
email:
|
85
|
+
- tee@neighborland.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- Gemfile
|
91
|
+
- LICENSE.txt
|
92
|
+
- README.md
|
93
|
+
- Rakefile
|
94
|
+
- lib/pres.rb
|
95
|
+
- lib/pres/presenter.rb
|
96
|
+
- lib/pres/presents.rb
|
97
|
+
- lib/pres/version.rb
|
98
|
+
- test/presenter_test.rb
|
99
|
+
- test/presents_test.rb
|
100
|
+
- test/test_helper.rb
|
101
|
+
homepage: https://github.com/neighborland/pres
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
metadata: {}
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 2.0.0
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 2.4.5
|
122
|
+
signing_key:
|
123
|
+
specification_version: 4
|
124
|
+
summary: A Simple Rails Presenter
|
125
|
+
test_files:
|
126
|
+
- Gemfile
|
127
|
+
- Rakefile
|
128
|
+
- test/presenter_test.rb
|
129
|
+
- test/presents_test.rb
|
130
|
+
- test/test_helper.rb
|
131
|
+
has_rdoc:
|