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,54 +0,0 @@
1
- module Hanami
2
- module View
3
- # Inheriting mechanisms
4
- #
5
- # @since 0.1.0
6
- module Inheritable
7
- # Register a view subclass
8
- #
9
- # @api private
10
- # @since 0.1.0
11
- #
12
- # @example
13
- # require 'hanami/view'
14
- #
15
- # class IndexView
16
- # include Hanami::View
17
- # end
18
- #
19
- # class JsonIndexView < IndexView
20
- # end
21
- def inherited(base)
22
- subclasses.add base
23
- end
24
-
25
- # Set of registered subclasses
26
- #
27
- # @api private
28
- # @since 0.1.0
29
- def subclasses
30
- @subclasses ||= Set.new
31
- end
32
-
33
- protected
34
- # Loading mechanism hook.
35
- #
36
- # @api private
37
- # @since 0.1.0
38
- #
39
- # @see Hanami::View.load!
40
- def load!
41
- subclasses.freeze
42
- views.freeze
43
- end
44
-
45
- # Registered views
46
- #
47
- # @api private
48
- # @since 0.1.0
49
- def views
50
- @views ||= [ self ] + subclasses.to_a
51
- end
52
- end
53
- end
54
- end
@@ -1,294 +0,0 @@
1
- require 'hanami/view/rendering/registry'
2
- require 'hanami/view/rendering/scope'
3
- require 'hanami/view/rendering/subscope'
4
- require 'hanami/view/rendering/null_local'
5
-
6
- module Hanami
7
- module View
8
- # Rendering methods
9
- #
10
- # @since 0.1.0
11
- #
12
- # @see Hanami::View::Rendering::InstanceMethods
13
- module Rendering
14
- # @since 0.1.0
15
- # @api private
16
- def self.extended(base)
17
- base.class_eval do
18
- include InstanceMethods
19
- end
20
- end
21
-
22
- module InstanceMethods
23
- # Initialize a view
24
- #
25
- # @param template [Hanami::View::Template] the template to render
26
- # @param locals [Hash] a set of objects available during the rendering
27
- # process.
28
- #
29
- # @since 0.1.0
30
- #
31
- # @see Hanami::View::Template
32
- #
33
- # @example
34
- # require 'hanami/view'
35
- #
36
- # class IndexView
37
- # include Hanami::View
38
- # end
39
- #
40
- # template = Hanami::View::Template.new('index.html.erb')
41
- # view = IndexView.new(template, {article: article})
42
- def initialize(template, **locals)
43
- @template = template
44
- @locals = locals
45
- @scope = Scope.new(self, @locals)
46
- end
47
-
48
- # Render the template by bounding the local scope.
49
- # If it uses a layout, it renders the template first and then the
50
- # control passes to the layout.
51
- #
52
- # Override this method for custom rendering policies.
53
- # For instance, when a serializer is used and there isn't the need of
54
- # a template.
55
- #
56
- # @return [String] the output of the rendering process
57
- #
58
- # @raise [Hanami::View::MissingTemplateError] if the template is nil
59
- #
60
- # @since 0.1.0
61
- #
62
- # @see Hanami::View::Layout
63
- #
64
- # @example with template
65
- # require 'hanami/view'
66
- #
67
- # class IndexView
68
- # include Hanami::View
69
- # end
70
- #
71
- # template = Hanami::View::Template.new('index.html.erb')
72
- # view = IndexView.new(template, {article: article})
73
- #
74
- # view.render # => <h1>Introducing Hanami::view</h1> ...
75
- #
76
- # @example with template and layout
77
- # require 'hanami/view'
78
- #
79
- # class ApplicationLayout
80
- # include Hanami::View::Layout
81
- # end
82
- #
83
- # class IndexView
84
- # include Hanami::View
85
- # layout :application
86
- # end
87
- #
88
- # template = Hanami::View::Template.new('index.html.erb')
89
- # view = IndexView.new(template, {article: article})
90
- #
91
- # view.render # => <html> ... <h1>Introducing Hanami::view</h1> ...
92
- #
93
- # @example with custom rendering
94
- # require 'hanami/view'
95
- #
96
- # class IndexView
97
- # include Hanami::View
98
- #
99
- # def render
100
- # ArticleSerializer.new(article).render
101
- # end
102
- # end
103
- #
104
- # view = IndexView.new(nil, {article: article})
105
- #
106
- # view.render # => {title: ...}
107
- def render
108
- layout.render
109
- end
110
-
111
- # It tries to invoke a method for the view or a local for the given key.
112
- # If the lookup fails, it returns a null object.
113
- #
114
- # @return [Object,Hanami::View::Rendering::NullLocal] the returning value
115
- #
116
- # @since 0.7.0
117
- #
118
- # @example
119
- # <% if local(:plan).overdue? %>
120
- # <h2>Your plan is overdue.</h2>
121
- # <% end %>
122
- def local(key)
123
- if respond_to?(key)
124
- __send__(key)
125
- else
126
- locals.fetch(key) { NullLocal.new(key) }
127
- end
128
- end
129
-
130
- protected
131
- # The output of the template rendering process.
132
- #
133
- # @return [String] the rendering output
134
- #
135
- # @raise [Hanami::View::MissingTemplateError] if the template is nil
136
- #
137
- # @api private
138
- # @since 0.1.0
139
- def rendered
140
- template.render @scope
141
- end
142
-
143
- # The layout.
144
- #
145
- # @return [Class, Hanami::View::Rendering::NullLayout]
146
- #
147
- # @see Hanami::View::Layout
148
- # @see Hanami::View.layout
149
- # @see Hanami::View::Dsl#layout
150
- #
151
- # @api private
152
- # @since 0.1.0
153
- def layout
154
- @layout ||= self.class.layout.new(@scope, rendered)
155
- end
156
-
157
- # The template.
158
- #
159
- # @return [Hanami::View::Template] the template
160
- #
161
- # @raise [Hanami::View::MissingTemplateError] if the template is nil
162
- #
163
- # @api private
164
- # @since 0.1.0
165
- def template
166
- @template or raise MissingTemplateError.new(self.class.template, @scope.format)
167
- end
168
-
169
- # A set of objects available during the rendering process.
170
- #
171
- # @return [Hash]
172
- #
173
- # @see Hanami::View#initialize
174
- #
175
- # @api private
176
- # @since 0.1.0
177
- def locals
178
- @locals
179
- end
180
-
181
- # Delegates missing methods to the scope.
182
- #
183
- # @see Hanami::View::Rendering::Scope
184
- #
185
- # @api private
186
- # @since 0.1.0
187
- #
188
- # @example
189
- # require 'hanami/view'
190
- #
191
- # class IndexView
192
- # include Hanami::View
193
- # end
194
- #
195
- # template = Hanami::View::Template.new('index.html.erb')
196
- # view = IndexView.new(template, {article: article})
197
- #
198
- # view.article # => #<Article:0x007fb0bbd3b6e8>
199
- def method_missing(m)
200
- @scope.__send__ m
201
- end
202
- end
203
-
204
- # Render the given context and locals with the appropriate template.
205
- # If there are registered subclasses, it choose the right class, according
206
- # to the requested format.
207
- #
208
- # @param context [Hash] the context for the rendering process
209
- # @option context [Symbol] :format the requested format
210
- #
211
- # @return [String] the output of the rendering process
212
- #
213
- # @raise [Hanami::View::MissingTemplateError] if it can't find a template
214
- # for the given context
215
- #
216
- # @raise [Hanami::View::MissingFormatError] if the given context doesn't
217
- # have the :format key
218
- #
219
- # @since 0.1.0
220
- #
221
- # @see Hanami::View#initialize
222
- # @see Hanami::View#render
223
- #
224
- # @example
225
- # require 'hanami/view'
226
- #
227
- # article = OpenStruct.new(title: 'Hello')
228
- #
229
- # module Articles
230
- # class Show
231
- # include Hanami::View
232
- #
233
- # def title
234
- # @title ||= article.title.upcase
235
- # end
236
- # end
237
- #
238
- # class JsonShow < Show
239
- # format :json
240
- #
241
- # def title
242
- # super.downcase
243
- # end
244
- # end
245
- # end
246
- #
247
- # Hanami::View.root = '/path/to/templates'
248
- # Hanami::View.load!
249
- #
250
- # Articles::Show.render(format: :html, article: article)
251
- # # => renders `articles/show.html.erb`
252
- #
253
- # Articles::Show.render(format: :json, article: article)
254
- # # => renders `articles/show.json.erb`
255
- #
256
- # Articles::Show.render(format: :xml, article: article)
257
- # # => raises Hanami::View::MissingTemplateError
258
- def render(context)
259
- registry.resolve(context).render
260
- end
261
-
262
- protected
263
-
264
- # Loading mechanism hook.
265
- #
266
- # @api private
267
- # @since 0.1.0
268
- #
269
- # @see Hanami::View.load!
270
- def load!
271
- super
272
- load_registry!
273
- end
274
-
275
- private
276
-
277
- # The registry that holds all the registered subclasses.
278
- #
279
- # @api private
280
- # @since 0.1.0
281
- #
282
- # @see Hanami::View::Rendering::Registry
283
- def registry
284
- @registry ||= Registry.new(self)
285
- end
286
-
287
- # @api private
288
- def load_registry!
289
- @registry = nil
290
- registry.freeze
291
- end
292
- end
293
- end
294
- end
@@ -1,128 +0,0 @@
1
- require 'hanami/utils/string'
2
- require 'hanami/utils/class'
3
- require 'hanami/view/rendering/null_layout'
4
-
5
- module Hanami
6
- module View
7
- module Rendering
8
- # Defines the logic to find a layout
9
- #
10
- # @api private
11
- # @since 0.1.0
12
- #
13
- # @see Hanami::Layout
14
- class LayoutFinder
15
- # Layout class name suffix
16
- #
17
- # @api private
18
- # @since 0.1.0
19
- SUFFIX = 'Layout'.freeze
20
-
21
- # Find a layout from the given name.
22
- #
23
- # @param layout [Symbol,String,NilClass] layout name or nil if you want
24
- # to fallback to the framework defaults (see `Hanami::View.layout`).
25
- #
26
- # @param namespace [Class,Module] a Ruby namespace where to lookup
27
- #
28
- # @return [Hanami::Layout] the layout for the given name or
29
- # `Hanami::View.layout`
30
- #
31
- # @api private
32
- # @since 0.1.0
33
- #
34
- # @example With given name
35
- # require 'hanami/view'
36
- #
37
- # Hanami::View::Rendering::LayoutFinder.find(:article) # =>
38
- # ArticleLayout
39
- #
40
- # @example With a class
41
- # require 'hanami/view'
42
- #
43
- # Hanami::View::Rendering::LayoutFinder.find(ArticleLayout) # =>
44
- # ArticleLayout
45
- #
46
- # @example With namespace
47
- # require 'hanami/view'
48
- #
49
- # Hanami::View::Rendering::LayoutFinder.find(:application, CardDeck) # =>
50
- # CardDeck::ApplicationLayout
51
- #
52
- # @example With nil
53
- # require 'hanami/view'
54
- #
55
- # Hanami::View::Rendering::LayoutFinder.find(nil) # =>
56
- # Hanami::View::Rendering::NullLayout
57
- #
58
- # @example With unknown layout
59
- # require 'hanami/view'
60
- #
61
- # Hanami::View::Rendering::LayoutFinder.find(:unknown) # =>
62
- # Hanami::View::Rendering::NullLayout
63
- #
64
- def self.find(layout, namespace = Object)
65
- case layout
66
- when Symbol, String
67
- # TODO Move this low level logic into a Hanami::Utils solution
68
- class_name = "#{ Utils::String.classify(layout) }#{ SUFFIX }"
69
- namespace = Utils::Class.load!(namespace)
70
- namespace.const_get(class_name)
71
- when Class
72
- layout
73
- end || NullLayout
74
- end
75
-
76
- # Initialize the finder
77
- #
78
- # @param view [Class, #layout]
79
- #
80
- # @api private
81
- # @since 0.1.0
82
- def initialize(view)
83
- @view = view
84
- end
85
-
86
- # Find the layout for the view
87
- #
88
- # @return [Hanami::Layout] the layout associated to the view
89
- #
90
- # @see Hanami::View::Rendering::LayoutFinder.find
91
- # @see Hanami::View::Rendering::LayoutFinder#initialize
92
- #
93
- # @api private
94
- # @since 0.1.0
95
- #
96
- # @example With layout
97
- # require 'hanami/view'
98
- #
99
- # module Articles
100
- # class Show
101
- # include Hanami::View
102
- # layout :article
103
- # end
104
- # end
105
- #
106
- # Hanami::View::Rendering::LayoutFinder.new(Articles::Show) # =>
107
- # ArticleLayout
108
- #
109
- # @example Without layout
110
- # require 'hanami/view'
111
- #
112
- # module Dashboard
113
- # class Index
114
- # include Hanami::View
115
- # end
116
- # end
117
- #
118
- # Hanami::View.layout # => :application
119
- #
120
- # Hanami::View::Rendering::LayoutFinder.new(Dashboard::Index) # =>
121
- # ApplicationLayout
122
- def find
123
- self.class.find(@view.layout)
124
- end
125
- end
126
- end
127
- end
128
- end