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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -10
- data/LICENSE +20 -0
- data/README.md +20 -862
- data/hanami-view.gemspec +26 -16
- data/lib/hanami-view.rb +3 -1
- data/lib/hanami/view.rb +208 -223
- data/lib/hanami/view/application_configuration.rb +77 -0
- data/lib/hanami/view/application_context.rb +35 -0
- data/lib/hanami/view/application_view.rb +89 -0
- data/lib/hanami/view/context.rb +97 -0
- data/lib/hanami/view/context_helpers/content_helpers.rb +26 -0
- data/lib/hanami/view/decorated_attributes.rb +82 -0
- data/lib/hanami/view/errors.rb +19 -56
- data/lib/hanami/view/exposure.rb +126 -0
- data/lib/hanami/view/exposures.rb +74 -0
- data/lib/hanami/view/part.rb +217 -0
- data/lib/hanami/view/part_builder.rb +140 -0
- data/lib/hanami/view/path.rb +68 -0
- data/lib/hanami/view/render_environment.rb +62 -0
- data/lib/hanami/view/render_environment_missing.rb +44 -0
- data/lib/hanami/view/rendered.rb +55 -0
- data/lib/hanami/view/renderer.rb +79 -0
- data/lib/hanami/view/scope.rb +189 -0
- data/lib/hanami/view/scope_builder.rb +98 -0
- data/lib/hanami/view/standalone_view.rb +396 -0
- data/lib/hanami/view/tilt.rb +78 -0
- data/lib/hanami/view/tilt/erb.rb +26 -0
- data/lib/hanami/view/tilt/erbse.rb +21 -0
- data/lib/hanami/view/tilt/haml.rb +26 -0
- data/lib/hanami/view/version.rb +5 -5
- metadata +114 -70
- data/LICENSE.md +0 -22
- data/lib/hanami/layout.rb +0 -190
- data/lib/hanami/presenter.rb +0 -98
- data/lib/hanami/view/configuration.rb +0 -504
- data/lib/hanami/view/dsl.rb +0 -347
- data/lib/hanami/view/escape.rb +0 -225
- data/lib/hanami/view/inheritable.rb +0 -54
- data/lib/hanami/view/rendering.rb +0 -294
- data/lib/hanami/view/rendering/layout_finder.rb +0 -128
- data/lib/hanami/view/rendering/layout_registry.rb +0 -69
- data/lib/hanami/view/rendering/layout_scope.rb +0 -281
- data/lib/hanami/view/rendering/null_layout.rb +0 -52
- data/lib/hanami/view/rendering/null_local.rb +0 -82
- data/lib/hanami/view/rendering/null_template.rb +0 -83
- data/lib/hanami/view/rendering/null_view.rb +0 -26
- data/lib/hanami/view/rendering/options.rb +0 -24
- data/lib/hanami/view/rendering/partial.rb +0 -31
- data/lib/hanami/view/rendering/partial_file.rb +0 -29
- data/lib/hanami/view/rendering/partial_finder.rb +0 -75
- data/lib/hanami/view/rendering/partial_templates_finder.rb +0 -73
- data/lib/hanami/view/rendering/registry.rb +0 -134
- data/lib/hanami/view/rendering/scope.rb +0 -108
- data/lib/hanami/view/rendering/subscope.rb +0 -56
- data/lib/hanami/view/rendering/template.rb +0 -69
- data/lib/hanami/view/rendering/template_finder.rb +0 -55
- data/lib/hanami/view/rendering/template_name.rb +0 -50
- data/lib/hanami/view/rendering/templates_finder.rb +0 -144
- data/lib/hanami/view/rendering/view_finder.rb +0 -37
- 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
|