pakyow-presenter 0.11.3 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +5 -5
  2. data/{pakyow-presenter/CHANGELOG.md → CHANGELOG.md} +0 -5
  3. data/LICENSE +4 -0
  4. data/{pakyow-presenter/README.md → README.md} +1 -2
  5. data/lib/pakyow/generators/presenter/presenter_generator.rb +28 -0
  6. data/lib/pakyow/generators/presenter/templates/presenter.rb.tt +2 -0
  7. data/lib/pakyow/plugin/helpers/rendering.rb +19 -0
  8. data/lib/pakyow/presenter/actions/auto_render.rb +15 -0
  9. data/lib/pakyow/presenter/attributes/attribute.rb +22 -0
  10. data/lib/pakyow/presenter/attributes/boolean.rb +24 -0
  11. data/lib/pakyow/presenter/attributes/hash.rb +89 -0
  12. data/lib/pakyow/presenter/attributes/set.rb +61 -0
  13. data/lib/pakyow/presenter/attributes/string.rb +38 -0
  14. data/lib/pakyow/presenter/attributes.rb +126 -0
  15. data/lib/pakyow/presenter/behavior/config.rb +29 -0
  16. data/lib/pakyow/presenter/behavior/error_rendering.rb +124 -0
  17. data/lib/pakyow/presenter/behavior/exposures.rb +29 -0
  18. data/lib/pakyow/presenter/behavior/implicit_rendering.rb +21 -0
  19. data/lib/pakyow/presenter/behavior/initializing.rb +37 -0
  20. data/lib/pakyow/presenter/behavior/modes.rb +117 -0
  21. data/lib/pakyow/presenter/behavior/versions.rb +71 -0
  22. data/lib/pakyow/presenter/behavior/watching.rb +21 -0
  23. data/lib/pakyow/presenter/binder.rb +115 -0
  24. data/lib/pakyow/presenter/binding_parts.rb +64 -0
  25. data/lib/pakyow/presenter/component.rb +74 -0
  26. data/lib/pakyow/presenter/composers/component.rb +78 -0
  27. data/lib/pakyow/presenter/composers/view.rb +73 -0
  28. data/lib/pakyow/presenter/errors.rb +63 -0
  29. data/lib/pakyow/presenter/framework.rb +203 -0
  30. data/lib/pakyow/presenter/front_matter_parser.rb +42 -0
  31. data/lib/pakyow/presenter/helpers/rendering.rb +18 -0
  32. data/lib/pakyow/presenter/presentable.rb +28 -0
  33. data/lib/pakyow/presenter/presentable_error.rb +19 -0
  34. data/lib/pakyow/presenter/presenter.rb +766 -0
  35. data/lib/pakyow/presenter/presenters/endpoint.rb +158 -0
  36. data/lib/pakyow/presenter/presenters/form.rb +522 -0
  37. data/lib/pakyow/presenter/processor.rb +61 -0
  38. data/lib/pakyow/presenter/renderable.rb +28 -0
  39. data/lib/pakyow/presenter/renderer.rb +269 -0
  40. data/lib/pakyow/presenter/rendering/actions/cleanup_prototype_nodes.rb +21 -0
  41. data/lib/pakyow/presenter/rendering/actions/cleanup_unbound_bindings.rb +35 -0
  42. data/lib/pakyow/presenter/rendering/actions/create_template_nodes.rb +27 -0
  43. data/lib/pakyow/presenter/rendering/actions/insert_prototype_bar.rb +101 -0
  44. data/lib/pakyow/presenter/rendering/actions/install_authenticity.rb +42 -0
  45. data/lib/pakyow/presenter/rendering/actions/place_in_mode.rb +56 -0
  46. data/lib/pakyow/presenter/rendering/actions/render_components.rb +279 -0
  47. data/lib/pakyow/presenter/rendering/actions/set_page_title.rb +35 -0
  48. data/lib/pakyow/presenter/rendering/actions/setup_endpoints.rb +62 -0
  49. data/lib/pakyow/presenter/rendering/actions/setup_forms.rb +174 -0
  50. data/lib/pakyow/presenter/significant_nodes.rb +309 -0
  51. data/lib/pakyow/presenter/templates.rb +229 -0
  52. data/lib/pakyow/presenter/versioned_view.rb +209 -0
  53. data/lib/pakyow/presenter/view.rb +586 -0
  54. data/lib/pakyow/presenter/views/form.rb +58 -0
  55. data/lib/pakyow/presenter/views/layout.rb +32 -0
  56. data/lib/pakyow/presenter/views/page.rb +72 -0
  57. data/lib/pakyow/presenter/views/partial.rb +28 -0
  58. data/lib/pakyow/presenter.rb +33 -0
  59. data/lib/pakyow/views/errors/layouts/development_error.html +102 -0
  60. data/lib/pakyow/views/errors/layouts/production_error.html +27 -0
  61. data/lib/pakyow/views/errors/pages/404.html +12 -0
  62. data/lib/pakyow/views/errors/pages/500.html +12 -0
  63. data/lib/pakyow/views/errors/pages/development/500.html +39 -0
  64. data/lib/string_doc/attributes.rb +109 -0
  65. data/lib/string_doc/meta_attributes.rb +48 -0
  66. data/lib/string_doc/meta_node.rb +328 -0
  67. data/lib/string_doc/node.rb +377 -0
  68. data/lib/string_doc.rb +642 -0
  69. metadata +95 -75
  70. data/pakyow-presenter/LICENSE +0 -20
  71. data/pakyow-presenter/lib/pakyow/presenter/attributes.rb +0 -228
  72. data/pakyow-presenter/lib/pakyow/presenter/base.rb +0 -38
  73. data/pakyow-presenter/lib/pakyow/presenter/binder.rb +0 -116
  74. data/pakyow-presenter/lib/pakyow/presenter/binder_set.rb +0 -94
  75. data/pakyow-presenter/lib/pakyow/presenter/binding_eval.rb +0 -37
  76. data/pakyow-presenter/lib/pakyow/presenter/config/presenter.rb +0 -42
  77. data/pakyow-presenter/lib/pakyow/presenter/container.rb +0 -6
  78. data/pakyow-presenter/lib/pakyow/presenter/doc_helpers.rb +0 -17
  79. data/pakyow-presenter/lib/pakyow/presenter/exceptions.rb +0 -11
  80. data/pakyow-presenter/lib/pakyow/presenter/ext/app.rb +0 -33
  81. data/pakyow-presenter/lib/pakyow/presenter/ext/call_context.rb +0 -28
  82. data/pakyow-presenter/lib/pakyow/presenter/helpers.rb +0 -46
  83. data/pakyow-presenter/lib/pakyow/presenter/page.rb +0 -110
  84. data/pakyow-presenter/lib/pakyow/presenter/partial.rb +0 -6
  85. data/pakyow-presenter/lib/pakyow/presenter/presenter.rb +0 -232
  86. data/pakyow-presenter/lib/pakyow/presenter/string_doc.rb +0 -380
  87. data/pakyow-presenter/lib/pakyow/presenter/string_doc_parser.rb +0 -144
  88. data/pakyow-presenter/lib/pakyow/presenter/string_doc_renderer.rb +0 -18
  89. data/pakyow-presenter/lib/pakyow/presenter/template.rb +0 -51
  90. data/pakyow-presenter/lib/pakyow/presenter/view.rb +0 -541
  91. data/pakyow-presenter/lib/pakyow/presenter/view_collection.rb +0 -330
  92. data/pakyow-presenter/lib/pakyow/presenter/view_composer.rb +0 -237
  93. data/pakyow-presenter/lib/pakyow/presenter/view_context.rb +0 -111
  94. data/pakyow-presenter/lib/pakyow/presenter/view_store.rb +0 -262
  95. data/pakyow-presenter/lib/pakyow/presenter/view_store_loader.rb +0 -43
  96. data/pakyow-presenter/lib/pakyow/presenter/view_version.rb +0 -113
  97. data/pakyow-presenter/lib/pakyow/presenter.rb +0 -8
  98. data/pakyow-presenter/lib/pakyow/views/errors/404.erb +0 -26
  99. data/pakyow-presenter/lib/pakyow/views/errors/500.erb +0 -23
  100. data/pakyow-presenter/lib/pakyow-presenter.rb +0 -1
