presenter-rails 0.1.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/MIT-LICENSE +20 -0
- data/README.md +166 -0
- data/Rakefile +23 -0
- data/lib/generators/presenter/USAGE +8 -0
- data/lib/generators/presenter/install/USAGE +9 -0
- data/lib/generators/presenter/install/install_generator.rb +12 -0
- data/lib/generators/presenter/install/templates/application_presenter.template +13 -0
- data/lib/generators/presenter/presenter_generator.rb +11 -0
- data/lib/generators/presenter/templates/model_presenter.template +12 -0
- data/lib/presenter.rb +5 -0
- data/lib/presenter/base.rb +25 -0
- data/lib/presenter/controller.rb +3 -0
- data/lib/presenter/helper.rb +12 -0
- data/lib/presenter/naming.rb +17 -0
- data/lib/presenter/version.rb +3 -0
- data/lib/tasks/presenter/rails_tasks.rake +4 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5ef5a2774a142651a244f17d207b850cf66d330b
|
4
|
+
data.tar.gz: b5c11f5d72a1f2a6845724ed1d6dbf9b1dea1b08
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 11bf5be25532c008fe7affe61c637ce32a3a24ef5c41149bcc8880e8833d44d96a7cf6ebfd0e6fe7147e87689ea54845d7e38a75f25ff010055dc66090b4d37a
|
7
|
+
data.tar.gz: 1586385a58f932d1adf22d1d97fcc8d18e5ab949d225b193bd2923bd525ee5d09525dd51b3004be2f6a7e2c364e686e9a2b1ca7e20f7202d5ab4cda6a5c9711c
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 Sam Sargent
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
# presenter-rails
|
2
|
+
|
3
|
+
Presenter is an easy way of implementing the presenter design pattern in Rails.
|
4
|
+
|
5
|
+
With a naming convention based approach, easily define presenter classes to clean up
|
6
|
+
your models and views, handling method delegation based on instance variable & file naming.
|
7
|
+
|
8
|
+
This should hopefully mean you can just use presenter objects in place of model objects
|
9
|
+
throughout your app without effecting any behaviour - as you can still call your custom model
|
10
|
+
methods and active record methods on the presenter objects.
|
11
|
+
|
12
|
+
This ultimately means all methods that belong to the model stay on the model itself
|
13
|
+
and seperated from any methods which don't handle data.
|
14
|
+
|
15
|
+
All presenter classes inherit from ApplicationPresenter generated from the install to keep the same
|
16
|
+
convention you see throughout the rest of your Rails app.
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
Add this line to your application's Gemfile and bundle:
|
20
|
+
```ruby
|
21
|
+
gem 'presenter-rails'
|
22
|
+
```
|
23
|
+
```bash
|
24
|
+
$ bundle
|
25
|
+
```
|
26
|
+
Run the install generator
|
27
|
+
```bash
|
28
|
+
$ rails g presenter:install
|
29
|
+
```
|
30
|
+
Add this line to the top of your application.rb
|
31
|
+
```ruby
|
32
|
+
# config/application.rb
|
33
|
+
require 'presenter'
|
34
|
+
```
|
35
|
+
Followed by this line inside the Application class
|
36
|
+
```ruby
|
37
|
+
# config/application.rb
|
38
|
+
module YourAppName
|
39
|
+
class Application < Rails::Application
|
40
|
+
config.autoload_paths << Rails.root.join('app/presenters')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Usage
|
46
|
+
|
47
|
+
These instructions will use a 'User' model for example purposes. Just switch out User for your own model names
|
48
|
+
|
49
|
+
After you run the install generator, run
|
50
|
+
```bash
|
51
|
+
$ rails g presenter User
|
52
|
+
```
|
53
|
+
|
54
|
+
to create a presenter file for one of your models. This will inherit from ApplicationPresenter, example shown below:
|
55
|
+
```ruby
|
56
|
+
# app/presenters/user_presenter.rb
|
57
|
+
class UserPresenter < ApplicationPresenter
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
Note: This automatically inherits a dynamic initialize method which sets an instance variable. You also inherit a helper method dynamically named after the model too.
|
62
|
+
So you DO NOT have to define this yourself:
|
63
|
+
```ruby
|
64
|
+
def initialize(user)
|
65
|
+
@user = user
|
66
|
+
end
|
67
|
+
|
68
|
+
def user # Make sure you use the helper methods in your presenters in place of the instance variable.
|
69
|
+
@user
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
This also comes with with some error handling and some other code. So don't worry about this.
|
74
|
+
I'm showing it just so you know what to expect if you try overwrite initialize or the helper without super. If you wish to extend it
|
75
|
+
then remember to super or you will overwrite the default behaviour.
|
76
|
+
|
77
|
+
If you do wish to extend the initialize method / change the instance variable name, call super first. Next, define an instance variable and assign it to the model object using the helper method (named after the model name).
|
78
|
+
```ruby
|
79
|
+
def initialize(user)
|
80
|
+
super
|
81
|
+
# assigning your variable to the user method gives it access to the inherited code.
|
82
|
+
@another_variable_name = self.user
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
This means you can define methods in your presenter using the instance variable named after your model.
|
87
|
+
Let's imagine our User model has a first_name and last_name field and we want to define #name. All we would have to do is:
|
88
|
+
```ruby
|
89
|
+
class UserPresenter < ApplicationPresenter
|
90
|
+
def name
|
91
|
+
"#{user.first_name} #{user.last_name}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
now you can initialize a presenter. There are 2 methods for this, either directly initialize the object as usual with:
|
97
|
+
```ruby
|
98
|
+
@user = UserPresenter.new(user)
|
99
|
+
```
|
100
|
+
or use our built in helper to accomplish the same thing:
|
101
|
+
```ruby
|
102
|
+
@user = present(user)
|
103
|
+
```
|
104
|
+
(More on this below)
|
105
|
+
|
106
|
+
Example provided shows how it would be used in a controller:
|
107
|
+
```ruby
|
108
|
+
class UsersController < ApplicationController
|
109
|
+
def show
|
110
|
+
user = User.find(params[:id]) # get an instance of user
|
111
|
+
@user = present(user)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
Now the user instance variable has access to all methods belonging to it's presenter and the model being passed in.
|
117
|
+
This allows access to
|
118
|
+
```ruby
|
119
|
+
@user.name
|
120
|
+
# which returns first name and last name like 'Sam Sargent'
|
121
|
+
# or even call the normal model methods
|
122
|
+
@user.first_name
|
123
|
+
# which would delegate the method back to the user model being passed into the present helper
|
124
|
+
# returning something like 'Sam'
|
125
|
+
# Note: This works with all ActiveRecord methods too, just as if it's an object of the ActiveRecord class User
|
126
|
+
# allowing access to even @user.update(first_name: 'Finn') on the presenter object
|
127
|
+
```
|
128
|
+
|
129
|
+
## Helper methods
|
130
|
+
|
131
|
+
### #present
|
132
|
+
|
133
|
+
#present is a method accessible in controllers and views for initializing new presenter objects
|
134
|
+
```ruby
|
135
|
+
user = User.first
|
136
|
+
@user = present(user) # returns a presenter object for that model, replacing need to initialize with #new
|
137
|
+
|
138
|
+
# instead of
|
139
|
+
user = User.first
|
140
|
+
@user = UserPresenter.new(user)
|
141
|
+
|
142
|
+
# alternatively, pass in a collection to return an array of presenter objects
|
143
|
+
users = User.all # an active record relation
|
144
|
+
@users = present(users)
|
145
|
+
users = User.all.to_a # an array
|
146
|
+
@users = present(users)
|
147
|
+
```
|
148
|
+
|
149
|
+
### #instance getter
|
150
|
+
|
151
|
+
For each presenter you create, a helper method is defined to get the model object being passed in. This replaces the need to throw around
|
152
|
+
the instance variable. It's also faster as it allows the method delegation to not have to parse naming and fetch instance variables every time the inherited #method_missing is called.
|
153
|
+
|
154
|
+
shown using a User model as example
|
155
|
+
```ruby
|
156
|
+
# app/presenters/user_presenter.rb
|
157
|
+
class UserPresenter < ApplicationPresenter
|
158
|
+
# this has the method #user defined automatically to access the user object being passed in to the presenter
|
159
|
+
def name
|
160
|
+
"#{user.first_name} {user.last_name}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
## License
|
166
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Presenter'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
23
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Presenter
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
class_option :doc, type: :boolean, default: true, desc: 'Include commented documentation'
|
6
|
+
|
7
|
+
def generate_application_presenter
|
8
|
+
template 'application_presenter.template', 'app/presenters/application_presenter.rb'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class ApplicationPresenter < Presenter::Base
|
2
|
+
<%- if options.doc? -%>
|
3
|
+
# You'll notice Presenter::Base, this handles delegation of methods based on naming conventions.
|
4
|
+
# Along with defining the #initialize method & the model helper method for all presenters.
|
5
|
+
|
6
|
+
# Use rails g presenter ModelName to create a presenter file for a model.
|
7
|
+
|
8
|
+
# All presenter classes inherit from this ApplicationPresenter and so define
|
9
|
+
# methods here which you want all your presenters to inherit (just as you usually would).
|
10
|
+
|
11
|
+
# For more, check the docs at: https://www.github.com/samsarge/presenter-rails
|
12
|
+
<%- end -%>
|
13
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Presenter
|
2
|
+
class PresenterGenerator < Rails::Generators::Base
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
class_option :doc, type: :boolean, default: true, desc: 'Include commented documentation'
|
5
|
+
argument :model, type: :string
|
6
|
+
|
7
|
+
def generate_model_presenter
|
8
|
+
template 'model_presenter.template', "app/presenters/#{model.singularize.underscore}_presenter.rb"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class <%= "#{model.singularize.camelcase}Presenter" %> < ApplicationPresenter
|
2
|
+
<%- if options.doc? -%>
|
3
|
+
# Don't worry about the initialize method, it's already handled for you.
|
4
|
+
|
5
|
+
# You can now pass in an instance of <%= model.singularize.camelcase %> when you initialize this presenter
|
6
|
+
# and access it with the helper method
|
7
|
+
# #<%= model.singularize.underscore %>
|
8
|
+
# instead of an instance variable when writing your methods
|
9
|
+
|
10
|
+
# Write methods for this presenter in here using the helper method
|
11
|
+
<%- end -%>
|
12
|
+
end
|
data/lib/presenter.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Presenter
|
2
|
+
class Base
|
3
|
+
include Presenter::Naming
|
4
|
+
|
5
|
+
def initialize(model)
|
6
|
+
@model = model
|
7
|
+
generate_model_instance_getter
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
def generate_model_instance_getter
|
12
|
+
define_singleton_method model_object_name_from_presenter(@model) do
|
13
|
+
@model
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(method, *args, &block)
|
18
|
+
@model.send(method, *args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to_missing?(method, include_all = false)
|
22
|
+
@model.respond_to?(method, include_all)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Presenter
|
2
|
+
module Helper
|
3
|
+
include Presenter::Naming
|
4
|
+
def present(object_or_collection)
|
5
|
+
if object_or_collection.respond_to?(:map) # If it is a collection
|
6
|
+
object_or_collection.map { |object| presenter_from_model_object(object).new(object) }
|
7
|
+
else # If it is a single object
|
8
|
+
presenter_from_model_object(object_or_collection).new(object_or_collection)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This module is for naming related methods
|
2
|
+
module Presenter
|
3
|
+
module Naming
|
4
|
+
def model_object_name_from_presenter(model)
|
5
|
+
model.class.to_s.underscore.sub('_presenter', '')
|
6
|
+
end
|
7
|
+
|
8
|
+
def presenter_from_model_object(model)
|
9
|
+
presenter_name(model).constantize
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def presenter_name(model)
|
14
|
+
"#{model.class.to_s}Presenter"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: presenter-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sam Sargent
|
8
|
+
- Finn Francis
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2017-07-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 5.0.2
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 5.0.2
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: sqlite3
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec-rails
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
description: Keep code neat and abstract view & presenter logic. Adding a simple separation
|
57
|
+
of concerns when creating your models with an easy API.
|
58
|
+
email:
|
59
|
+
- samsarge@hotmail.co.uk
|
60
|
+
- finnfrancis123@gmail.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- MIT-LICENSE
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- lib/generators/presenter/USAGE
|
69
|
+
- lib/generators/presenter/install/USAGE
|
70
|
+
- lib/generators/presenter/install/install_generator.rb
|
71
|
+
- lib/generators/presenter/install/templates/application_presenter.template
|
72
|
+
- lib/generators/presenter/presenter_generator.rb
|
73
|
+
- lib/generators/presenter/templates/model_presenter.template
|
74
|
+
- lib/presenter.rb
|
75
|
+
- lib/presenter/base.rb
|
76
|
+
- lib/presenter/controller.rb
|
77
|
+
- lib/presenter/helper.rb
|
78
|
+
- lib/presenter/naming.rb
|
79
|
+
- lib/presenter/version.rb
|
80
|
+
- lib/tasks/presenter/rails_tasks.rake
|
81
|
+
homepage: https://github.com/samsarge/presenter-rails
|
82
|
+
licenses:
|
83
|
+
- MIT
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.4.5.1
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: Easily implement the presenter design pattern in rails projects.
|
105
|
+
test_files: []
|