draper 0.7.3 → 0.7.4
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.
- data/.gitignore +1 -0
- data/.yardopts +1 -0
- data/Gemfile +1 -0
- data/Readme.markdown +32 -17
- data/doc/ApplicationDecorator.html +147 -0
- data/doc/Draper.html +123 -0
- data/doc/Draper/AllHelpers.html +256 -0
- data/doc/Draper/Base.html +1222 -0
- data/doc/Draper/DecoratorGenerator.html +216 -0
- data/doc/Draper/LazyHelpers.html +174 -0
- data/doc/Draper/ModelSupport.html +164 -0
- data/doc/Draper/System.html +179 -0
- data/doc/_index.html +172 -0
- data/doc/class_list.html +47 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +53 -0
- data/doc/css/style.css +320 -0
- data/doc/file_list.html +46 -0
- data/doc/frames.html +13 -0
- data/doc/index.html +172 -0
- data/doc/js/app.js +205 -0
- data/doc/js/full_list.js +150 -0
- data/doc/js/jquery.js +16 -0
- data/doc/method_list.html +174 -0
- data/doc/top-level-namespace.html +103 -0
- data/lib/draper/base.rb +100 -15
- data/lib/draper/model_support.rb +1 -0
- data/lib/draper/version.rb +1 -1
- data/lib/generators/rails/decorator_generator.rb +15 -0
- data/spec/base_spec.rb +16 -3
- data/spec/draper/model_support_spec.rb +5 -0
- data/spec/samples/active_record.rb +1 -4
- data/spec/samples/decorator_with_allows.rb +1 -1
- data/spec/samples/product_decorator.rb +4 -0
- metadata +45 -40
@@ -0,0 +1,103 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.7.2
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
relpath = '';
|
19
|
+
if (relpath != '') relpath += '/';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
23
|
+
|
24
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
25
|
+
|
26
|
+
|
27
|
+
</head>
|
28
|
+
<body>
|
29
|
+
<script type="text/javascript" charset="utf-8">
|
30
|
+
if (window.top.frames.main) document.body.className = 'frames';
|
31
|
+
</script>
|
32
|
+
|
33
|
+
<div id="header">
|
34
|
+
<div id="menu">
|
35
|
+
|
36
|
+
<a href="_index.html">Index</a> »
|
37
|
+
|
38
|
+
|
39
|
+
<span class="title">Top Level Namespace</span>
|
40
|
+
|
41
|
+
|
42
|
+
<div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
|
43
|
+
</div>
|
44
|
+
|
45
|
+
<div id="search">
|
46
|
+
|
47
|
+
<a id="class_list_link" href="#">Class List</a>
|
48
|
+
|
49
|
+
<a id="method_list_link" href="#">Method List</a>
|
50
|
+
|
51
|
+
<a id="file_list_link" href="#">File List</a>
|
52
|
+
|
53
|
+
</div>
|
54
|
+
<div class="clear"></div>
|
55
|
+
</div>
|
56
|
+
|
57
|
+
<iframe id="search_frame"></iframe>
|
58
|
+
|
59
|
+
<div id="content"><h1>Top Level Namespace
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
</h1>
|
64
|
+
|
65
|
+
<dl class="box">
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
</dl>
|
75
|
+
<div class="clear"></div>
|
76
|
+
|
77
|
+
<h2>Defined Under Namespace</h2>
|
78
|
+
<p class="children">
|
79
|
+
|
80
|
+
|
81
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Draper.html" title="Draper (module)">Draper</a></span>
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
</p>
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
</div>
|
95
|
+
|
96
|
+
<div id="footer">
|
97
|
+
Generated on Thu Sep 1 01:13:37 2011 by
|
98
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
99
|
+
0.7.2 (ruby-1.8.7).
|
100
|
+
</div>
|
101
|
+
|
102
|
+
</body>
|
103
|
+
</html>
|
data/lib/draper/base.rb
CHANGED
@@ -6,72 +6,157 @@ module Draper
|
|
6
6
|
|
7
7
|
DEFAULT_DENIED = Object.new.methods << :method_missing
|
8
8
|
FORCED_PROXY = [:to_param]
|
9
|
+
FORCED_PROXY.each do |method|
|
10
|
+
define_method method do |*args, &block|
|
11
|
+
model.send method, *args, &block
|
12
|
+
end
|
13
|
+
end
|
9
14
|
self.denied = DEFAULT_DENIED
|
10
15
|
|
11
|
-
|
16
|
+
# Initialize a new decorator instance by passing in
|
17
|
+
# an instance of the source class. Pass in an optional
|
18
|
+
# context is stored for later use.
|
19
|
+
#
|
20
|
+
# @param [Object] instance to wrap
|
21
|
+
# @param [Object] context (optional)
|
22
|
+
def initialize(input, context = {})
|
23
|
+
input.inspect # forces evaluation of a lazy query from AR
|
12
24
|
input.inspect
|
13
25
|
self.class.model_class = input.class if model_class.nil?
|
14
26
|
@model = input
|
15
27
|
self.context = context
|
16
|
-
build_methods
|
17
28
|
end
|
18
29
|
|
19
|
-
|
20
|
-
|
30
|
+
# Proxies to the class specified by `decorates` to automatically
|
31
|
+
# lookup an object in the database and decorate it.
|
32
|
+
#
|
33
|
+
# @param [Symbol or String] id to lookup
|
34
|
+
# @return [Object] instance of this decorator class
|
35
|
+
def self.find(input, context = {})
|
36
|
+
self.new(model_class.find(input), context)
|
21
37
|
end
|
22
38
|
|
39
|
+
# Typically called within a decorator definition, this method
|
40
|
+
# specifies the name of the wrapped object class.
|
41
|
+
#
|
42
|
+
# For instance, a `ProductDecorator` class might call `decorates :product`
|
43
|
+
#
|
44
|
+
# But they don't have to match in name, so a `EmployeeDecorator`
|
45
|
+
# class could call `decorates :person` to wrap instances of `Person`
|
46
|
+
#
|
47
|
+
# This is primarilly set so the `.find` method knows which class
|
48
|
+
# to query.
|
49
|
+
#
|
50
|
+
# @param [Symbol] class_name snakecase name of the decorated class, like `:product`
|
23
51
|
def self.decorates(input)
|
24
52
|
self.model_class = input.to_s.camelize.constantize
|
25
53
|
model_class.send :include, Draper::ModelSupport
|
26
54
|
end
|
27
55
|
|
56
|
+
# Specifies a black list of methods which may *not* be proxied to
|
57
|
+
# to the wrapped object.
|
58
|
+
#
|
59
|
+
# Do not use both `.allows` and `.denies` together, either write
|
60
|
+
# a whitelist with `.allows` or a blacklist with `.denies`
|
61
|
+
#
|
62
|
+
# @param [Symbols*] methods to deny like `:find, :find_by_name`
|
28
63
|
def self.denies(*input_denied)
|
29
64
|
raise ArgumentError, "Specify at least one method (as a symbol) to exclude when using denies" if input_denied.empty?
|
30
65
|
raise ArgumentError, "Use either 'allows' or 'denies', but not both." if self.allowed?
|
31
66
|
self.denied += input_denied
|
32
67
|
end
|
33
68
|
|
69
|
+
# Specifies a white list of methods which *may* be proxied to
|
70
|
+
# to the wrapped object. When `allows` is used, only the listed
|
71
|
+
# methods and methods defined in the decorator itself will be
|
72
|
+
# available.
|
73
|
+
#
|
74
|
+
# Do not use both `.allows` and `.denies` together, either write
|
75
|
+
# a whitelist with `.allows` or a blacklist with `.denies`
|
76
|
+
#
|
77
|
+
# @param [Symbols*] methods to allow like `:find, :find_by_name`
|
34
78
|
def self.allows(*input_allows)
|
35
79
|
raise ArgumentError, "Specify at least one method (as a symbol) to allow when using allows" if input_allows.empty?
|
36
80
|
raise ArgumentError, "Use either 'allows' or 'denies', but not both." unless (self.denied == DEFAULT_DENIED)
|
37
81
|
self.allowed = input_allows
|
38
82
|
end
|
39
83
|
|
40
|
-
|
84
|
+
# Initialize a new decorator instance by passing in
|
85
|
+
# an instance of the source class. Pass in an optional
|
86
|
+
# context is stored for later use.
|
87
|
+
#
|
88
|
+
# When passing in a single object, using `.decorate` is
|
89
|
+
# identical to calling `.new`. However, `.decorate` can
|
90
|
+
# also accept a collection and return a collection of
|
91
|
+
# individually decorated objects.
|
92
|
+
#
|
93
|
+
# @param [Object] instance(s) to wrap
|
94
|
+
# @param [Object] context (optional)
|
95
|
+
def self.decorate(input, context = {})
|
41
96
|
input.respond_to?(:each) ? input.map{|i| new(i, context)} : new(input, context)
|
42
97
|
end
|
43
98
|
|
99
|
+
# Access the helpers proxy to call built-in and user-defined
|
100
|
+
# Rails helpers. Aliased to `.h` for convinience.
|
101
|
+
#
|
102
|
+
# @return [Object] proxy
|
44
103
|
def helpers
|
45
104
|
@helpers ||= ApplicationController::all_helpers
|
46
105
|
end
|
47
106
|
alias :h :helpers
|
48
107
|
|
108
|
+
# Calling `lazy_helpers` will make the built-in and
|
109
|
+
# user-defined Rails helpers accessible as class methods
|
110
|
+
# in the decorator without using the `h.` or `helpers.` proxy.
|
111
|
+
#
|
112
|
+
# The drawback is that you dump many methods into your decorator's
|
113
|
+
# namespace and collisions could create unexpected results.
|
49
114
|
def self.lazy_helpers
|
50
115
|
self.send(:include, Draper::LazyHelpers)
|
51
116
|
end
|
52
117
|
|
118
|
+
# Use primarily by `form_for`, this returns an instance of
|
119
|
+
# `ActiveModel::Name` set to the wrapped model's class name
|
120
|
+
#
|
121
|
+
# @return [ActiveModel::Name] model_name
|
53
122
|
def self.model_name
|
54
123
|
ActiveModel::Name.new(model_class)
|
55
124
|
end
|
56
125
|
|
126
|
+
# Fetch the original wrapped model.
|
127
|
+
#
|
128
|
+
# @return [Object] original_model
|
57
129
|
def to_model
|
58
130
|
@model
|
59
131
|
end
|
60
132
|
|
133
|
+
# Delegates == to the decorated models
|
134
|
+
#
|
135
|
+
# @return [Boolean] true if other's model == self's model
|
136
|
+
def ==(other)
|
137
|
+
@model == other.model
|
138
|
+
end
|
139
|
+
|
140
|
+
def respond_to?(method)
|
141
|
+
if select_methods.include?(method)
|
142
|
+
model.respond_to?(method)
|
143
|
+
else
|
144
|
+
super
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def method_missing(method, *args, &block)
|
149
|
+
if select_methods.include?(method)
|
150
|
+
model.send(method, *args, &block)
|
151
|
+
else
|
152
|
+
super
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
61
156
|
private
|
62
157
|
def select_methods
|
63
158
|
specified = self.allowed || (model.public_methods.map{|s| s.to_sym} - denied.map{|s| s.to_sym})
|
64
159
|
(specified - self.public_methods.map{|s| s.to_sym}) + FORCED_PROXY
|
65
160
|
end
|
66
|
-
|
67
|
-
def build_methods
|
68
|
-
select_methods.each do |method|
|
69
|
-
(class << self; self; end).class_eval do
|
70
|
-
define_method method do |*args, &block|
|
71
|
-
model.send method, *args, &block
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
161
|
end
|
77
162
|
end
|
data/lib/draper/model_support.rb
CHANGED
data/lib/draper/version.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path('../../draper/decorator/decorator_generator.rb', __FILE__)
|
2
|
+
class Rails::DecoratorGenerator < Draper::DecoratorGenerator
|
3
|
+
|
4
|
+
source_root File.expand_path('../../draper/decorator/templates', __FILE__)
|
5
|
+
|
6
|
+
class_option :invoke_after_finished, :type => :string, :description => "Generator to invoke when finished"
|
7
|
+
|
8
|
+
def build_model_and_application_decorators
|
9
|
+
super
|
10
|
+
if self.options[:invoke_after_finished]
|
11
|
+
Rails::Generators.invoke(self.options[:invoke_after_finished], [@name, @_initializer.first[1..-1]])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/base_spec.rb
CHANGED
@@ -43,8 +43,9 @@ describe Draper::Base do
|
|
43
43
|
|
44
44
|
context("selecting methods") do
|
45
45
|
it "echos the methods of the wrapped class except default exclusions" do
|
46
|
+
pending "Fine on 1.9 but fails on 1.8 due to differences in implementation of respond_to and method_missing. Help?"
|
46
47
|
source.methods.each do |method|
|
47
|
-
unless Draper::Base::DEFAULT_DENIED.include?(method)
|
48
|
+
unless Draper::Base::DEFAULT_DENIED.include?(method)
|
48
49
|
subject.should respond_to(method)
|
49
50
|
end
|
50
51
|
end
|
@@ -88,6 +89,11 @@ describe Draper::Base do
|
|
88
89
|
pd.should be_instance_of(ProductDecorator)
|
89
90
|
pd.model.should be_instance_of(Product)
|
90
91
|
end
|
92
|
+
|
93
|
+
it "should accept and store a context" do
|
94
|
+
pd = ProductDecorator.find(1, :admin)
|
95
|
+
pd.context.should == :admin
|
96
|
+
end
|
91
97
|
end
|
92
98
|
|
93
99
|
context ".decorate" do
|
@@ -132,6 +138,13 @@ describe Draper::Base do
|
|
132
138
|
end
|
133
139
|
end
|
134
140
|
|
141
|
+
context('.==') do
|
142
|
+
it "should compare the decorated models" do
|
143
|
+
other = Draper::Base.new(source)
|
144
|
+
subject.should == other
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
135
148
|
describe "a sample usage with denies" do
|
136
149
|
let(:subject_with_denies){ DecoratorWithDenies.new(source) }
|
137
150
|
|
@@ -156,11 +169,11 @@ describe Draper::Base do
|
|
156
169
|
let(:subject_with_allows){ DecoratorWithAllows.new(source) }
|
157
170
|
|
158
171
|
it "should echo the allowed method" do
|
159
|
-
subject_with_allows.should respond_to(:
|
172
|
+
subject_with_allows.should respond_to(:goodnight_moon)
|
160
173
|
end
|
161
174
|
|
162
175
|
it "should echo _only_ the allowed method" do
|
163
|
-
subject_with_allows.should_not respond_to(:
|
176
|
+
subject_with_allows.should_not respond_to(:hello_world)
|
164
177
|
end
|
165
178
|
end
|
166
179
|
|
@@ -6,5 +6,10 @@ describe Draper::ModelSupport do
|
|
6
6
|
describe '#decorator' do
|
7
7
|
its(:decorator) { should be_kind_of(ProductDecorator) }
|
8
8
|
its(:decorator) { should be(subject.decorator) }
|
9
|
+
|
10
|
+
it 'should have abillity to pass block' do
|
11
|
+
a = Product.new.decorator { |d| d.awesome_title }
|
12
|
+
a.should eql "Awesome Title"
|
13
|
+
end
|
9
14
|
end
|
10
15
|
end
|
metadata
CHANGED
@@ -1,39 +1,52 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: draper
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.4
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 7
|
9
|
-
- 3
|
10
|
-
version: 0.7.3
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Jeff Casimir
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2011-08-29 00:00:00 Z
|
12
|
+
date: 2011-10-03 00:00:00.000000000Z
|
19
13
|
dependencies: []
|
20
|
-
|
21
|
-
|
22
|
-
email:
|
14
|
+
description: Draper reimagines the role of helpers in the view layer of a Rails application,
|
15
|
+
allowing an object-oriented approach rather than procedural.
|
16
|
+
email:
|
23
17
|
- jeff@casimircreative.com
|
24
18
|
executables: []
|
25
|
-
|
26
19
|
extensions: []
|
27
|
-
|
28
20
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
files:
|
21
|
+
files:
|
31
22
|
- .gitignore
|
32
23
|
- .travis.yml
|
24
|
+
- .yardopts
|
33
25
|
- Gemfile
|
34
26
|
- Guardfile
|
35
27
|
- Rakefile
|
36
28
|
- Readme.markdown
|
29
|
+
- doc/ApplicationDecorator.html
|
30
|
+
- doc/Draper.html
|
31
|
+
- doc/Draper/AllHelpers.html
|
32
|
+
- doc/Draper/Base.html
|
33
|
+
- doc/Draper/DecoratorGenerator.html
|
34
|
+
- doc/Draper/LazyHelpers.html
|
35
|
+
- doc/Draper/ModelSupport.html
|
36
|
+
- doc/Draper/System.html
|
37
|
+
- doc/_index.html
|
38
|
+
- doc/class_list.html
|
39
|
+
- doc/css/common.css
|
40
|
+
- doc/css/full_list.css
|
41
|
+
- doc/css/style.css
|
42
|
+
- doc/file_list.html
|
43
|
+
- doc/frames.html
|
44
|
+
- doc/index.html
|
45
|
+
- doc/js/app.js
|
46
|
+
- doc/js/full_list.js
|
47
|
+
- doc/js/jquery.js
|
48
|
+
- doc/method_list.html
|
49
|
+
- doc/top-level-namespace.html
|
37
50
|
- draper.gemspec
|
38
51
|
- lib/draper.rb
|
39
52
|
- lib/draper/all_helpers.rb
|
@@ -46,6 +59,7 @@ files:
|
|
46
59
|
- lib/generators/draper/decorator/decorator_generator.rb
|
47
60
|
- lib/generators/draper/decorator/templates/application_decorator.rb
|
48
61
|
- lib/generators/draper/decorator/templates/decorator.rb
|
62
|
+
- lib/generators/rails/decorator_generator.rb
|
49
63
|
- spec/base_spec.rb
|
50
64
|
- spec/draper/model_support_spec.rb
|
51
65
|
- spec/samples/active_record.rb
|
@@ -59,38 +73,29 @@ files:
|
|
59
73
|
- spec/spec_helper.rb
|
60
74
|
homepage: http://github.com/jcasimir/draper
|
61
75
|
licenses: []
|
62
|
-
|
63
76
|
post_install_message:
|
64
77
|
rdoc_options: []
|
65
|
-
|
66
|
-
require_paths:
|
78
|
+
require_paths:
|
67
79
|
- lib
|
68
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
81
|
none: false
|
70
|
-
requirements:
|
71
|
-
- -
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
|
74
|
-
|
75
|
-
- 0
|
76
|
-
version: "0"
|
77
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
87
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
83
|
-
segments:
|
84
|
-
- 0
|
85
|
-
version: "0"
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
86
92
|
requirements: []
|
87
|
-
|
88
93
|
rubyforge_project: draper
|
89
|
-
rubygems_version: 1.8.
|
94
|
+
rubygems_version: 1.8.10
|
90
95
|
signing_key:
|
91
96
|
specification_version: 3
|
92
97
|
summary: Decorator pattern implmentation for Rails.
|
93
|
-
test_files:
|
98
|
+
test_files:
|
94
99
|
- spec/base_spec.rb
|
95
100
|
- spec/draper/model_support_spec.rb
|
96
101
|
- spec/samples/active_record.rb
|