draper 0.17.0 → 1.0.0.beta2

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.
Files changed (154) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +5 -0
  3. data/CHANGELOG.markdown +49 -0
  4. data/Gemfile +4 -0
  5. data/Rakefile +50 -31
  6. data/Readme.markdown +63 -92
  7. data/draper.gemspec +6 -4
  8. data/lib/draper/collection_decorator.rb +88 -0
  9. data/lib/draper/decoratable.rb +44 -0
  10. data/lib/draper/decorated_association.rb +55 -0
  11. data/lib/draper/decorator.rb +260 -0
  12. data/lib/draper/finders.rb +34 -0
  13. data/lib/draper/helper_proxy.rb +16 -0
  14. data/lib/draper/railtie.rb +17 -21
  15. data/lib/draper/security.rb +48 -0
  16. data/lib/draper/tasks/tu.rake +5 -0
  17. data/lib/draper/test/minitest_integration.rb +5 -24
  18. data/lib/draper/test/rspec_integration.rb +0 -6
  19. data/lib/draper/test/test_unit_integration.rb +9 -0
  20. data/lib/draper/version.rb +1 -1
  21. data/lib/draper/view_context.rb +24 -6
  22. data/lib/draper/view_helpers.rb +36 -0
  23. data/lib/draper.rb +48 -7
  24. data/lib/generators/decorator/decorator_generator.rb +1 -1
  25. data/lib/generators/decorator/templates/decorator.rb +0 -1
  26. data/lib/generators/rspec/decorator_generator.rb +1 -1
  27. data/lib/generators/test_unit/decorator_generator.rb +1 -1
  28. data/lib/generators/test_unit/templates/decorator_test.rb +0 -3
  29. data/spec/draper/collection_decorator_spec.rb +240 -0
  30. data/spec/draper/decoratable_spec.rb +164 -0
  31. data/spec/draper/decorated_association_spec.rb +130 -0
  32. data/spec/draper/decorator_spec.rb +622 -0
  33. data/spec/draper/finders_spec.rb +145 -0
  34. data/spec/draper/helper_proxy_spec.rb +12 -0
  35. data/spec/draper/security_spec.rb +158 -0
  36. data/spec/draper/view_helpers_spec.rb +41 -0
  37. data/spec/dummy/.rspec +2 -0
  38. data/spec/dummy/README.rdoc +261 -0
  39. data/spec/dummy/Rakefile +7 -0
  40. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  41. data/spec/dummy/app/controllers/localized_urls.rb +5 -0
  42. data/spec/dummy/app/controllers/posts_controller.rb +17 -0
  43. data/spec/dummy/app/decorators/post_decorator.rb +29 -0
  44. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  45. data/spec/dummy/app/mailers/application_mailer.rb +3 -0
  46. data/spec/dummy/app/mailers/post_mailer.rb +9 -0
  47. data/spec/dummy/app/models/post.rb +3 -0
  48. data/spec/dummy/app/views/layouts/application.html.erb +11 -0
  49. data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +1 -0
  50. data/spec/dummy/app/views/posts/_post.html.erb +19 -0
  51. data/spec/dummy/app/views/posts/show.html.erb +1 -0
  52. data/spec/dummy/config/application.rb +64 -0
  53. data/spec/dummy/config/boot.rb +10 -0
  54. data/spec/dummy/config/database.yml +25 -0
  55. data/spec/dummy/config/environment.rb +5 -0
  56. data/spec/dummy/config/environments/development.rb +34 -0
  57. data/spec/dummy/config/environments/production.rb +55 -0
  58. data/spec/dummy/config/environments/test.rb +32 -0
  59. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  60. data/spec/dummy/config/initializers/inflections.rb +15 -0
  61. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  62. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  63. data/spec/dummy/config/initializers/session_store.rb +8 -0
  64. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  65. data/spec/dummy/config/locales/en.yml +5 -0
  66. data/spec/dummy/config/routes.rb +7 -0
  67. data/spec/dummy/config.ru +4 -0
  68. data/spec/dummy/db/migrate/20121019115657_create_posts.rb +8 -0
  69. data/spec/dummy/db/schema.rb +21 -0
  70. data/spec/dummy/db/seeds.rb +2 -0
  71. data/spec/dummy/lib/tasks/spec.rake +5 -0
  72. data/spec/dummy/log/.gitkeep +0 -0
  73. data/spec/dummy/public/404.html +26 -0
  74. data/spec/dummy/public/422.html +26 -0
  75. data/spec/dummy/public/500.html +25 -0
  76. data/spec/dummy/public/favicon.ico +0 -0
  77. data/spec/dummy/script/rails +6 -0
  78. data/spec/dummy/spec/decorators/post_decorator_spec.rb +26 -0
  79. data/spec/dummy/spec/mailers/post_mailer_spec.rb +29 -0
  80. data/spec/dummy/spec/spec_helper.rb +9 -0
  81. data/spec/generators/decorator/decorator_generator_spec.rb +25 -6
  82. data/spec/integration/integration_spec.rb +33 -0
  83. data/spec/minitest-rails/spec_type_spec.rb +63 -0
  84. data/{performance → spec/performance}/decorators.rb +2 -4
  85. data/spec/spec_helper.rb +23 -26
  86. data/spec/support/action_controller.rb +12 -0
  87. data/spec/support/active_model.rb +7 -0
  88. data/spec/support/{samples/active_record.rb → active_record.rb} +5 -0
  89. data/spec/support/{samples → decorators}/decorator_with_application_helper.rb +1 -1
  90. data/spec/support/decorators/namespaced_product_decorator.rb +5 -0
  91. data/spec/support/decorators/non_active_model_product_decorator.rb +2 -0
  92. data/spec/support/decorators/product_decorator.rb +23 -0
  93. data/spec/support/decorators/products_decorator.rb +10 -0
  94. data/spec/support/decorators/some_thing_decorator.rb +2 -0
  95. data/spec/support/{samples → decorators}/specific_product_decorator.rb +0 -2
  96. data/spec/support/dummy_app.rb +84 -0
  97. data/spec/support/matchers/have_text.rb +50 -0
  98. data/spec/support/{samples → models}/namespaced_product.rb +1 -3
  99. data/spec/support/{samples → models}/non_active_model_product.rb +1 -0
  100. data/spec/support/{samples → models}/product.rb +17 -2
  101. data/spec/support/models/some_thing.rb +5 -0
  102. data/spec/support/models/uninferrable_decorator_model.rb +3 -0
  103. metadata +211 -102
  104. data/doc/ApplicationDecorator.html +0 -147
  105. data/doc/Draper/AllHelpers.html +0 -256
  106. data/doc/Draper/Base.html +0 -1222
  107. data/doc/Draper/DecoratorGenerator.html +0 -216
  108. data/doc/Draper/LazyHelpers.html +0 -174
  109. data/doc/Draper/ModelSupport.html +0 -164
  110. data/doc/Draper/System.html +0 -179
  111. data/doc/Draper.html +0 -123
  112. data/doc/_index.html +0 -172
  113. data/doc/class_list.html +0 -47
  114. data/doc/css/common.css +0 -1
  115. data/doc/css/full_list.css +0 -53
  116. data/doc/css/style.css +0 -320
  117. data/doc/file_list.html +0 -46
  118. data/doc/frames.html +0 -13
  119. data/doc/index.html +0 -172
  120. data/doc/js/app.js +0 -205
  121. data/doc/js/full_list.js +0 -150
  122. data/doc/js/jquery.js +0 -16
  123. data/doc/method_list.html +0 -174
  124. data/doc/top-level-namespace.html +0 -103
  125. data/lib/draper/active_model_support.rb +0 -27
  126. data/lib/draper/base.rb +0 -312
  127. data/lib/draper/decorated_enumerable_proxy.rb +0 -57
  128. data/lib/draper/model_support.rb +0 -17
  129. data/lib/draper/rspec_integration.rb +0 -2
  130. data/lib/draper/system.rb +0 -10
  131. data/lib/draper/test/view_context.rb +0 -12
  132. data/spec/draper/base_spec.rb +0 -863
  133. data/spec/draper/helper_support_spec.rb +0 -18
  134. data/spec/draper/model_support_spec.rb +0 -48
  135. data/spec/draper/view_context_spec.rb +0 -30
  136. data/spec/support/samples/active_model.rb +0 -9
  137. data/spec/support/samples/application_controller.rb +0 -42
  138. data/spec/support/samples/application_helper.rb +0 -8
  139. data/spec/support/samples/decorator.rb +0 -5
  140. data/spec/support/samples/decorator_with_allows.rb +0 -3
  141. data/spec/support/samples/decorator_with_denies.rb +0 -3
  142. data/spec/support/samples/decorator_with_denies_all.rb +0 -3
  143. data/spec/support/samples/decorator_with_multiple_allows.rb +0 -4
  144. data/spec/support/samples/decorator_with_special_methods.rb +0 -13
  145. data/spec/support/samples/namespaced_product_decorator.rb +0 -7
  146. data/spec/support/samples/product_decorator.rb +0 -7
  147. data/spec/support/samples/sequel_product.rb +0 -13
  148. data/spec/support/samples/some_thing.rb +0 -2
  149. data/spec/support/samples/some_thing_decorator.rb +0 -3
  150. /data/{performance → spec/performance}/active_record.rb +0 -0
  151. /data/{performance/bechmark.rb → spec/performance/benchmark.rb} +0 -0
  152. /data/{performance → spec/performance}/models.rb +0 -0
  153. /data/spec/support/{samples → decorators}/widget_decorator.rb +0 -0
  154. /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
- &mdash; 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> &raquo;
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
@@ -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
@@ -1,2 +0,0 @@
1
- warn 'DEPRECATION WARNING -- use `require "draper/test/rspec_integration"` instead of `require "draper/rspec_integration"`'
2
- require 'draper/test/rspec_integration'