draper 0.17.0 → 1.0.0.beta1
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 +3 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.markdown +14 -0
- data/Gemfile +4 -0
- data/Rakefile +50 -31
- data/Readme.markdown +63 -92
- data/draper.gemspec +4 -2
- data/lib/draper/collection_decorator.rb +88 -0
- data/lib/draper/decoratable.rb +44 -0
- data/lib/draper/decorated_association.rb +55 -0
- data/lib/draper/decorator.rb +208 -0
- data/lib/draper/finders.rb +44 -0
- data/lib/draper/helper_proxy.rb +16 -0
- data/lib/draper/railtie.rb +17 -21
- data/lib/draper/security.rb +48 -0
- data/lib/draper/tasks/tu.rake +5 -0
- data/lib/draper/test/minitest_integration.rb +5 -24
- data/lib/draper/test/rspec_integration.rb +0 -6
- data/lib/draper/test/test_unit_integration.rb +9 -0
- data/lib/draper/version.rb +1 -1
- data/lib/draper/view_context.rb +24 -6
- data/lib/draper/view_helpers.rb +36 -0
- data/lib/draper.rb +42 -7
- data/lib/generators/decorator/decorator_generator.rb +1 -1
- data/lib/generators/decorator/templates/decorator.rb +0 -1
- data/lib/generators/rspec/decorator_generator.rb +1 -1
- data/lib/generators/test_unit/decorator_generator.rb +1 -1
- data/lib/generators/test_unit/templates/decorator_test.rb +0 -3
- data/spec/draper/collection_decorator_spec.rb +240 -0
- data/spec/draper/decoratable_spec.rb +164 -0
- data/spec/draper/decorated_association_spec.rb +130 -0
- data/spec/draper/decorator_spec.rb +497 -0
- data/spec/draper/finders_spec.rb +156 -0
- data/spec/draper/helper_proxy_spec.rb +12 -0
- data/spec/draper/security_spec.rb +158 -0
- data/spec/draper/view_helpers_spec.rb +41 -0
- data/spec/dummy/.rspec +2 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +4 -0
- data/spec/dummy/app/controllers/localized_urls.rb +5 -0
- data/spec/dummy/app/controllers/posts_controller.rb +17 -0
- data/spec/dummy/app/decorators/post_decorator.rb +25 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +3 -0
- data/spec/dummy/app/mailers/post_mailer.rb +9 -0
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +11 -0
- data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +1 -0
- data/spec/dummy/app/views/posts/_post.html.erb +19 -0
- data/spec/dummy/app/views/posts/show.html.erb +1 -0
- data/spec/dummy/config/application.rb +64 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +34 -0
- data/spec/dummy/config/environments/production.rb +55 -0
- data/spec/dummy/config/environments/test.rb +32 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +7 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20121019115657_create_posts.rb +8 -0
- data/spec/dummy/db/schema.rb +21 -0
- data/spec/dummy/db/seeds.rb +2 -0
- data/spec/dummy/lib/tasks/spec.rake +5 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/spec/decorators/post_decorator_spec.rb +23 -0
- data/spec/dummy/spec/mailers/post_mailer_spec.rb +29 -0
- data/spec/dummy/spec/spec_helper.rb +9 -0
- data/spec/generators/decorator/decorator_generator_spec.rb +24 -5
- data/spec/integration/integration_spec.rb +33 -0
- data/spec/minitest-rails/spec_type_spec.rb +63 -0
- data/{performance → spec/performance}/decorators.rb +2 -4
- data/spec/spec_helper.rb +23 -26
- data/spec/support/action_controller.rb +12 -0
- data/spec/support/active_model.rb +7 -0
- data/spec/support/{samples/active_record.rb → active_record.rb} +5 -0
- data/spec/support/{samples → decorators}/decorator_with_application_helper.rb +1 -1
- data/spec/support/decorators/namespaced_product_decorator.rb +5 -0
- data/spec/support/decorators/non_active_model_product_decorator.rb +2 -0
- data/spec/support/decorators/product_decorator.rb +19 -0
- data/spec/support/decorators/products_decorator.rb +10 -0
- data/spec/support/decorators/some_thing_decorator.rb +2 -0
- data/spec/support/{samples → decorators}/specific_product_decorator.rb +0 -2
- data/spec/support/dummy_app.rb +84 -0
- data/spec/support/matchers/have_text.rb +50 -0
- data/spec/support/{samples → models}/namespaced_product.rb +1 -3
- data/spec/support/{samples → models}/non_active_model_product.rb +1 -0
- data/spec/support/{samples → models}/product.rb +13 -2
- data/spec/support/models/some_thing.rb +5 -0
- data/spec/support/models/uninferrable_decorator_model.rb +3 -0
- metadata +207 -98
- data/doc/ApplicationDecorator.html +0 -147
- data/doc/Draper/AllHelpers.html +0 -256
- data/doc/Draper/Base.html +0 -1222
- data/doc/Draper/DecoratorGenerator.html +0 -216
- data/doc/Draper/LazyHelpers.html +0 -174
- data/doc/Draper/ModelSupport.html +0 -164
- data/doc/Draper/System.html +0 -179
- data/doc/Draper.html +0 -123
- data/doc/_index.html +0 -172
- data/doc/class_list.html +0 -47
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -53
- data/doc/css/style.css +0 -320
- data/doc/file_list.html +0 -46
- data/doc/frames.html +0 -13
- data/doc/index.html +0 -172
- data/doc/js/app.js +0 -205
- data/doc/js/full_list.js +0 -150
- data/doc/js/jquery.js +0 -16
- data/doc/method_list.html +0 -174
- data/doc/top-level-namespace.html +0 -103
- data/lib/draper/active_model_support.rb +0 -27
- data/lib/draper/base.rb +0 -312
- data/lib/draper/decorated_enumerable_proxy.rb +0 -57
- data/lib/draper/model_support.rb +0 -17
- data/lib/draper/rspec_integration.rb +0 -2
- data/lib/draper/system.rb +0 -10
- data/lib/draper/test/view_context.rb +0 -12
- data/spec/draper/base_spec.rb +0 -863
- data/spec/draper/helper_support_spec.rb +0 -18
- data/spec/draper/model_support_spec.rb +0 -48
- data/spec/draper/view_context_spec.rb +0 -30
- data/spec/support/samples/active_model.rb +0 -9
- data/spec/support/samples/application_controller.rb +0 -42
- data/spec/support/samples/application_helper.rb +0 -8
- data/spec/support/samples/decorator.rb +0 -5
- data/spec/support/samples/decorator_with_allows.rb +0 -3
- data/spec/support/samples/decorator_with_denies.rb +0 -3
- data/spec/support/samples/decorator_with_denies_all.rb +0 -3
- data/spec/support/samples/decorator_with_multiple_allows.rb +0 -4
- data/spec/support/samples/decorator_with_special_methods.rb +0 -13
- data/spec/support/samples/namespaced_product_decorator.rb +0 -7
- data/spec/support/samples/product_decorator.rb +0 -7
- data/spec/support/samples/sequel_product.rb +0 -13
- data/spec/support/samples/some_thing.rb +0 -2
- data/spec/support/samples/some_thing_decorator.rb +0 -3
- /data/{performance → spec/performance}/active_record.rb +0 -0
- /data/{performance/bechmark.rb → spec/performance/benchmark.rb} +0 -0
- /data/{performance → spec/performance}/models.rb +0 -0
- /data/spec/support/{samples → decorators}/widget_decorator.rb +0 -0
- /data/spec/support/{samples → models}/widget.rb +0 -0
data/doc/method_list.html
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
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>
|
|
@@ -1,103 +0,0 @@
|
|
|
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>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
module Draper::ActiveModelSupport
|
|
2
|
-
module Proxies
|
|
3
|
-
def self.extended(base)
|
|
4
|
-
# These methods (as keys) will be created only if the correspondent
|
|
5
|
-
# model responds to the method
|
|
6
|
-
proxies = [:to_param, :errors, :id]
|
|
7
|
-
|
|
8
|
-
proxies.each do |method_name|
|
|
9
|
-
if base.model.respond_to?(method_name)
|
|
10
|
-
base.singleton_class.class_eval do
|
|
11
|
-
if !base.class.instance_methods.include?(method_name) || base.class.instance_method(method_name).owner === Draper::Base
|
|
12
|
-
define_method(method_name) do |*args, &block|
|
|
13
|
-
model.send(method_name, *args, &block)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
base.class_eval do
|
|
21
|
-
def to_model
|
|
22
|
-
self
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
data/lib/draper/base.rb
DELETED
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
module Draper
|
|
2
|
-
class Base
|
|
3
|
-
require 'active_support/core_ext/class/attribute'
|
|
4
|
-
require 'active_support/core_ext/array/extract_options'
|
|
5
|
-
|
|
6
|
-
class_attribute :denied, :allowed, :model_class
|
|
7
|
-
attr_accessor :model, :options
|
|
8
|
-
|
|
9
|
-
DEFAULT_DENIED = Object.instance_methods << :method_missing
|
|
10
|
-
DEFAULT_ALLOWED = []
|
|
11
|
-
self.denied = DEFAULT_DENIED
|
|
12
|
-
self.allowed = DEFAULT_ALLOWED
|
|
13
|
-
|
|
14
|
-
# Initialize a new decorator instance by passing in
|
|
15
|
-
# an instance of the source class. Pass in an optional
|
|
16
|
-
# context inside the options hash is stored for later use.
|
|
17
|
-
#
|
|
18
|
-
# @param [Object] instance to wrap
|
|
19
|
-
# @param [Hash] options (optional)
|
|
20
|
-
def initialize(input, options = {})
|
|
21
|
-
input.inspect # forces evaluation of a lazy query from AR
|
|
22
|
-
self.class.model_class = input.class if model_class.nil?
|
|
23
|
-
@model = input.kind_of?(Draper::Base) ? input.model : input
|
|
24
|
-
self.options = options
|
|
25
|
-
self.extend Draper::ActiveModelSupport::Proxies
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Proxies to the class specified by `decorates` to automatically
|
|
29
|
-
# lookup an object in the database and decorate it.
|
|
30
|
-
#
|
|
31
|
-
# @param [Symbol or String] id to lookup
|
|
32
|
-
# @return [Object] instance of this decorator class
|
|
33
|
-
def self.find(input, options = {})
|
|
34
|
-
self.new(model_class.find(input), options)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Typically called within a decorator definition, this method
|
|
38
|
-
# specifies the name of the wrapped object class.
|
|
39
|
-
#
|
|
40
|
-
# For instance, a `ProductDecorator` class might call `decorates :product`
|
|
41
|
-
#
|
|
42
|
-
# But they don't have to match in name, so a `EmployeeDecorator`
|
|
43
|
-
# class could call `decorates :person` to wrap instances of `Person`
|
|
44
|
-
#
|
|
45
|
-
# This is primarilly set so the `.find` method knows which class
|
|
46
|
-
# to query.
|
|
47
|
-
#
|
|
48
|
-
# @param [Symbol] class_name snakecase name of the decorated class, like `:product`
|
|
49
|
-
def self.decorates(input, options = {})
|
|
50
|
-
self.model_class = options[:class] || options[:class_name] || input.to_s.camelize
|
|
51
|
-
self.model_class = model_class.constantize if model_class.respond_to?(:constantize)
|
|
52
|
-
model_class.send :include, Draper::ModelSupport
|
|
53
|
-
define_method(input){ @model }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Typically called within a decorator definition, this method causes
|
|
57
|
-
# the assocation to be decorated when it is retrieved.
|
|
58
|
-
#
|
|
59
|
-
# @param [Symbol] name of association to decorate, like `:products`
|
|
60
|
-
# @option options [Hash] :with The decorator to decorate the association with
|
|
61
|
-
# :scope The scope to apply to the association
|
|
62
|
-
def self.decorates_association(association_symbol, options = {})
|
|
63
|
-
define_method(association_symbol) do
|
|
64
|
-
orig_association = model.send(association_symbol)
|
|
65
|
-
|
|
66
|
-
return orig_association if orig_association.nil?
|
|
67
|
-
return decorated_associations[association_symbol] if decorated_associations[association_symbol]
|
|
68
|
-
|
|
69
|
-
orig_association = orig_association.send(options[:scope]) if options[:scope]
|
|
70
|
-
|
|
71
|
-
return options[:with].decorate(orig_association) if options[:with]
|
|
72
|
-
|
|
73
|
-
klass = if options[:polymorphic]
|
|
74
|
-
orig_association.class
|
|
75
|
-
elsif association_reflection = find_association_reflection(association_symbol)
|
|
76
|
-
association_reflection.klass
|
|
77
|
-
elsif orig_association.respond_to?(:first)
|
|
78
|
-
orig_association.first.class
|
|
79
|
-
else
|
|
80
|
-
orig_association.class
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
decorated_associations[association_symbol] = "#{klass}Decorator".constantize.decorate(orig_association, options)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# A convenience method for decorating multiple associations. Calls
|
|
88
|
-
# decorates_association on each of the given symbols.
|
|
89
|
-
#
|
|
90
|
-
# @param [Symbols*] name of associations to decorate
|
|
91
|
-
def self.decorates_associations(*association_symbols)
|
|
92
|
-
options = association_symbols.extract_options!
|
|
93
|
-
association_symbols.each{ |sym| decorates_association(sym, options) }
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Specifies a black list of methods which may *not* be proxied to
|
|
97
|
-
# to the wrapped object.
|
|
98
|
-
#
|
|
99
|
-
# Do not use both `.allows` and `.denies` together, either write
|
|
100
|
-
# a whitelist with `.allows` or a blacklist with `.denies`
|
|
101
|
-
#
|
|
102
|
-
# @param [Symbols*] methods to deny like `:find, :find_by_name`
|
|
103
|
-
def self.denies(*input_denied)
|
|
104
|
-
raise ArgumentError, "Specify at least one method (as a symbol) to exclude when using denies" if input_denied.empty?
|
|
105
|
-
raise ArgumentError, "Use either 'allows' or 'denies', but not both." unless (self.allowed == DEFAULT_ALLOWED)
|
|
106
|
-
self.denied += input_denied
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Specifies that all methods may *not* be proxied to
|
|
110
|
-
# to the wrapped object.
|
|
111
|
-
#
|
|
112
|
-
# Do not use `.allows` and `.denies` in combination with '.denies_all'
|
|
113
|
-
def self.denies_all
|
|
114
|
-
raise ArgumentError, "Use either 'allows' or 'denies', but not both." unless ((self.allowed == DEFAULT_ALLOWED && self.denied == DEFAULT_DENIED) || (self.allowed != DEFAULT_ALLOWED && self.denied != DEFAULT_DENIED))
|
|
115
|
-
self.denied += [nil] # Add dummy value to denied to prevent calls to #allows. Hacky???
|
|
116
|
-
self.allowed += [nil] # Add dummy value to allowed to prevent calls to #denies
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Specifies a white list of methods which *may* be proxied to
|
|
120
|
-
# to the wrapped object. When `allows` is used, only the listed
|
|
121
|
-
# methods and methods defined in the decorator itself will be
|
|
122
|
-
# available.
|
|
123
|
-
#
|
|
124
|
-
# Do not use both `.allows` and `.denies` together, either write
|
|
125
|
-
# a whitelist with `.allows` or a blacklist with `.denies`
|
|
126
|
-
#
|
|
127
|
-
# @param [Symbols*] methods to allow like `:find, :find_by_name`
|
|
128
|
-
def self.allows(*input_allows)
|
|
129
|
-
raise ArgumentError, "Specify at least one method (as a symbol) to allow when using allows" if input_allows.empty?
|
|
130
|
-
raise ArgumentError, "Use either 'allows' or 'denies', but not both." unless (self.denied == DEFAULT_DENIED)
|
|
131
|
-
self.allowed += input_allows
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# Initialize a new decorator instance by passing in
|
|
135
|
-
# an instance of the source class. Pass in an optional
|
|
136
|
-
# context into the options hash is stored for later use.
|
|
137
|
-
#
|
|
138
|
-
# When passing in a single object, using `.decorate` is
|
|
139
|
-
# identical to calling `.new`. However, `.decorate` can
|
|
140
|
-
# also accept a collection and return a collection of
|
|
141
|
-
# individually decorated objects.
|
|
142
|
-
#
|
|
143
|
-
# @param [Object] instance(s) to wrap
|
|
144
|
-
# @param [Hash] options (optional)
|
|
145
|
-
# @option options [Boolean] :infer If true, each model will be
|
|
146
|
-
# wrapped by its inferred decorator.
|
|
147
|
-
def self.decorate(input, options = {})
|
|
148
|
-
if input.instance_of?(self)
|
|
149
|
-
input.options = options unless options.empty?
|
|
150
|
-
return input
|
|
151
|
-
elsif input.respond_to?(:each) && (!defined?(Sequel) || !input.is_a?(Sequel::Model))
|
|
152
|
-
Draper::DecoratedEnumerableProxy.new(input, self, options)
|
|
153
|
-
elsif options[:infer]
|
|
154
|
-
input.decorator(options)
|
|
155
|
-
else
|
|
156
|
-
new(input, options)
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
# Fetch all instances of the decorated class and decorate them.
|
|
161
|
-
#
|
|
162
|
-
# @param [Hash] options (optional)
|
|
163
|
-
# @return [Draper::DecoratedEnumerableProxy]
|
|
164
|
-
def self.all(options = {})
|
|
165
|
-
Draper::DecoratedEnumerableProxy.new(model_class.all, self, options)
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def self.first(options = {})
|
|
169
|
-
decorate(model_class.first, options)
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def self.last(options = {})
|
|
173
|
-
decorate(model_class.last, options)
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
# Some helpers are private, for example html_escape... as a workaround
|
|
177
|
-
# we are wrapping the helpers in a delegator that passes the methods
|
|
178
|
-
# along through a send, which will ignore private/public distinctions
|
|
179
|
-
class HelpersWrapper
|
|
180
|
-
def initialize(helpers)
|
|
181
|
-
@helpers = helpers
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def method_missing(method, *args, &block)
|
|
185
|
-
@helpers.send(method, *args, &block)
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
#needed for tests
|
|
189
|
-
def ==(other)
|
|
190
|
-
other.instance_variable_get(:@helpers) == @helpers
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
# Access the helpers proxy to call built-in and user-defined
|
|
195
|
-
# Rails helpers. Aliased to `.h` for convenience.
|
|
196
|
-
#
|
|
197
|
-
# @return [Object] proxy
|
|
198
|
-
def helpers
|
|
199
|
-
HelpersWrapper.new self.class.helpers
|
|
200
|
-
end
|
|
201
|
-
alias :h :helpers
|
|
202
|
-
|
|
203
|
-
# Localize is something that's used quite often. Even though
|
|
204
|
-
# it's available through helpers, that's annoying. Aliased
|
|
205
|
-
# to `.l` for convenience.
|
|
206
|
-
def localize(str)
|
|
207
|
-
self.class.helpers.localize(str)
|
|
208
|
-
end
|
|
209
|
-
alias :l :localize
|
|
210
|
-
|
|
211
|
-
# Access the helpers proxy to call built-in and user-defined
|
|
212
|
-
# Rails helpers from a class context.
|
|
213
|
-
#
|
|
214
|
-
# @return [Object] proxy
|
|
215
|
-
class << self
|
|
216
|
-
def helpers
|
|
217
|
-
Draper::ViewContext.current
|
|
218
|
-
end
|
|
219
|
-
alias :h :helpers
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
# Fetch the original wrapped model.
|
|
223
|
-
#
|
|
224
|
-
# @return [Object] original_model
|
|
225
|
-
def wrapped_object
|
|
226
|
-
@model
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
# Delegates == to the decorated models
|
|
230
|
-
#
|
|
231
|
-
# @return [Boolean] true if other's model == self's model
|
|
232
|
-
def ==(other)
|
|
233
|
-
@model == (other.respond_to?(:model) ? other.model : other)
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
def kind_of?(klass)
|
|
237
|
-
super || model.kind_of?(klass)
|
|
238
|
-
end
|
|
239
|
-
alias :is_a? :kind_of?
|
|
240
|
-
|
|
241
|
-
def respond_to?(method, include_private = false)
|
|
242
|
-
super || (allow?(method) && model.respond_to?(method, include_private))
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
# We always want to delegate present, in case we decorate a nil object.
|
|
246
|
-
#
|
|
247
|
-
# I don't like the idea of decorating a nil object, but we'll deal with
|
|
248
|
-
# that later.
|
|
249
|
-
def present?
|
|
250
|
-
model.present?
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def method_missing(method, *args, &block)
|
|
254
|
-
super unless allow?(method)
|
|
255
|
-
|
|
256
|
-
if model.respond_to?(method)
|
|
257
|
-
self.class.send :define_method, method do |*args, &blokk|
|
|
258
|
-
model.send method, *args, &blokk
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
send method, *args, &block
|
|
262
|
-
else
|
|
263
|
-
super
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
rescue NoMethodError => no_method_error
|
|
267
|
-
super if no_method_error.name == method
|
|
268
|
-
raise no_method_error
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def self.method_missing(method, *args, &block)
|
|
272
|
-
if method.to_s.match(/^find_((all_|last_)?by_|or_(initialize|create)_by_).*/)
|
|
273
|
-
self.decorate(model_class.send(method, *args, &block), :context => args.dup.extract_options!)
|
|
274
|
-
else
|
|
275
|
-
model_class.send(method, *args, &block)
|
|
276
|
-
end
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
def self.respond_to?(method, include_private = false)
|
|
280
|
-
super || model_class.respond_to?(method)
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
def context
|
|
284
|
-
options.fetch(:context, {})
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
def context=(input)
|
|
288
|
-
options[:context] = input
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
def source
|
|
292
|
-
model
|
|
293
|
-
end
|
|
294
|
-
alias_method :to_source, :model
|
|
295
|
-
|
|
296
|
-
private
|
|
297
|
-
|
|
298
|
-
def allow?(method)
|
|
299
|
-
(allowed.empty? || allowed.include?(method)) && !denied.include?(method)
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
def find_association_reflection(association)
|
|
303
|
-
if model.class.respond_to?(:reflect_on_association)
|
|
304
|
-
model.class.reflect_on_association(association)
|
|
305
|
-
end
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
def decorated_associations
|
|
309
|
-
@decorated_associations ||= {}
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
end
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
require 'active_support/core_ext/object/blank'
|
|
2
|
-
module Draper
|
|
3
|
-
class DecoratedEnumerableProxy
|
|
4
|
-
include Enumerable
|
|
5
|
-
|
|
6
|
-
delegate :as_json, :collect, :map, :each, :[], :all?, :include?, :first, :last, :shift, :to => :decorated_collection
|
|
7
|
-
|
|
8
|
-
def initialize(collection, klass, options = {})
|
|
9
|
-
@wrapped_collection, @klass, @options = collection, klass, options
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def decorated_collection
|
|
13
|
-
@decorated_collection ||= @wrapped_collection.collect { |member| @klass.decorate(member, @options) }
|
|
14
|
-
end
|
|
15
|
-
alias_method :to_ary, :decorated_collection
|
|
16
|
-
|
|
17
|
-
def find(ifnone_or_id = nil, &blk)
|
|
18
|
-
if block_given?
|
|
19
|
-
source.find(ifnone_or_id, &blk)
|
|
20
|
-
else
|
|
21
|
-
obj = decorated_collection.first
|
|
22
|
-
return nil if obj.blank?
|
|
23
|
-
obj.class.find(ifnone_or_id)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def method_missing (method, *args, &block)
|
|
28
|
-
@wrapped_collection.send(method, *args, &block)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def respond_to?(method, include_private = false)
|
|
32
|
-
super || @wrapped_collection.respond_to?(method, include_private)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def kind_of?(klass)
|
|
36
|
-
@wrapped_collection.kind_of?(klass) || super
|
|
37
|
-
end
|
|
38
|
-
alias :is_a? :kind_of?
|
|
39
|
-
|
|
40
|
-
def ==(other)
|
|
41
|
-
@wrapped_collection == (other.respond_to?(:source) ? other.source : other)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def to_s
|
|
45
|
-
"#<DecoratedEnumerableProxy of #{@klass} for #{@wrapped_collection.inspect}>"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def context=(input)
|
|
49
|
-
self.map { |member| member.context = input }
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def source
|
|
53
|
-
@wrapped_collection
|
|
54
|
-
end
|
|
55
|
-
alias_method :to_source, :source
|
|
56
|
-
end
|
|
57
|
-
end
|
data/lib/draper/model_support.rb
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
module Draper::ModelSupport
|
|
2
|
-
extend ActiveSupport::Concern
|
|
3
|
-
|
|
4
|
-
def decorator(options = {})
|
|
5
|
-
@decorator ||= "#{self.class.name}Decorator".constantize.decorate(self, options.merge(:infer => false))
|
|
6
|
-
block_given? ? yield(@decorator) : @decorator
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
alias :decorate :decorator
|
|
10
|
-
|
|
11
|
-
module ClassMethods
|
|
12
|
-
def decorate(options = {})
|
|
13
|
-
decorator_proxy = "#{model_name}Decorator".constantize.decorate(self.scoped, options)
|
|
14
|
-
block_given? ? yield(decorator_proxy) : decorator_proxy
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|