@@ -0,0 +1,309 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "string_doc"
4
+
5
+ require "pakyow/presenter/presenters/endpoint"
6
+ require "pakyow/presenter/presenters/form"
7
+
8
+ module Pakyow
9
+ module Presenter
10
+ # @api private
11
+ FORM_TAG = "form".freeze
12
+ # @api private
13
+ OPTION_TAG = "option".freeze
14
+ # @api private
15
+ OPTGROUP_TAG = "optgroup".freeze
16
+ # @api private
17
+ INPUT_TAG = "input".freeze
18
+ # @api private
19
+ LABEL_TAG = "label".freeze
20
+ # @api private
21
+ TITLE_TAG = "title".freeze
22
+ # @api private
23
+ BODY_TAG = "body".freeze
24
+ # @api private
25
+ HEAD_TAG = "head".freeze
26
+ # @api private
27
+ META_TAG = "meta".freeze
28
+ # @api private
29
+ HTML_TAG = "html".freeze
30
+ # @api private
31
+ SCRIPT_TAG = "script".freeze
32
+ # @api private
33
+ SELECT_TAG = "select".freeze
34
+ # @api private
35
+ TEXTAREA_TAG = "textarea".freeze
36
+
37
+ # @api private
38
+ class SignificantNode
39
+ def self.within_binding?(node)
40
+ if BindingNode.significant?(node)
41
+ true
42
+ elsif !node.is_a?(Oga::XML::Document)
43
+ within_binding?(node.parent)
44
+ else
45
+ false
46
+ end
47
+ end
48
+
49
+ def self.binding_within?(node)
50
+ node.children.any? { |child|
51
+ BindingNode.significant?(child) || binding_within?(child)
52
+ }
53
+ end
54
+
55
+ def self.within_form?(node)
56
+ if FormNode.significant?(node)
57
+ true
58
+ elsif !node.is_a?(Oga::XML::Document)
59
+ within_form?(node.parent)
60
+ else
61
+ false
62
+ end
63
+ end
64
+ end
65
+
66
+ # @api private
67
+ class PrototypeNode < SignificantNode
68
+ StringDoc.significant :prototype, self
69
+
70
+ def self.significant?(node)
71
+ node.is_a?(Oga::XML::Element) && node.attribute(:prototype)
72
+ end
73
+ end
74
+
75
+ # @api private
76
+ class EndpointNode < SignificantNode
77
+ StringDoc.significant :endpoint, self
78
+
79
+ def self.significant?(node)
80
+ node.is_a?(Oga::XML::Element) && node.attribute(:endpoint)
81
+ end
82
+
83
+ def self.decorate(node)
84
+ node.set_label(:presenter_type, Presenters::Endpoint)
85
+ end
86
+ end
87
+
88
+ # @api private
89
+ class EndpointActionNode < SignificantNode
90
+ StringDoc.significant :endpoint_action, self
91
+
92
+ def self.significant?(node)
93
+ node.is_a?(Oga::XML::Element) && node.attribute(:"endpoint-action")
94
+ end
95
+ end
96
+
97
+ # @api private
98
+ class ContainerNode < SignificantNode
99
+ StringDoc.significant :container, self
100
+
101
+ CONTAINER_REGEX = /@container\s*([a-zA-Z0-9\-_]*)/.freeze
102
+
103
+ def self.significant?(node)
104
+ node.is_a?(Oga::XML::Comment) && node.text.strip.match(CONTAINER_REGEX)
105
+ end
106
+ end
107
+
108
+ # @api private
109
+ class PartialNode < SignificantNode
110
+ StringDoc.significant :partial, self
111
+
112
+ PARTIAL_REGEX = /@include\s*([a-zA-Z0-9\-_]*)/.freeze
113
+
114
+ def self.significant?(node)
115
+ node.is_a?(Oga::XML::Comment) && node.to_xml.strip.match(PARTIAL_REGEX)
116
+ end
117
+ end
118
+
119
+ # @api private
120
+ class BindingNode < SignificantNode
121
+ StringDoc.significant :binding, self, descend: false
122
+
123
+ def self.significant?(node)
124
+ node.is_a?(Oga::XML::Element) && node.attribute(:binding) && node.name != FORM_TAG
125
+ end
126
+ end
127
+
128
+ # @api private
129
+ class WithinBindingNode < SignificantNode
130
+ StringDoc.significant :within_binding, self
131
+
132
+ def self.significant?(node)
133
+ node.is_a?(Oga::XML::Element) && within_binding?(node)
134
+ end
135
+ end
136
+
137
+ # @api private
138
+ class BindingWithinNode < SignificantNode
139
+ StringDoc.significant :binding_within, self
140
+
141
+ def self.significant?(node)
142
+ node.is_a?(Oga::XML::Element) && binding_within?(node)
143
+ end
144
+ end
145
+
146
+ # @api private
147
+ class MultipartBinding < SignificantNode
148
+ StringDoc.significant :multipart_binding, self
149
+
150
+ def self.significant?(node)
151
+ BindingNode.significant?(node) &&
152
+ node.attribute(:binding).value.include?(".") &&
153
+ !node.attribute(:binding).value.start_with?("@")
154
+ end
155
+ end
156
+
157
+ # @api private
158
+ class ComponentNode < SignificantNode
159
+ StringDoc.significant :component, self
160
+
161
+ def self.significant?(node)
162
+ node.is_a?(Oga::XML::Element) && node.attribute(:ui)
163
+ end
164
+
165
+ def self.decorate(node)
166
+ node.set_label(:components, node.attributes[:"data-ui"].split(";").map { |component_string|
167
+ Component.parse(component_string)
168
+ })
169
+ end
170
+ end
171
+
172
+ # @api private
173
+ class ModeNode < SignificantNode
174
+ StringDoc.significant :mode, self
175
+
176
+ def self.significant?(node)
177
+ node.is_a?(Oga::XML::Element) && node.attribute(:mode)
178
+ end
179
+ end
180
+
181
+ # @api private
182
+ class FormNode < SignificantNode
183
+ StringDoc.significant :form, self, descend: false
184
+
185
+ def self.significant?(node)
186
+ node.is_a?(Oga::XML::Element) && node.attribute(:binding) && node.name == FORM_TAG
187
+ end
188
+
189
+ def self.decorate(node)
190
+ node.set_label(:presenter_type, Presenters::Form)
191
+ node.set_label(:view_type, Form)
192
+ end
193
+ end
194
+
195
+ # @api private
196
+ class WithinFormNode < SignificantNode
197
+ StringDoc.significant :within_form, self
198
+
199
+ def self.significant?(node)
200
+ node.is_a?(Oga::XML::Element) && within_form?(node)
201
+ end
202
+ end
203
+
204
+ # @api private
205
+ class OptionNode < SignificantNode
206
+ StringDoc.significant :option, self
207
+
208
+ def self.significant?(node)
209
+ node.is_a?(Oga::XML::Element) && node.name == OPTION_TAG
210
+ end
211
+ end
212
+
213
+ # @api private
214
+ class OptgroupNode < SignificantNode
215
+ StringDoc.significant :optgroup, self
216
+
217
+ def self.significant?(node)
218
+ node.is_a?(Oga::XML::Element) && node.name == OPTGROUP_TAG
219
+ end
220
+ end
221
+
222
+ # @api private
223
+ class MethodOverrideNode < SignificantNode
224
+ StringDoc.significant :method_override, self
225
+
226
+ def self.significant?(node)
227
+ node.is_a?(Oga::XML::Element) && node.name == INPUT_TAG && node.attribute(:name).to_s == "_method"
228
+ end
229
+ end
230
+
231
+ # @api private
232
+ class LabelNode < SignificantNode
233
+ StringDoc.significant :label, self
234
+
235
+ def self.significant?(node)
236
+ node.is_a?(Oga::XML::Element) && node.name == LABEL_TAG
237
+ end
238
+ end
239
+
240
+ # @api private
241
+ class TitleNode < SignificantNode
242
+ StringDoc.significant :title, self
243
+
244
+ def self.significant?(node)
245
+ node.is_a?(Oga::XML::Element) && node.name == TITLE_TAG
246
+ end
247
+ end
248
+
249
+ # @api private
250
+ class BodyNode < SignificantNode
251
+ StringDoc.significant :body, self
252
+
253
+ def self.significant?(node)
254
+ node.is_a?(Oga::XML::Element) && node.name == BODY_TAG
255
+ end
256
+ end
257
+
258
+ # @api private
259
+ class HeadNode < SignificantNode
260
+ StringDoc.significant :head, self
261
+
262
+ def self.significant?(node)
263
+ node.is_a?(Oga::XML::Element) && node.name == HEAD_TAG
264
+ end
265
+ end
266
+
267
+ # @api private
268
+ class MetaNode < SignificantNode
269
+ StringDoc.significant :meta, self
270
+
271
+ def self.significant?(node)
272
+ node.is_a?(Oga::XML::Element) && node.name == META_TAG
273
+ end
274
+ end
275
+
276
+ # @api private
277
+ class HTMLNode < SignificantNode
278
+ StringDoc.significant :html, self
279
+
280
+ def self.significant?(node)
281
+ node.is_a?(Oga::XML::Element) && node.name == HTML_TAG
282
+ end
283
+ end
284
+
285
+ # @api private
286
+ class TemplateNode < SignificantNode
287
+ StringDoc.significant :template, self
288
+
289
+ def self.significant?(node)
290
+ node.is_a?(Oga::XML::Element) && node.name == SCRIPT_TAG && node[:type] == "text/template"
291
+ end
292
+ end
293
+
294
+ # @api private
295
+ class FieldNode < SignificantNode
296
+ StringDoc.significant :field, self
297
+
298
+ FIELD_TAGS = [
299
+ INPUT_TAG,
300
+ SELECT_TAG,
301
+ TEXTAREA_TAG
302
+ ].freeze
303
+
304
+ def self.significant?(node)
305
+ node.is_a?(Oga::XML::Element) && FIELD_TAGS.include?(node.name)
306
+ end
307
+ end
308
+ end
309
+ end
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/deep_dup"
4
+ require "pakyow/support/core_refinements/string/normalization"
5
+
6
+ module Pakyow
7
+ module Presenter
8
+ class Templates
9
+ using Support::DeepDup
10
+ using Support::Refinements::String::Normalization
11
+
12
+ attr_reader :name, :path, :layouts, :pages, :includes, :config
13
+
14
+ DEFAULT_LAYOUTS_PATH = "layouts"
15
+ DEFAULT_PARTIALS_PATH = "includes"
16
+ DEFAULT_PAGES_PATH = "pages"
17
+
18
+ def initialize(name, path, processor: nil, config: {})
19
+ @name, @path, @processor = name, Pathname(path), processor
20
+ build_config(config)
21
+ load_templates
22
+ end
23
+
24
+ def view?(path)
25
+ @info.key?(path)
26
+ end
27
+
28
+ def paths
29
+ @info.keys
30
+ end
31
+
32
+ def info(path)
33
+ if view?(path)
34
+ @info[path]
35
+ end
36
+ end
37
+
38
+ def layout(name_or_path)
39
+ if name_or_path.is_a?(Symbol)
40
+ layout_with_name(name_or_path)
41
+ else
42
+ info(name_or_path) & [:layout]
43
+ end
44
+ end
45
+
46
+ def page(path)
47
+ info(path) & [:page]
48
+ end
49
+
50
+ def partials(path)
51
+ info(path) & [:partials] || {}
52
+ end
53
+
54
+ def partial(path, name)
55
+ partials(path)[name.to_sym]
56
+ end
57
+
58
+ def layouts_path
59
+ path.join(@config[:paths][:layouts])
60
+ end
61
+
62
+ def partials_path
63
+ path.join(@config[:paths][:partials])
64
+ end
65
+
66
+ def pages_path
67
+ path.join(@config[:paths][:pages])
68
+ end
69
+
70
+ def template?(path)
71
+ return false if path.basename.to_s.start_with?(".")
72
+ return false unless path.extname == ".html" || @processor&.process?(path.extname)
73
+
74
+ true
75
+ end
76
+
77
+ # Yields each template.
78
+ #
79
+ def each
80
+ @info.each do |_path, info|
81
+ yield info[:layout]
82
+ yield info[:page]
83
+ info[:partials].each do |_name, partial|
84
+ yield partial
85
+ end
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def build_config(config)
92
+ @config = {
93
+ prefix: config[:prefix] || "/",
94
+ paths: {
95
+ layouts: config.dig(:paths, :layouts) || DEFAULT_LAYOUTS_PATH,
96
+ pages: config.dig(:paths, :pages) || DEFAULT_PAGES_PATH,
97
+ partials: config.dig(:paths, :partials) || DEFAULT_PARTIALS_PATH,
98
+ }
99
+ }
100
+ end
101
+
102
+ def load_templates
103
+ load_layouts
104
+ load_partials
105
+ load_path_info
106
+ end
107
+
108
+ def load_layouts
109
+ @layouts = if File.exist?(layouts_path)
110
+ layouts_path.children.each_with_object({}) { |file, layouts|
111
+ next unless template?(file)
112
+ layout = load_view_of_type_at_path(Layout, file)
113
+ layouts[layout.name] = layout
114
+ }
115
+ else
116
+ {}
117
+ end
118
+ end
119
+
120
+ def load_partials
121
+ @includes = if File.exist?(partials_path)
122
+ partials_path.children.each_with_object({}) { |file, partials|
123
+ next unless template?(file)
124
+ partial = load_view_of_type_at_path(Partial, file, normalize_path(file))
125
+ partials[partial.name] = partial
126
+ }
127
+ else
128
+ {}
129
+ end
130
+ end
131
+
132
+ def load_path_info
133
+ @info = {}
134
+
135
+ Pathname.glob(File.join(pages_path, "**/*")) do |path|
136
+ # TODO: better way to skip partials?
137
+ next if path.basename.to_s.start_with?("_")
138
+
139
+ next unless template?(path)
140
+
141
+ begin
142
+ if page = page_at_path(path)
143
+ @info[File.join(@config[:prefix], normalize_path(path, pages_path))] = {
144
+ page: page,
145
+ layout: layout_with_name(page.info(:layout)),
146
+ partials: @includes.merge(partials_at_path(path))
147
+ }
148
+ end
149
+ rescue FrontMatterParsingError => e
150
+ message = "Could not parse front matter for #{path}:\n\n#{e.context}"
151
+
152
+ if e.wrapped_exception
153
+ message << "\n#{e.wrapped_exception.problem} at line #{e.wrapped_exception.line} column #{e.wrapped_exception.column}"
154
+ end
155
+
156
+ raise FrontMatterParsingError.new(message)
157
+ end
158
+ end
159
+ end
160
+
161
+ def layout_with_name(name)
162
+ @layouts[name.to_sym]
163
+ end
164
+
165
+ def page_at_path(path)
166
+ if File.directory?(path)
167
+ if Dir.glob(File.join(path, "index.*")).empty?
168
+ index_page_at_path(path)
169
+ end
170
+ else
171
+ load_view_of_type_at_path(Page, path, normalize_path(path))
172
+ end
173
+ end
174
+
175
+ def index_page_at_path(path)
176
+ # TODO: don't ascend above store path
177
+ path.ascend do |parent_path|
178
+ next unless info = info(normalize_path(parent_path))
179
+ next unless page = info[:page]
180
+ return page
181
+ end
182
+ end
183
+
184
+ # TODO: do we always need to make it relative, etc here?
185
+ # maybe break up these responsibilities to the bare minimum required
186
+ def normalize_path(path, relative_from = @path)
187
+ path = path.expand_path
188
+ relative_from = relative_from.expand_path
189
+
190
+ # make it relative
191
+ path = path.relative_path_from(relative_from)
192
+ # we can short-circuit here
193
+ return "/" if path.to_s == "."
194
+
195
+ # remove the extension
196
+ path = path.sub_ext("")
197
+
198
+ # remove index from the end
199
+ path = path.sub("index", "")
200
+
201
+ # actually normalize it
202
+ String.normalize_path(path.to_s)
203
+ end
204
+
205
+ def partials_at_path(path)
206
+ # FIXME: don't ascend above store path
207
+ path.ascend.select(&:directory?).each_with_object({}) { |parent_path, partials|
208
+ parent_path.children.select { |child|
209
+ child.basename.to_s.start_with?("_")
210
+ }.each_with_object(partials) { |child, child_partials|
211
+ partial = load_view_of_type_at_path(Partial, child, normalize_path(child))
212
+ child_partials[partial.name] ||= partial
213
+ }
214
+ }
215
+ end
216
+
217
+ def load_view_of_type_at_path(type, path, logical_path = nil)
218
+ content = File.read(path)
219
+ info, content = FrontMatterParser.parse_and_scrub(content)
220
+
221
+ if @processor
222
+ content = @processor.process(content, File.extname(path).delete(".").to_sym)
223
+ end
224
+
225
+ type.load(path, info: info, content: content, logical_path: logical_path)
226
+ end
227
+ end
228
+ end
229
+ end