tuxedo_decorate 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.travis.yml +12 -0
- data/Appraisals +9 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +226 -0
- data/Rakefile +9 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/gemfiles/rails_4.2.gemfile +8 -0
- data/gemfiles/rails_stable.gemfile +8 -0
- data/lib/tuxedo/action_view/helpers.rb +48 -0
- data/lib/tuxedo/config.rb +31 -0
- data/lib/tuxedo/railtie.rb +11 -0
- data/lib/tuxedo/version.rb +3 -0
- data/lib/tuxedo.rb +91 -0
- data/spec/config_spec.rb +17 -0
- data/spec/helpers/helpers_spec.rb +74 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/dummy_classes.rb +26 -0
- data/spec/tuxedo_spec.rb +46 -0
- data/tuxedo_decorate.gemspec +37 -0
- metadata +182 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b2be8003b952d96220499facd10d37c7de8acf51
|
4
|
+
data.tar.gz: 22b2839a94e764104c725a961b43d2f48a5ee7e3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f4aa5d568b6f6258fdbbdf8d36b8a0519ee627bc83b0baf161b810cecba34fa97273afd746cb3c052dbb79e989358866ae424c66208f0a581823f83cb294193
|
7
|
+
data.tar.gz: 7aed0a729b639a67d7eb2b672f7bfb1bd1d36ed75dd33c4c10ff04994f2cc9cb4525429a22c3b3d49efba3297225a3359b4cb5530d21cf0e680b057c954f6814
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
language: ruby
|
2
|
+
sudo: false
|
3
|
+
rvm:
|
4
|
+
- 2.2.0
|
5
|
+
- 2.2.4
|
6
|
+
gemfile:
|
7
|
+
- gemfiles/rails_4.2.gemfile
|
8
|
+
- gemfiles/rails_stable.gemfile
|
9
|
+
script: "bundle exec rake spec"
|
10
|
+
addons:
|
11
|
+
code_climate:
|
12
|
+
repo_token: 344f2a60a2920e96f71877b87829836b01a44e1e94463cde54e2c54e8f389f79
|
data/Appraisals
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Jan Stevens
|
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,226 @@
|
|
1
|
+
# Tuxedo Decorate
|
2
|
+
[![Build Status](https://travis-ci.org/playpasshq/tuxedo.svg)](https://travis-ci.org/playpasshq/tuxedo)
|
3
|
+
[![Code Climate](https://codeclimate.com/github/playpasshq/tuxedo/badges/gpa.svg)](https://codeclimate.com/github/playpasshq/tuxedo)
|
4
|
+
[![Inline docs](http://inch-ci.org/github/playpasshq/tuxedo.png)](http://inch-ci.org/github/playpasshq/tuxedo)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/tuxedo-decorate.svg)](https://badge.fury.io/rb/tuxedo-decorate)
|
6
|
+
|
7
|
+
Tuxedo Decorate provides an easy to use `Presenter` layer on top of Rails views.
|
8
|
+
It does not make any assumptions about your underline object or uses black
|
9
|
+
magic voodoo code to determine your ActiveRecord Relations.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Currently only rails 4.2 and up is supported and a ruby version of 2.2.0 or higher.
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'tuxedo_decorate', require: 'tuxedo'
|
18
|
+
```
|
19
|
+
|
20
|
+
**Notice the require statement!**
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
$ gem install tuxedo_decorate
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
To use Tuxedo simply include it in your presenter class. For example
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
class BananaPresenter
|
36
|
+
include Tuxedo
|
37
|
+
|
38
|
+
def name
|
39
|
+
'hello'
|
40
|
+
end
|
41
|
+
|
42
|
+
def name_with_args(name, surname: '')
|
43
|
+
"hello #{name}, #{surname}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
In your views you can use the `presenter_for` helper to use the presenter.
|
49
|
+
By default Tuxedo looks for a class with the same name but ending in `Presenter`.
|
50
|
+
For example, we now use `BananaPresenter`.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
<% presenter_for(Banana.new) do |present| %>
|
54
|
+
<span><%= present.name %></span>
|
55
|
+
<div><%= present.name_with_args('Jan', surname: 'Stevens') %></div>
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
### Using the Present-and-Call [PRAC]
|
60
|
+
A shorthand is also included that allows to easily call a presenter method
|
61
|
+
for to present object. For example
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
<%= prac(Banana.new, :name) %>
|
65
|
+
```
|
66
|
+
|
67
|
+
This basically translates to the following:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
<%= presenter_for(Banana.new).name %>
|
71
|
+
```
|
72
|
+
|
73
|
+
Extra arguments are passed along to the presenter method, so the following
|
74
|
+
also workes
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
<%= prac(Banana.new, :name_with_args, 'Jan', surname: 'Stevens') %>
|
78
|
+
```
|
79
|
+
|
80
|
+
### Example Setup
|
81
|
+
We have a `presenters` folder in our app folder. In their we have an `ApplicationPresenter`
|
82
|
+
that defines reusable methods. Every presenter inherits from `ApplicationPresenter`.
|
83
|
+
For example
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
class ApplicationPresenter
|
87
|
+
include Tuxedo
|
88
|
+
|
89
|
+
# Here we setup our typical delegation methods
|
90
|
+
delegate(:current_user,
|
91
|
+
:link_to,
|
92
|
+
:content_tag,
|
93
|
+
to: :_h)
|
94
|
+
|
95
|
+
# Bunch of shared methods
|
96
|
+
def html_id
|
97
|
+
# ...
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class BananaPresenter < ApplicationPresenter
|
102
|
+
def name
|
103
|
+
'hello'
|
104
|
+
end
|
105
|
+
|
106
|
+
def name_with_args(name, surname: '')
|
107
|
+
"hello #{name}, #{surname}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
## FAQ
|
113
|
+
|
114
|
+
### No blocks in the views because [reasons]!
|
115
|
+
Sure got you covered
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
<% present = presenter_for(Banana.new) %>
|
119
|
+
<span><%= present.name %></span>
|
120
|
+
<div><%= present.name_with_args('Jan', surname: 'Stevens') %></div>
|
121
|
+
```
|
122
|
+
|
123
|
+
### But I rather have Presenters that are Decorater classes and are named [obscure name]
|
124
|
+
Allright you can configure the suffix to be used by using a config block and placing it
|
125
|
+
somewhere in the Rails initialization chain
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
Tuxedo.configure do |config|
|
129
|
+
config.suffix = 'ObscureName'
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
### How can I access the original decorated object?
|
134
|
+
Easily, you can use `object` but thats quite obscure so by default Tuxedo "guesses" (`demodulize` + `gsub` + `underscore`)
|
135
|
+
the name of your object. For example if my Presenter class is name `BananaPresenter` then
|
136
|
+
I can access the original object by using `banana`
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
class BananaPresenter
|
140
|
+
include Tuxedo
|
141
|
+
|
142
|
+
def greetings
|
143
|
+
"hello #{banana.name}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
```
|
147
|
+
|
148
|
+
If thats not good enough you can overwrite the `object_alias` used. This allows for
|
149
|
+
using `monkey` instead of `banana`.
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
class BananaPresenter
|
153
|
+
include Tuxedo
|
154
|
+
object_alias :monkey
|
155
|
+
|
156
|
+
def greetings
|
157
|
+
"hello #{monkey.name}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
```
|
161
|
+
|
162
|
+
### Can I use `prac` inside my Presenters?
|
163
|
+
Sure you can, for your convenience `prac`` is made available. This allows you to reuse
|
164
|
+
presenter methods.
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
class BananaPresenter
|
168
|
+
def name
|
169
|
+
"BANANA BANANA BANANA"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class MonkeyPresenter
|
174
|
+
def eat
|
175
|
+
prac monkey.banana, :name
|
176
|
+
end
|
177
|
+
end
|
178
|
+
```
|
179
|
+
|
180
|
+
### How can I access my view helpers / url helpers / rails helpers
|
181
|
+
We expose a method `_h` that delegates to the view context. So you have to prefix
|
182
|
+
all your url helpers with `_h`, for example:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
class BananaPresenter
|
186
|
+
include Tuxedo
|
187
|
+
|
188
|
+
def edit_link
|
189
|
+
_h.edit_banana_path(banana)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
### But I don't want to prefix everything with _h
|
195
|
+
I'ts ruby just use `delegate`, for example in our application we have to following setup
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
class BananaPresenter
|
199
|
+
include Tuxedo
|
200
|
+
delegate(:current_user,
|
201
|
+
:link_to,
|
202
|
+
:auth_link_to,
|
203
|
+
:auth_service,
|
204
|
+
to: :_h)
|
205
|
+
|
206
|
+
def edit_link
|
207
|
+
_h.edit_banana_path(banana)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
## Development
|
213
|
+
|
214
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
215
|
+
|
216
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
217
|
+
|
218
|
+
## Contributing
|
219
|
+
|
220
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/playpasshq/tuxedo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
221
|
+
|
222
|
+
|
223
|
+
## License
|
224
|
+
|
225
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
226
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "tuxedo"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Tuxedo
|
2
|
+
module ActionView
|
3
|
+
# Main module for the ActionView helpers
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
#
|
7
|
+
# presenter_for(instance)
|
8
|
+
#
|
9
|
+
# prac(instance, method, *args)
|
10
|
+
#
|
11
|
+
module Helpers
|
12
|
+
|
13
|
+
# We can use this to give a block and wrap all the presenter methods in the block
|
14
|
+
# This shows clearly that we are using a presenter without the explicit assign statement
|
15
|
+
# Some magic happens to initiate a new presenter with the model and the view context
|
16
|
+
#
|
17
|
+
# @param model[Object] any type of object that needs to be presented
|
18
|
+
# @param klass [KlassName] a different presenter klass
|
19
|
+
# @return model presenter instance
|
20
|
+
#
|
21
|
+
def presenter_for(model, klass = nil)
|
22
|
+
return if model.nil?
|
23
|
+
klass ||= "#{model.class.name}#{Tuxedo.config.suffix}".constantize
|
24
|
+
presenter = klass.new(model, self)
|
25
|
+
yield presenter if block_given?
|
26
|
+
presenter
|
27
|
+
end
|
28
|
+
|
29
|
+
# Present And Call
|
30
|
+
# Shorthand method for using the following call
|
31
|
+
#
|
32
|
+
# presenter_for(object).zone_label
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
#
|
36
|
+
# prac object :zone_label
|
37
|
+
#
|
38
|
+
# @param object [Object]
|
39
|
+
# @param method [method] the method we should call on the presentor
|
40
|
+
# @param args [Hash] optional arguments for the method
|
41
|
+
#
|
42
|
+
def prac(object, method, *args)
|
43
|
+
return if object.nil? || method.nil?
|
44
|
+
presenter_for(object).send(method.to_sym, *args)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'active_support/configurable'
|
2
|
+
|
3
|
+
module Tuxedo
|
4
|
+
# Configures global settings for Tuxedo
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
#
|
8
|
+
# Tuxedo.configure do |config|
|
9
|
+
# config.suffix = 'Presenter'
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# @return [Tuxedo::Configuration]
|
13
|
+
#
|
14
|
+
def self.configure
|
15
|
+
yield @config ||= Tuxedo::Configuration.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the current config
|
19
|
+
#
|
20
|
+
# @return [Tuxedo::Configuration]
|
21
|
+
#
|
22
|
+
def self.config
|
23
|
+
@config || Tuxedo::Configuration.new
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
class Configuration
|
28
|
+
include ActiveSupport::Configurable
|
29
|
+
config_accessor(:suffix) { 'Presenter' }
|
30
|
+
end
|
31
|
+
end
|
data/lib/tuxedo.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'tuxedo/version'
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'active_support/inflector'
|
5
|
+
require 'active_support/core_ext/module/delegation'
|
6
|
+
require 'charlatan'
|
7
|
+
|
8
|
+
require 'tuxedo/config'
|
9
|
+
require 'tuxedo/action_view/helpers'
|
10
|
+
require 'tuxedo/railtie' if defined?(Rails)
|
11
|
+
|
12
|
+
# Tuxedo main module
|
13
|
+
# To use Tuxedo include it in any Ruby Object
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
#
|
17
|
+
# class BananaPresenter
|
18
|
+
# include Tuxedo
|
19
|
+
#
|
20
|
+
# def name
|
21
|
+
# 'hello'
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# def name_with_args(name, surname: '')
|
25
|
+
# "hello #{name}, #{surname}"
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
module Tuxedo
|
30
|
+
extend ActiveSupport::Concern
|
31
|
+
|
32
|
+
included do
|
33
|
+
include Charlatan.new(:object)
|
34
|
+
|
35
|
+
# Initializes a new Tuxedo class using the to decorate object and the view context
|
36
|
+
# @param [Object] object to decorate
|
37
|
+
# @param [ActionView::Context] view_context
|
38
|
+
#
|
39
|
+
def initialize(object, view_context)
|
40
|
+
super(object)
|
41
|
+
@view_context = view_context
|
42
|
+
self.class.setup_alias_method
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class_methods do
|
47
|
+
# Alias method name for accessing the original object
|
48
|
+
# Defaults to guessing the name from the class
|
49
|
+
#
|
50
|
+
# @param [Symbol] name alias
|
51
|
+
#
|
52
|
+
def object_alias(name)
|
53
|
+
setup_alias_method(name || underscored_name)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Guesses the name using the class name
|
57
|
+
#
|
58
|
+
# @return [String]
|
59
|
+
#
|
60
|
+
def underscored_name
|
61
|
+
name.demodulize.gsub(Tuxedo.config.suffix, '').underscore
|
62
|
+
end
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
# This setup (after initialize) a new method for accessing the original object
|
66
|
+
# alias_method wont work well with inheritance/includes/extends
|
67
|
+
#
|
68
|
+
def setup_alias_method(name = underscored_name)
|
69
|
+
define_method(name) { object }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Helper method that delegates to the view context
|
74
|
+
# this allows you to call the url helpers from Rails
|
75
|
+
#
|
76
|
+
# _h.link_to ...
|
77
|
+
#
|
78
|
+
# @return [ActionView::Context]
|
79
|
+
#
|
80
|
+
def _h
|
81
|
+
@view_context
|
82
|
+
end
|
83
|
+
|
84
|
+
# Define delegations of our prac helper to the view context, allows to call prac inside the
|
85
|
+
# presenters
|
86
|
+
delegate(:prac, to: :_h)
|
87
|
+
|
88
|
+
# These methods are already defined on Object by default or by rails, so we
|
89
|
+
# have to explicitly delegate them to the model.
|
90
|
+
delegate(:to_param, to: :object)
|
91
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Tuxedo do
|
4
|
+
describe 'suffix' do
|
5
|
+
specify { expect(Tuxedo.config.suffix).to eq 'Presenter' }
|
6
|
+
context 'configured via config block' do
|
7
|
+
before do
|
8
|
+
Tuxedo.configure { |config| config.suffix = 'Pre' }
|
9
|
+
end
|
10
|
+
specify { expect(Tuxedo.config.suffix).to eq 'Pre' }
|
11
|
+
|
12
|
+
after do
|
13
|
+
Tuxedo.configure { |config| config.suffix = 'Presenter' }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Tuxedo::ActionView::Helpers do
|
4
|
+
let(:helper_class) { Struct.new(:helper) { include Tuxedo::ActionView::Helpers } }
|
5
|
+
let(:helper) { helper_class.new }
|
6
|
+
describe 'presenter_for' do
|
7
|
+
subject { helper.presenter_for(Dummy.new) }
|
8
|
+
|
9
|
+
context "when providing instance" do
|
10
|
+
specify { expect(subject).to be_an_instance_of(DummyPresenter) }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when providing a different instance" do
|
14
|
+
subject { helper.presenter_for(Dummy.new, Dummy2Presenter) }
|
15
|
+
specify { expect(subject).to be_an_instance_of(Dummy2Presenter) }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when provided object is nil" do
|
19
|
+
subject { helper.presenter_for(nil) }
|
20
|
+
specify { expect(subject).to be_nil }
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when used with a block" do
|
24
|
+
specify { expect { |block| helper.presenter_for(Dummy.new, &block) }.to yield_control }
|
25
|
+
specify { expect { |block| helper.presenter_for(Dummy.new, &block) }.to yield_with_args(instance_of(DummyPresenter)) }
|
26
|
+
specify { expect { |block|
|
27
|
+
helper.presenter_for(Dummy.new, Dummy2Presenter, &block)
|
28
|
+
}.to yield_with_args(instance_of(Dummy2Presenter)) }
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when presenter does not exist" do
|
32
|
+
subject { helper.presenter_for(UnknownKlass) }
|
33
|
+
specify { expect { subject }.to raise_error(NameError) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'prac' do
|
38
|
+
subject { helper.prac Dummy.new, :name }
|
39
|
+
|
40
|
+
it "delegates to presenter_for" do
|
41
|
+
expect(helper).to receive(:presenter_for).with(instance_of(Dummy)).and_call_original
|
42
|
+
subject
|
43
|
+
end
|
44
|
+
|
45
|
+
context "providing a valid method name" do
|
46
|
+
it "calls the method on the presenter" do
|
47
|
+
expect_any_instance_of(DummyPresenter).to receive(:name)
|
48
|
+
subject
|
49
|
+
end
|
50
|
+
|
51
|
+
context "with extra arguments" do
|
52
|
+
subject { helper.prac Dummy.new, :name_with_args, 'Jan', surname: 'Stevens' }
|
53
|
+
it "calls the method with arguments on the presenter" do
|
54
|
+
expect_any_instance_of(DummyPresenter).to receive(:name_with_args).with('Jan', surname: 'Stevens')
|
55
|
+
subject
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when the object is nil" do
|
61
|
+
subject { helper.prac nil, :name }
|
62
|
+
it "should return nil" do
|
63
|
+
expect(subject).to be_nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when the method is nil" do
|
68
|
+
subject { helper.prac Dummy.new, nil }
|
69
|
+
it "should return nil" do
|
70
|
+
expect(subject).to be_nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'tuxedo'
|
3
|
+
require 'support/dummy_classes'
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.expect_with(:rspec) { |c| c.syntax = :expect }
|
7
|
+
config.order = :random
|
8
|
+
config.mock_with :rspec do |mocks|
|
9
|
+
mocks.yield_receiver_to_any_instance_implementation_blocks = true
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Dummy
|
2
|
+
end
|
3
|
+
|
4
|
+
class DummyPresenter
|
5
|
+
include Tuxedo
|
6
|
+
|
7
|
+
def name
|
8
|
+
'hello'
|
9
|
+
end
|
10
|
+
|
11
|
+
def name_with_args(name, surname: '')
|
12
|
+
"hello #{name}, #{surname}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Dummy2Presenter
|
17
|
+
include Tuxedo
|
18
|
+
end
|
19
|
+
|
20
|
+
class ApplicationPresenter
|
21
|
+
include Tuxedo
|
22
|
+
end
|
23
|
+
|
24
|
+
class OverwriteNamePresenter < ApplicationPresenter
|
25
|
+
|
26
|
+
end
|
data/spec/tuxedo_spec.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Tuxedo do
|
4
|
+
let(:view_class) { Struct.new(:view) { include Tuxedo::ActionView::Helpers } }
|
5
|
+
let(:view) { view_class.new }
|
6
|
+
let(:dummy) { Dummy.new }
|
7
|
+
let(:presenter_instance) { OverwriteNamePresenter.new(dummy, view) }
|
8
|
+
|
9
|
+
it 'addes an alias to the original object using the class name by default' do
|
10
|
+
expect(presenter_instance).to respond_to(:overwrite_name)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#_h' do
|
14
|
+
subject { presenter_instance._h }
|
15
|
+
it 'returns the view context' do
|
16
|
+
expect(subject).to eq view
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#prac' do
|
21
|
+
subject { presenter_instance.prac(dummy, :name) }
|
22
|
+
it 'delegates prac to the view context' do
|
23
|
+
expect_any_instance_of(DummyPresenter).to receive(:name)
|
24
|
+
subject
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#to_param' do
|
29
|
+
subject { presenter_instance.to_param }
|
30
|
+
it 'delegates to the object' do
|
31
|
+
expect(dummy).to receive(:to_param)
|
32
|
+
subject
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '.object_alias' do
|
37
|
+
after :each do
|
38
|
+
OverwriteNamePresenter.object_alias(nil)
|
39
|
+
end
|
40
|
+
subject { OverwriteNamePresenter.object_alias(:cookies) }
|
41
|
+
it 'allows to overwrite the alias to access the object' do
|
42
|
+
subject
|
43
|
+
expect(presenter_instance.cookies).to eq(dummy)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tuxedo/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "tuxedo_decorate"
|
8
|
+
gem.version = Tuxedo::VERSION
|
9
|
+
gem.authors = ["Jan Stevens"]
|
10
|
+
gem.email = ["jan@playpass.be"]
|
11
|
+
|
12
|
+
gem.summary = %q{Tuxedo simple presenter logic under 150 LOC}
|
13
|
+
gem.homepage = "https://github.com/playpasshq/tuxedo"
|
14
|
+
gem.license = "MIT"
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
17
|
+
# delete this section to allow pushing this gem to any host.
|
18
|
+
if gem.respond_to?(:metadata)
|
19
|
+
gem.metadata['allowed_push_host'] = "https://rubygems.org"
|
20
|
+
else
|
21
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
22
|
+
end
|
23
|
+
|
24
|
+
gem.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|gem|features)/}) }
|
25
|
+
gem.test_files = gem.files.grep(%r{^(test|gem|features)/})
|
26
|
+
gem.require_paths = ["lib"]
|
27
|
+
|
28
|
+
gem.add_development_dependency "bundler", "~> 1.3"
|
29
|
+
gem.add_development_dependency "rake", "~> 10.0"
|
30
|
+
gem.add_development_dependency "appraisal"
|
31
|
+
gem.add_development_dependency "rspec"
|
32
|
+
gem.add_development_dependency "yard"
|
33
|
+
|
34
|
+
gem.add_dependency 'activesupport', '>= 4.0.0'
|
35
|
+
gem.add_dependency 'railties', '>= 4.0.0'
|
36
|
+
gem.add_dependency 'charlatan', '~> 0'
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tuxedo_decorate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Stevens
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: appraisal
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: yard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 4.0.0
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 4.0.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: railties
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 4.0.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 4.0.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: charlatan
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- jan@playpass.be
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".rspec"
|
134
|
+
- ".travis.yml"
|
135
|
+
- Appraisals
|
136
|
+
- CODE_OF_CONDUCT.md
|
137
|
+
- Gemfile
|
138
|
+
- LICENSE.txt
|
139
|
+
- README.md
|
140
|
+
- Rakefile
|
141
|
+
- bin/console
|
142
|
+
- bin/setup
|
143
|
+
- gemfiles/rails_4.2.gemfile
|
144
|
+
- gemfiles/rails_stable.gemfile
|
145
|
+
- lib/tuxedo.rb
|
146
|
+
- lib/tuxedo/action_view/helpers.rb
|
147
|
+
- lib/tuxedo/config.rb
|
148
|
+
- lib/tuxedo/railtie.rb
|
149
|
+
- lib/tuxedo/version.rb
|
150
|
+
- spec/config_spec.rb
|
151
|
+
- spec/helpers/helpers_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
- spec/support/dummy_classes.rb
|
154
|
+
- spec/tuxedo_spec.rb
|
155
|
+
- tuxedo_decorate.gemspec
|
156
|
+
homepage: https://github.com/playpasshq/tuxedo
|
157
|
+
licenses:
|
158
|
+
- MIT
|
159
|
+
metadata:
|
160
|
+
allowed_push_host: https://rubygems.org
|
161
|
+
post_install_message:
|
162
|
+
rdoc_options: []
|
163
|
+
require_paths:
|
164
|
+
- lib
|
165
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
requirements: []
|
176
|
+
rubyforge_project:
|
177
|
+
rubygems_version: 2.4.5.1
|
178
|
+
signing_key:
|
179
|
+
specification_version: 4
|
180
|
+
summary: Tuxedo simple presenter logic under 150 LOC
|
181
|
+
test_files: []
|
182
|
+
has_rdoc:
|