hanami-view 1.3.3 → 2.0.0.alpha2

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -10
  3. data/LICENSE +20 -0
  4. data/README.md +20 -862
  5. data/hanami-view.gemspec +26 -16
  6. data/lib/hanami-view.rb +3 -1
  7. data/lib/hanami/view.rb +208 -223
  8. data/lib/hanami/view/application_configuration.rb +77 -0
  9. data/lib/hanami/view/application_context.rb +35 -0
  10. data/lib/hanami/view/application_view.rb +89 -0
  11. data/lib/hanami/view/context.rb +97 -0
  12. data/lib/hanami/view/context_helpers/content_helpers.rb +26 -0
  13. data/lib/hanami/view/decorated_attributes.rb +82 -0
  14. data/lib/hanami/view/errors.rb +19 -56
  15. data/lib/hanami/view/exposure.rb +126 -0
  16. data/lib/hanami/view/exposures.rb +74 -0
  17. data/lib/hanami/view/part.rb +217 -0
  18. data/lib/hanami/view/part_builder.rb +140 -0
  19. data/lib/hanami/view/path.rb +68 -0
  20. data/lib/hanami/view/render_environment.rb +62 -0
  21. data/lib/hanami/view/render_environment_missing.rb +44 -0
  22. data/lib/hanami/view/rendered.rb +55 -0
  23. data/lib/hanami/view/renderer.rb +79 -0
  24. data/lib/hanami/view/scope.rb +189 -0
  25. data/lib/hanami/view/scope_builder.rb +98 -0
  26. data/lib/hanami/view/standalone_view.rb +396 -0
  27. data/lib/hanami/view/tilt.rb +78 -0
  28. data/lib/hanami/view/tilt/erb.rb +26 -0
  29. data/lib/hanami/view/tilt/erbse.rb +21 -0
  30. data/lib/hanami/view/tilt/haml.rb +26 -0
  31. data/lib/hanami/view/version.rb +5 -5
  32. metadata +114 -70
  33. data/LICENSE.md +0 -22
  34. data/lib/hanami/layout.rb +0 -190
  35. data/lib/hanami/presenter.rb +0 -98
  36. data/lib/hanami/view/configuration.rb +0 -504
  37. data/lib/hanami/view/dsl.rb +0 -347
  38. data/lib/hanami/view/escape.rb +0 -225
  39. data/lib/hanami/view/inheritable.rb +0 -54
  40. data/lib/hanami/view/rendering.rb +0 -294
  41. data/lib/hanami/view/rendering/layout_finder.rb +0 -128
  42. data/lib/hanami/view/rendering/layout_registry.rb +0 -69
  43. data/lib/hanami/view/rendering/layout_scope.rb +0 -281
  44. data/lib/hanami/view/rendering/null_layout.rb +0 -52
  45. data/lib/hanami/view/rendering/null_local.rb +0 -82
  46. data/lib/hanami/view/rendering/null_template.rb +0 -83
  47. data/lib/hanami/view/rendering/null_view.rb +0 -26
  48. data/lib/hanami/view/rendering/options.rb +0 -24
  49. data/lib/hanami/view/rendering/partial.rb +0 -31
  50. data/lib/hanami/view/rendering/partial_file.rb +0 -29
  51. data/lib/hanami/view/rendering/partial_finder.rb +0 -75
  52. data/lib/hanami/view/rendering/partial_templates_finder.rb +0 -73
  53. data/lib/hanami/view/rendering/registry.rb +0 -134
  54. data/lib/hanami/view/rendering/scope.rb +0 -108
  55. data/lib/hanami/view/rendering/subscope.rb +0 -56
  56. data/lib/hanami/view/rendering/template.rb +0 -69
  57. data/lib/hanami/view/rendering/template_finder.rb +0 -55
  58. data/lib/hanami/view/rendering/template_name.rb +0 -50
  59. data/lib/hanami/view/rendering/templates_finder.rb +0 -144
  60. data/lib/hanami/view/rendering/view_finder.rb +0 -37
  61. data/lib/hanami/view/template.rb +0 -57
