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 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
@@ -0,0 +1,11 @@
1
+ source "https://rubygems.org"
2
+
3
+ if ENV["TRAVIS"]
4
+ gem "coveralls", require: false
5
+ end
6
+
7
+ if ENV["BYEBUG"]
8
+ gem "byebug"
9
+ end
10
+
11
+ gemspec
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,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ task default: [:test]
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.test_files = %w(test/**/*.rb)
9
+ t.verbose = false
10
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module Pres
2
+ VERSION = "0.0.1"
3
+ end
data/lib/pres.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "active_support/core_ext/module/delegation"
2
+ require "pres/version"
3
+ require "pres/presenter.rb"
4
+ require "pres/presents.rb"
@@ -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
@@ -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: