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