@@ -1,69 +0,0 @@
1
- require 'hanami/view/rendering/null_template'
2
- require 'hanami/view/rendering/templates_finder'
3
-
4
- module Hanami
5
- module View
6
- module Rendering
7
- # Holds the references of all the registered layouts.
8
- # As now the registry is unique at the level of the framework.
9
- #
10
- # @api private
11
- # @since 0.1.0
12
- #
13
- # @see Hanami::Layout::ClassMethods#registry
14
- class LayoutRegistry
15
- # Initialize the registry
16
- #
17
- # @param view [Class] the view
18
- #
19
- # @api private
20
- # @since 0.1.0
21
- def initialize(view)
22
- @registry = {}
23
- @view = view
24
- prepare!
25
- end
26
-
27
- # Returns the layout for the given context.
28
- #
29
- # @param context [Hash] the rendering context
30
- # @option context [Symbol] :format the requested format
31
- #
32
- # @return [Hanami::Layout, Hanami::View::Rendering::NullTemplate]
33
- # the layout associated with the given context or a `NullTemplate` if
34
- # it can't be found.
35
- #
36
- # @raise [Hanami::View::MissingFormatError] if the given context doesn't
37
- # have the :format key
38
- #
39
- # @api private
40
- # @since 0.1.0
41
- def resolve(context)
42
- @registry.fetch(format(context)) { NullTemplate.new }
43
- end
44
-
45
- protected
46
- # @api private
47
- # @since 0.1.0
48
- def prepare!
49
- templates.each do |template|
50
- @registry.merge! template.format => template
51
- end
52
- @registry.any? or raise MissingTemplateLayoutError.new(@view)
53
- end
54
-
55
- # @api private
56
- # @since 0.1.0
57
- def templates
58
- TemplatesFinder.new(@view).find
59
- end
60
-
61
- # @api private
62
- # @since 0.1.0
63
- def format(context)
64
- context.fetch(:format) { raise MissingFormatError }
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,281 +0,0 @@
1
- require 'hanami/view/rendering/null_local'
2
- require 'hanami/view/rendering/options'
3
- require 'hanami/utils/escape'
4
- require 'hanami/utils/basic_object'
5
-
6
- module Hanami
7
- module View
8
- module Rendering
9
- # List of render types that exactly one of must be included when calling `#render`.
10
- # For example, when calling `<%= render something: 'my_thing', locals: {} %>`,
11
- # 'something' must be one of the values listed here.
12
- #
13
- # @since 1.1.0
14
- # @api private
15
- KNOWN_RENDER_TYPES = [:partial, :template].freeze
16
-
17
- # Scope for layout rendering
18
- #
19
- # @since 0.1.0
20
- class LayoutScope < Utils::BasicObject
21
- # Initialize the scope
22
- #
23
- # @param layout [Hanami::Layout] the layout to render
24
- # @param scope [Hanami::View::Rendering::Scope] the scope of the current
25
- # view
26
- #
27
- # @api private
28
- # @since 0.1.0
29
- def initialize(layout, scope)
30
- @layout = layout
31
- @scope = scope
32
- @view = nil
33
- @locals = nil
34
- end
35
-
36
- # Render a partial or a template within a layout template.
37
- #
38
- # @param options [Hash]
39
- # @option options [String] :partial the partial template to render
40
- # @option options [String] :template the template to render
41
- #
42
- # @return [String] the output of the rendering process
43
- #
44
- # @raise [Hanami::Error::UnknownRenderTypeError] if the given type to
45
- # be rendered is unknown
46
- #
47
- # @since 0.1.0
48
- #
49
- # @example Rendering partial
50
- # # Given a partial under:
51
- # # templates/shared/_sidebar.html.erb
52
- # #
53
- # # In the layout template:
54
- # # templates/application.html.erb
55
- # #
56
- # # Use like this:
57
- # <%= render partial: 'shared/sidebar' %>
58
- #
59
- # @example Rendering template
60
- # # Given a template under:
61
- # # templates/articles/index.html.erb
62
- # #
63
- # # In the layout template:
64
- # # templates/application.html.erb
65
- # #
66
- # # Use like this:
67
- # <%= render template: 'articles/index' %>
68
- #
69
- # @example Rendering partial, using optional :locals
70
- # # Given a partial under:
71
- # # templates/shared/_sidebar.html.erb
72
- # #
73
- # # In the layout template:
74
- # # templates/application.html.erb
75
- # #
76
- # # Use like this:
77
- # <%= render partial: 'shared/sidebar', locals: { user: current_user } %>
78
- #
79
- # #
80
- # # `user` will be available in the scope of the sidebar rendering
81
- #
82
- # @example Rendering partial, passing a block
83
- # # Given a partial under:
84
- # # templates/shared/_sidebar.html.erb
85
- # #
86
- # # In the layout template:
87
- # # templates/application.html.erb
88
- # #
89
- # # Use like this:
90
- # <%= render(partial: 'shared/sidebar') { ... } %>
91
- #
92
- # #
93
- # # Then if you call `yield` inside the partial, it will call the
94
- # # passed block.
95
- def render(options, &block)
96
- renderer(options).render(&block)
97
- end
98
-
99
- # Returns the requested format.
100
- #
101
- # @return [Symbol] the requested format (eg. :html, :json, :xml, etc..)
102
- #
103
- # @since 0.1.0
104
- def format
105
- @scope.format
106
- end
107
-
108
- # The current view.
109
- #
110
- # @return [Hanami::View] the current view
111
- #
112
- # @since 0.1.0
113
- def view
114
- @view || @scope.view
115
- end
116
-
117
- # The current locals.
118
- #
119
- # @return [Hash] the current locals
120
- #
121
- # @since 0.1.0
122
- def locals
123
- (@locals || @scope.locals).dup
124
- end
125
-
126
- # It tries to invoke a method for the view or a local for the given key.
127
- # If the lookup fails, it returns a null object.
128
- #
129
- # @return [Object,Hanami::View::Rendering::NullLocal] the returning value
130
- #
131
- # @since 0.7.0
132
- #
133
- # @example Safe method navigation
134
- # <% if local(:plan).overdue? %>
135
- # <h2>Your plan is overdue.</h2>
136
- # <% end %>
137
- #
138
- # @example Optional Contents
139
- # # Given the following layout template
140
- #
141
- # <!doctype HTML>
142
- # <html>
143
- # <!-- ... -->
144
- # <body>
145
- # <!-- ... -->
146
- # <%= local :footer %>
147
- # </body>
148
- # </html>
149
- #
150
- # # Case 1:
151
- # # Products::Index doesn't respond to #footer, local will return nil
152
- # #
153
- # # Case 2:
154
- # # Products::Show responds to #footer, local will send back
155
- # # #footer returning value
156
- #
157
- # module Products
158
- # class Index
159
- # include Hanami::View
160
- # end
161
- #
162
- # class Show
163
- # include Hanami::View
164
- #
165
- # def footer
166
- # "contents for footer"
167
- # end
168
- # end
169
- # end
170
- def local(key)
171
- if respond_to?(key)
172
- __send__(key)
173
- else
174
- locals.fetch(key) { NullLocal.new(key) }
175
- end
176
- end
177
-
178
- # Implements "respond to" logic
179
- #
180
- # @return [TrueClass,FalseClass]
181
- #
182
- # @since 0.3.0
183
- # @api private
184
- #
185
- # @see http://ruby-doc.org/core/Object.html#method-i-respond_to-3F
186
- def respond_to?(m, include_all = false)
187
- respond_to_missing?(m, include_all)
188
- end
189
-
190
- # Implements "respond to" logic
191
- #
192
- # @return [TrueClass,FalseClass]
193
- #
194
- # @since 0.3.0
195
- # @api private
196
- #
197
- # @see http://ruby-doc.org/core/Object.html#method-i-respond_to_missing-3F
198
- def respond_to_missing?(m, include_all)
199
- @layout.respond_to?(m, include_all) ||
200
- @scope.respond_to?(m, include_all)
201
- end
202
-
203
- protected
204
-
205
- # Forward all the missing methods to the view scope or to the layout.
206
- #
207
- # @api private
208
- # @since 0.1.0
209
- #
210
- # @see Hanami::View::Rendering::Scope
211
- # @see Hanami::Layout
212
- #
213
- # @example
214
- # # In the layout template:
215
- # # templates/application.html.erb
216
- # #
217
- # # Use like this:
218
- # <title><%= article.title %></title>
219
- #
220
- # # `article` will be looked up in the view scope first.
221
- # # If not found, it will be searched within the layout.
222
- def method_missing(m, *args, &blk)
223
- # FIXME: this isn't compatible with Hanami 2.0, as it extends a view
224
- # that we want to be frozen in the future
225
- #
226
- # See https://github.com/hanami/view/issues/130#issuecomment-319326236
227
- if @scope.respond_to?(m, true) && @scope.locals.has_key?(m) && layout.respond_to?(m, true)
228
- layout.__send__(m, *args, &blk)
229
- elsif @scope.respond_to?(m, true)
230
- @scope.__send__(m, *args, &blk)
231
- elsif layout.respond_to?(m, true)
232
- layout.__send__(m, *args, &blk)
233
- else
234
- ::Hanami::View::Escape.html(super)
235
- end
236
- end
237
-
238
- # @api private
239
- def renderer(options)
240
- if options[:partial]
241
- Rendering::Partial
242
- elsif options[:template]
243
- Rendering::Template
244
- else
245
- ::Kernel.raise UnknownRenderTypeError.new(KNOWN_RENDER_TYPES, options)
246
- end.new(view, _options(options))
247
- end
248
-
249
- private
250
-
251
- # Returns an inspect String
252
- #
253
- # @return [String] inspect String (contains classname, objectid in hex, available ivars)
254
- #
255
- # @since 1.3.2
256
- # @api private
257
- def __inspect
258
- result = ""
259
- result += %( @layout="#{@layout.inspect}") if @layout
260
- result += %( @scope="#{@scope.inspect}") if @scope
261
- result
262
- end
263
-
264
- # @api private
265
- def _options(options)
266
- current_locals = locals.reject do |key, _|
267
- @scope.respond_to?(key, true) &&
268
- (layout.respond_to?(key, true) || @scope.view.respond_to?(:name, true))
269
- end
270
- Options.build(options, current_locals, format)
271
- end
272
-
273
- # @since 0.4.2
274
- # @api private
275
- def layout
276
- @layout || @layout.class.layout.new(@scope, "")
277
- end
278
- end
279
- end
280
- end
281
- end
@@ -1,52 +0,0 @@
1
- module Hanami
2
- module View
3
- module Rendering
4
- # Null Object pattern for Layout.
5
- # It's used when a view doesn't require a layout.
6
- #
7
- # @api private
8
- # @since 0.1.0
9
- #
10
- # @example
11
- # require 'hanami/view'
12
- #
13
- # module Articles
14
- # class Show
15
- # include Hanami::View
16
- # layout false
17
- # end
18
- # end
19
- #
20
- # # In this scenario we will use a `NullLayout`.
21
- class NullLayout
22
-
23
- # Initialize a layout
24
- #
25
- # @param scope [Hanami::View::Rendering::Scope] view rendering scope
26
- # @param rendered [String] the output of the view rendering process
27
- #
28
- # @api private
29
- # @since 0.1.0
30
- #
31
- # @see Hanami::Layout#initialize
32
- # @see Hanami::View::Rendering#render
33
- def initialize(scope, rendered)
34
- @rendered = rendered
35
- end
36
-
37
- # Render the layout
38
- #
39
- # @return [String] the output of the rendering process
40
- #
41
- # @api private
42
- # @since 0.1.0
43
- #
44
- # @see Hanami::Layout#render
45
- # @see Hanami::View::Rendering#render
46
- def render
47
- @rendered
48
- end
49
- end
50
- end
51
- end
52
- end
@@ -1,82 +0,0 @@
1
- require 'hanami/utils/basic_object'
2
-
3
- module Hanami
4
- module View
5
- module Rendering
6
- # Null local
7
- #
8
- # @since 0.7.0
9
- #
10
- # @see Hanami::View::Rendering#local
11
- class NullLocal < Utils::BasicObject
12
- # @since 0.7.0
13
- # @api private
14
- TO_STR = "".freeze
15
-
16
- # @since 0.7.0
17
- # @api private
18
- def initialize(local)
19
- @local = local
20
- end
21
-
22
- # @since 0.7.0
23
- # @api private
24
- def all?
25
- false
26
- end
27
-
28
- # @since 0.7.0
29
- # @api private
30
- def any?
31
- false
32
- end
33
-
34
- # @since 0.7.0
35
- # @api private
36
- def empty?
37
- true
38
- end
39
-
40
- # @since 0.7.0
41
- # @api private
42
- def nil?
43
- true
44
- end
45
-
46
- # @since 0.7.0
47
- # @api private
48
- def to_str
49
- TO_STR
50
- end
51
-
52
- # @since 0.8.0
53
- # @api private
54
- alias to_s to_str
55
-
56
- # @since 0.7.0
57
- # @api private
58
- def method_missing(m, *)
59
- if m.match(/\?\z/)
60
- false
61
- else
62
- self.class.new("#{ @local }.#{ m }")
63
- end
64
- end
65
-
66
- private
67
-
68
- # @since 0.7.0
69
- # @api private
70
- def respond_to_missing?(method_name, include_all)
71
- true
72
- end
73
-
74
- # @since 0.7.0
75
- # @api private
76
- def __inspect
77
- " :#{ @local }"
78
- end
79
- end
80
- end
81
- end
82
- end