draper 0.7.2 → 0.8.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.
- data/.gitignore +2 -0
- data/.travis.yml +7 -0
- data/.yardopts +1 -0
- data/Gemfile +12 -2
- data/Readme.markdown +39 -24
- data/doc/ApplicationDecorator.html +147 -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/Draper.html +123 -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/draper.gemspec +0 -16
- data/lib/draper/base.rb +101 -16
- data/lib/draper/model_support.rb +1 -0
- data/lib/draper/system.rb +1 -1
- data/lib/draper/version.rb +1 -1
- data/lib/draper/view_context.rb +11 -0
- data/lib/draper.rb +1 -1
- data/lib/generators/rails/decorator_generator.rb +15 -0
- data/spec/base_spec.rb +23 -4
- data/spec/draper/model_support_spec.rb +5 -0
- data/spec/generators/draper/decorator/decorator_generator_spec.rb +28 -0
- data/spec/samples/active_record.rb +1 -4
- data/spec/samples/application_controller.rb +28 -6
- data/spec/samples/decorator_with_allows.rb +1 -1
- data/spec/samples/product_decorator.rb +4 -0
- data/spec/spec_helper.rb +4 -22
- data/spec/view_context_spec.rb +25 -0
- metadata +32 -103
- data/lib/draper/all_helpers.rb +0 -50
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
6
|
+
|
|
7
|
+
<link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" charset="utf-8" />
|
|
8
|
+
|
|
9
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
|
14
|
+
|
|
15
|
+
<script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
<base id="base_target" target="_parent" />
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<script type="text/javascript" charset="utf-8">
|
|
22
|
+
if (window.top.frames.main) {
|
|
23
|
+
document.getElementById('base_target').target = 'main';
|
|
24
|
+
document.body.className = 'frames';
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
<div id="content">
|
|
28
|
+
<h1 id="full_list_header">Method List</h1>
|
|
29
|
+
<div id="nav">
|
|
30
|
+
|
|
31
|
+
<a target="_self" href="class_list.html">Classes</a>
|
|
32
|
+
|
|
33
|
+
<a target="_self" href="method_list.html">Methods</a>
|
|
34
|
+
|
|
35
|
+
<a target="_self" href="file_list.html">Files</a>
|
|
36
|
+
|
|
37
|
+
</div>
|
|
38
|
+
<div id="search">Search: <input type="text" /></div>
|
|
39
|
+
|
|
40
|
+
<ul id="full_list" class="methods">
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
<li class="r1 ">
|
|
44
|
+
<span class='object_link'><a href="Draper/AllHelpers.html#all_helpers-instance_method" title="Draper::AllHelpers#all_helpers (method)">#all_helpers</a></span>
|
|
45
|
+
|
|
46
|
+
<small>Draper::AllHelpers</small>
|
|
47
|
+
|
|
48
|
+
</li>
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
<li class="r2 ">
|
|
52
|
+
<span class='object_link'><a href="Draper/Base.html#allows-class_method" title="Draper::Base.allows (method)">allows</a></span>
|
|
53
|
+
|
|
54
|
+
<small>Draper::Base</small>
|
|
55
|
+
|
|
56
|
+
</li>
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
<li class="r1 ">
|
|
60
|
+
<span class='object_link'><a href="Draper/Base.html#context-instance_method" title="Draper::Base#context (method)">#context</a></span>
|
|
61
|
+
|
|
62
|
+
<small>Draper::Base</small>
|
|
63
|
+
|
|
64
|
+
</li>
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
<li class="r2 ">
|
|
68
|
+
<span class='object_link'><a href="Draper/Base.html#decorate-class_method" title="Draper::Base.decorate (method)">decorate</a></span>
|
|
69
|
+
|
|
70
|
+
<small>Draper::Base</small>
|
|
71
|
+
|
|
72
|
+
</li>
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
<li class="r1 ">
|
|
76
|
+
<span class='object_link'><a href="Draper/Base.html#decorates-class_method" title="Draper::Base.decorates (method)">decorates</a></span>
|
|
77
|
+
|
|
78
|
+
<small>Draper::Base</small>
|
|
79
|
+
|
|
80
|
+
</li>
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
<li class="r2 ">
|
|
84
|
+
<span class='object_link'><a href="Draper/ModelSupport.html#decorator-instance_method" title="Draper::ModelSupport#decorator (method)">#decorator</a></span>
|
|
85
|
+
|
|
86
|
+
<small>Draper::ModelSupport</small>
|
|
87
|
+
|
|
88
|
+
</li>
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
<li class="r1 ">
|
|
92
|
+
<span class='object_link'><a href="Draper/Base.html#denies-class_method" title="Draper::Base.denies (method)">denies</a></span>
|
|
93
|
+
|
|
94
|
+
<small>Draper::Base</small>
|
|
95
|
+
|
|
96
|
+
</li>
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
<li class="r2 ">
|
|
100
|
+
<span class='object_link'><a href="Draper/Base.html#find-class_method" title="Draper::Base.find (method)">find</a></span>
|
|
101
|
+
|
|
102
|
+
<small>Draper::Base</small>
|
|
103
|
+
|
|
104
|
+
</li>
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
<li class="r1 ">
|
|
108
|
+
<span class='object_link'><a href="Draper/Base.html#helpers-instance_method" title="Draper::Base#helpers (method)">#helpers</a></span>
|
|
109
|
+
|
|
110
|
+
<small>Draper::Base</small>
|
|
111
|
+
|
|
112
|
+
</li>
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
<li class="r2 ">
|
|
116
|
+
<span class='object_link'><a href="Draper/Base.html#initialize-instance_method" title="Draper::Base#initialize (method)">#initialize</a></span>
|
|
117
|
+
|
|
118
|
+
<small>Draper::Base</small>
|
|
119
|
+
|
|
120
|
+
</li>
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
<li class="r1 ">
|
|
124
|
+
<span class='object_link'><a href="Draper/Base.html#lazy_helpers-class_method" title="Draper::Base.lazy_helpers (method)">lazy_helpers</a></span>
|
|
125
|
+
|
|
126
|
+
<small>Draper::Base</small>
|
|
127
|
+
|
|
128
|
+
</li>
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
<li class="r2 ">
|
|
132
|
+
<span class='object_link'><a href="Draper/LazyHelpers.html#method_missing-instance_method" title="Draper::LazyHelpers#method_missing (method)">#method_missing</a></span>
|
|
133
|
+
|
|
134
|
+
<small>Draper::LazyHelpers</small>
|
|
135
|
+
|
|
136
|
+
</li>
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
<li class="r1 ">
|
|
140
|
+
<span class='object_link'><a href="Draper/Base.html#model-instance_method" title="Draper::Base#model (method)">#model</a></span>
|
|
141
|
+
|
|
142
|
+
<small>Draper::Base</small>
|
|
143
|
+
|
|
144
|
+
</li>
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
<li class="r2 ">
|
|
148
|
+
<span class='object_link'><a href="Draper/Base.html#model_name-class_method" title="Draper::Base.model_name (method)">model_name</a></span>
|
|
149
|
+
|
|
150
|
+
<small>Draper::Base</small>
|
|
151
|
+
|
|
152
|
+
</li>
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
<li class="r1 ">
|
|
156
|
+
<span class='object_link'><a href="Draper/System.html#setup-class_method" title="Draper::System.setup (method)">setup</a></span>
|
|
157
|
+
|
|
158
|
+
<small>Draper::System</small>
|
|
159
|
+
|
|
160
|
+
</li>
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
<li class="r2 ">
|
|
164
|
+
<span class='object_link'><a href="Draper/Base.html#to_model-instance_method" title="Draper::Base#to_model (method)">#to_model</a></span>
|
|
165
|
+
|
|
166
|
+
<small>Draper::Base</small>
|
|
167
|
+
|
|
168
|
+
</li>
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
</ul>
|
|
172
|
+
</div>
|
|
173
|
+
</body>
|
|
174
|
+
</html>
|
|
@@ -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/draper.gemspec
CHANGED
|
@@ -17,20 +17,4 @@ Gem::Specification.new do |s|
|
|
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
19
|
s.require_paths = ["lib"]
|
|
20
|
-
|
|
21
|
-
s.add_development_dependency "rake", ["0.8.7"]
|
|
22
|
-
s.add_development_dependency "rspec", ["~> 2.0.1"]
|
|
23
|
-
s.add_development_dependency "activesupport", ["~> 3.0.9"]
|
|
24
|
-
s.add_development_dependency "actionpack", ["~> 3.0.9"]
|
|
25
|
-
s.add_development_dependency "guard"
|
|
26
|
-
s.add_development_dependency "guard-rspec"
|
|
27
|
-
s.add_development_dependency "rb-fsevent"
|
|
28
|
-
if RUBY_VERSION.to_f == 1.8
|
|
29
|
-
s.add_development_dependency "ruby-debug"
|
|
30
|
-
s.add_development_dependency "rcov"
|
|
31
|
-
s.add_development_dependency "launchy"
|
|
32
|
-
else
|
|
33
|
-
s.add_development_dependency "ruby-debug19"
|
|
34
|
-
s.add_development_dependency 'cover_me', ['>= 1.0.0.rc6']
|
|
35
|
-
end
|
|
36
20
|
end
|
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
|
+
Thread.current[:current_view_context]
|
|
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/system.rb
CHANGED
data/lib/draper/version.rb
CHANGED
data/lib/draper.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
|
@@ -2,9 +2,16 @@ require 'spec_helper'
|
|
|
2
2
|
require 'draper'
|
|
3
3
|
|
|
4
4
|
describe Draper::Base do
|
|
5
|
+
before(:each){ ApplicationController.new.set_current_view_context }
|
|
5
6
|
subject{ Draper::Base.new(source) }
|
|
6
7
|
let(:source){ Product.new }
|
|
7
8
|
|
|
9
|
+
context(".helpers") do
|
|
10
|
+
it "should have a valid view_context" do
|
|
11
|
+
subject.helpers.should be
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
8
15
|
context(".lazy_helpers") do
|
|
9
16
|
it "makes Rails helpers available without using the h. proxy" do
|
|
10
17
|
Draper::Base.lazy_helpers
|
|
@@ -44,8 +51,8 @@ describe Draper::Base do
|
|
|
44
51
|
context("selecting methods") do
|
|
45
52
|
it "echos the methods of the wrapped class except default exclusions" do
|
|
46
53
|
source.methods.each do |method|
|
|
47
|
-
unless Draper::Base::DEFAULT_DENIED.include?(method)
|
|
48
|
-
subject.should respond_to(method)
|
|
54
|
+
unless Draper::Base::DEFAULT_DENIED.include?(method)
|
|
55
|
+
subject.should respond_to(method.to_sym)
|
|
49
56
|
end
|
|
50
57
|
end
|
|
51
58
|
end
|
|
@@ -88,6 +95,11 @@ describe Draper::Base do
|
|
|
88
95
|
pd.should be_instance_of(ProductDecorator)
|
|
89
96
|
pd.model.should be_instance_of(Product)
|
|
90
97
|
end
|
|
98
|
+
|
|
99
|
+
it "should accept and store a context" do
|
|
100
|
+
pd = ProductDecorator.find(1, :admin)
|
|
101
|
+
pd.context.should == :admin
|
|
102
|
+
end
|
|
91
103
|
end
|
|
92
104
|
|
|
93
105
|
context ".decorate" do
|
|
@@ -132,6 +144,13 @@ describe Draper::Base do
|
|
|
132
144
|
end
|
|
133
145
|
end
|
|
134
146
|
|
|
147
|
+
context('.==') do
|
|
148
|
+
it "should compare the decorated models" do
|
|
149
|
+
other = Draper::Base.new(source)
|
|
150
|
+
subject.should == other
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
135
154
|
describe "a sample usage with denies" do
|
|
136
155
|
let(:subject_with_denies){ DecoratorWithDenies.new(source) }
|
|
137
156
|
|
|
@@ -156,11 +175,11 @@ describe Draper::Base do
|
|
|
156
175
|
let(:subject_with_allows){ DecoratorWithAllows.new(source) }
|
|
157
176
|
|
|
158
177
|
it "should echo the allowed method" do
|
|
159
|
-
subject_with_allows.should respond_to(:
|
|
178
|
+
subject_with_allows.should respond_to(:goodnight_moon)
|
|
160
179
|
end
|
|
161
180
|
|
|
162
181
|
it "should echo _only_ the allowed method" do
|
|
163
|
-
subject_with_allows.should_not respond_to(:
|
|
182
|
+
subject_with_allows.should_not respond_to(:hello_world)
|
|
164
183
|
end
|
|
165
184
|
end
|
|
166
185
|
|
|
@@ -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
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
# Generators are not automatically loaded by Rails
|
|
4
|
+
require 'generators/draper/decorator/decorator_generator'
|
|
5
|
+
|
|
6
|
+
describe Draper::DecoratorGenerator do
|
|
7
|
+
# Tell the generator where to put its output (what it thinks of as Rails.root)
|
|
8
|
+
destination File.expand_path("../../../../../tmp", __FILE__)
|
|
9
|
+
|
|
10
|
+
before { prepare_destination }
|
|
11
|
+
|
|
12
|
+
describe 'no arguments' do
|
|
13
|
+
before { run_generator %w(products) }
|
|
14
|
+
|
|
15
|
+
describe 'app/decorators/application_decorator.rb' do
|
|
16
|
+
subject { file('app/decorators/application_decorator.rb') }
|
|
17
|
+
it { should exist }
|
|
18
|
+
it { should contain "class ApplicationDecorator < Draper::Base" }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe 'app/decorators/products_decorator.rb' do
|
|
22
|
+
subject { file('app/decorators/products_decorator.rb') }
|
|
23
|
+
it { should exist }
|
|
24
|
+
it { should contain "class ProductsDecorator < ApplicationDecorator" }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|