confinement 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e85abea697c0437610597a3c221c833d97931bace819ba66ebb7c02d48ed6c20
4
- data.tar.gz: b611ce215a7c6057fe2e874707e314b0644f7f0732229810127cd7c7702fb572
3
+ metadata.gz: a991bdb8646d092772f6ae7154bc34c7c89ac4faf8d51822e7b1361ed8f7ec05
4
+ data.tar.gz: 073003314b979b4bbf03dc3baf487030e6a07199feef361b5addad3928a7b06c
5
5
  SHA512:
6
- metadata.gz: bdc4a25ecacc5d1c378f589d28cef55e63cfd3bbd6353ba9b1cf2439ae08f7bc219f2f77f2257d4bcf887fb7e85c8a6d659097f4a7052c5e47b72d7727b9cbde
7
- data.tar.gz: 17527d0a0f6307a5c2dc2b7b2ae445294c03afe5ffea69f20f3dabd3a6ac0a432181d82a8be7985666e01c875ff03f128aacc7add2a6968bda4770b17512c8a4
6
+ metadata.gz: 72cffafd98539f4655a039c674d9324e998ef508610bad89f9f6e21a5d06cd158487413b60bdeb6b961d76f338c44013bb4ff9f35ea0733ffba74856f01046d8
7
+ data.tar.gz: 1d6076cc1b834d0a3bf3cd9fcaee3dc7cabd6e048e3f5dc298a7d201c6b60d44f63f0a5f164378c0a9883d9a19e6c83e422a0b9b07d2727164e6e7f2a2493343
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- confinement (0.0.1)
4
+ confinement (0.0.2)
5
5
  erubi
6
6
 
7
7
  GEM
@@ -91,7 +91,7 @@ module Confinement
91
91
 
92
92
  root = Pathname.new(argv.first).expand_path
93
93
 
94
- templates = DATA.read.split(/^==> /)[1..-1]
94
+ templates = data.split(/^==> /)[1..-1]
95
95
  templates = templates.filter_map do |template|
96
96
  path, *body = template.lines
97
97
  body = body.join("")
@@ -109,8 +109,6 @@ module Confinement
109
109
  end
110
110
 
111
111
  Dir.chdir(root) do
112
- run(["yarn", "init", "--yes"])
113
-
114
112
  run(["yarn", "add", "--dev", "parcel@nightly"])
115
113
  end
116
114
  end
@@ -165,6 +163,11 @@ module Confinement
165
163
 
166
164
  /^y/i.match?(answer)
167
165
  end
166
+
167
+ def data
168
+ contents = File.read(__FILE__)
169
+ contents.split(/^__END__$/)[1]
170
+ end
168
171
  end
169
172
  end
170
173
  end
@@ -177,7 +180,7 @@ require "confinement"
177
180
 
178
181
  Confinement.root = __dir__
179
182
 
180
- Confinement.site = Confinement::Builder.new(
183
+ Confinement.site = Confinement::Site.new(
181
184
  root: Confinement.root,
182
185
  assets: "assets",
183
186
  contents: "contents",
@@ -190,48 +193,50 @@ Confinement.site = Confinement::Builder.new(
190
193
  ==> build.rb
191
194
  require_relative "boot"
192
195
 
193
- using Confinement::Easier
194
-
195
- Confinement.site.contents do |contents, layouts, dest|
196
- dest["/"] = Confinement::Content.new(
197
- layout: layouts.join("default.html.erb"),
198
- input_path: contents.join("index.html.erb"),
199
- renderers: [Confinement::Renderer::Erb.new]
200
- )
201
- end
202
-
203
- Confinement.site.assets do |assets, dest|
204
- dest["/assets/application.js"] = Confinement::Asset.new(
205
- input_path: assets.join("application.js"),
206
- entrypoint: true,
207
- )
196
+ Confinement.site.build do |assets:, layouts:, contents:, routes:|
197
+ assets.init("application.js", entrypoint: true)
198
+ assets.init("application.css", entrypoint: false)
208
199
 
209
- dest["/assets/application.css"] = Confinement::Asset.new(
210
- input_path: assets.join("application.css"),
211
- entrypoint: false,
212
- )
213
- end
200
+ layouts.init("default.html.erb")
214
201
 
215
- Confinement.site.layouts do |layouts, dest|
216
- dest[layouts.join("default.html.erb")] = Confinement::Layout.new(
217
- renderers: [Confinement::Renderer::Erb.new]
218
- )
202
+ routes["/"] = contents.init("index.html.erb") do |content|
203
+ content.layout = layouts["default.html.erb"]
204
+ end
219
205
  end
220
206
 
221
207
  ==> write.rb
222
208
  require_relative "build"
223
209
 
224
- Confinement::Publish
225
- .new(Confinement.site)
226
- .write(Confinement.root.join("public"))
210
+ Confinement::Publish.new(Confinement.site).write
211
+
212
+ ==> package.json
213
+ {
214
+ "name": "website",
215
+ "version": "1.0.0",
216
+ "license": "UNLICENSED",
217
+ "devDependencies": {
218
+ },
219
+ "dependencies": {
220
+ }
221
+ }
227
222
 
228
223
  ==> assets/application.js
229
224
  import "./application.css";
230
225
 
231
226
  ==> assets/application.css
227
+ body { color: blue }
232
228
 
233
229
  ==> layouts/default.html.erb
230
+ <!DOCTYPE HTML>
231
+ <html lang="en">
232
+ <head>
233
+ <meta charset="utf-8">
234
+ <link rel="stylesheet" href="<%= assets["application.css"].url_path %>" charset="utf-8">
235
+ </head>
236
+ <body>
237
+ <%= yield %>
238
+ </body>
239
+ </html>
234
240
 
235
241
  ==> contents/index.html.erb
236
-
237
-
242
+ hello!
@@ -14,6 +14,7 @@ require "yaml"
14
14
 
15
15
  # gems
16
16
  require "erubi"
17
+ require "erubi/capture_end"
17
18
 
18
19
  # internal
19
20
  require_relative "confinement/version"
@@ -58,7 +59,7 @@ module Confinement
58
59
 
59
60
  return [{}, self] if matches["frontmatter"].nil?
60
61
 
61
- frontmatter = YAML.safe_load(matches["frontmatter"])
62
+ frontmatter = YAML.load(matches["frontmatter"], symbolize_names: true)
62
63
  body = matches["body"] || ""
63
64
  body = body.strip if strip
64
65
 
@@ -66,6 +67,10 @@ module Confinement
66
67
  rescue ArgumentError
67
68
  [{}, self]
68
69
  end
70
+
71
+ def normalize_for_route
72
+ "/#{self}".squeeze("/")
73
+ end
69
74
  end
70
75
  end
71
76
 
@@ -88,12 +93,24 @@ module Confinement
88
93
  end
89
94
  end
90
95
 
91
- class Builder
92
- def initialize(root:, assets:, contents:, layouts:, config: {})
96
+ class Site
97
+ def initialize(
98
+ root:,
99
+ assets:,
100
+ contents:,
101
+ layouts:,
102
+ view_context_helpers: [],
103
+ guesses: Renderer.guesses,
104
+ config: {}
105
+ )
93
106
  @root = root
94
107
  @assets = assets
95
108
  @contents = contents
96
109
  @layouts = layouts
110
+
111
+ @view_context_helpers = view_context_helpers
112
+ @guessing_registry = guesses
113
+
97
114
  @config = {
98
115
  index: config.fetch(:index, "index.html")
99
116
  }
@@ -101,167 +118,204 @@ module Confinement
101
118
  @output_root = root.concat(config.fetch(:destination_root, "public"))
102
119
  @assets_root = @output_root.concat(config.fetch(:assets_subdirectory, "assets"))
103
120
 
104
- @representation = Representation.new
121
+ @route_identifiers = RouteIdentifiers.new
122
+ @asset_blobs = Blobs.new(scoped_root: assets_path, file_abstraction_class: Asset)
123
+ @content_blobs = Blobs.new(scoped_root: contents_path, file_abstraction_class: Content)
124
+ @layout_blobs = Blobs.new(scoped_root: layouts_path, file_abstraction_class: Layout)
105
125
  end
106
126
 
107
127
  attr_reader :root
108
128
  attr_reader :output_root
109
129
  attr_reader :assets_root
110
- attr_reader :representation
111
130
  attr_reader :config
112
131
 
113
- def contents_path
114
- @contents_path ||= @root.concat(@contents)
115
- end
132
+ attr_reader :route_identifiers
133
+ attr_reader :asset_blobs
134
+ attr_reader :content_blobs
135
+ attr_reader :layout_blobs
116
136
 
117
- def layouts_path
118
- @layouts_path ||= @root.concat(@layouts)
119
- end
137
+ attr_reader :view_context_helpers
138
+ attr_reader :guessing_registry
120
139
 
121
- def assets_path
122
- @assets_path ||= @root.concat(@assets)
123
- end
140
+ def build
141
+ yield(
142
+ assets: @asset_blobs,
143
+ layouts: @layout_blobs,
144
+ contents: @content_blobs,
145
+ routes: @route_identifiers
146
+ )
124
147
 
125
- def layouts
126
- if !layouts_path.exist?
127
- raise PathDoesNotExist, "Layouts path doesn't exist: #{layouts_path}"
128
- end
148
+ guesser = Rendering::Guesser.new(guessing_registry)
149
+ guess_renderers(guesser, @layout_blobs)
150
+ guess_renderers(guesser, @content_blobs)
151
+
152
+ @asset_blobs.done!
153
+ @layout_blobs.done!
154
+ @content_blobs.done!
155
+ @route_identifiers.done!
129
156
 
130
- yield(layouts_path, @representation.layouts)
157
+ nil
131
158
  end
132
159
 
133
- def assets
134
- if !assets_path.exist?
135
- raise PathDoesNotExist, "Assets path doesn't exist: #{assets_path}"
160
+ private
161
+
162
+ def guess_renderers(guesser, blobs)
163
+ blobs.send(:lookup).values.each do |blob|
164
+ blob.renderers = blob.renderers.flat_map do |renderer|
165
+ if renderer == :guess
166
+ guesser.call(blob.input_path)
167
+ else
168
+ renderer
169
+ end
170
+ end
136
171
  end
172
+ end
137
173
 
138
- yield(assets_path, @representation.assets)
174
+ def contents_path
175
+ @contents_path ||= @root.concat(@contents).cleanpath
139
176
  end
140
177
 
141
- def contents
142
- if !contents_path.exist?
143
- raise PathDoesNotExist, "Contents path doesn't exist: #{contents_path}"
144
- end
178
+ def layouts_path
179
+ @layouts_path ||= @root.concat(@layouts).cleanpath
180
+ end
145
181
 
146
- yield(contents_path, layouts_path, @representation.contents)
182
+ def assets_path
183
+ @assets_path ||= @root.concat(@assets).cleanpath
147
184
  end
148
185
  end
149
186
 
150
- class Representation
151
- include Enumerable
152
-
187
+ # RouteIdentifiers is called such because it doesn't hold the actual
188
+ # content's route. The content's own `url_path` does.
189
+ #
190
+ # This is mainly so that assets could be referenced internally with a static
191
+ # identifier even though it could have a hashed route.
192
+ class RouteIdentifiers
153
193
  def initialize
154
- @lookup = {}
155
- @layouts_lookup = {}
156
- @only_assets = []
157
- @only_contents = []
194
+ self.lookup = {}
195
+ end
196
+
197
+ def done!
198
+ @done = true
158
199
  end
159
200
 
160
- attr_reader :only_assets
161
- attr_reader :layouts_lookup
162
- attr_reader :only_contents
201
+ def [](route)
202
+ route = route.normalize_for_route
163
203
 
164
- def fetch(key)
165
- if !@lookup.key?(key)
166
- raise "Not represented!"
204
+ if !lookup.key?(route)
205
+ raise "Route is not defined"
167
206
  end
168
207
 
169
- @lookup[key]
208
+ self.lookup[route]
170
209
  end
171
210
 
172
- def each
173
- if !block_given?
174
- return enum_for(:each)
175
- end
211
+ def []=(route, content)
212
+ raise "Can't add more routes after initial setup" if @done
176
213
 
177
- @lookup.each do |identifier, page|
178
- yield(identifier, page)
214
+ route = route.normalize_for_route
215
+
216
+ if lookup.key?(route)
217
+ raise "Route already defined!"
179
218
  end
219
+
220
+ content.url_path = route
221
+
222
+ lookup[route] = content
180
223
  end
181
224
 
182
- def layouts
183
- Setter.new(@layouts_lookup) do |path, layout|
184
- layout.input_path = path
185
- end
225
+ private
226
+
227
+ attr_accessor :lookup
228
+ end
229
+
230
+ class Blobs
231
+ def initialize(scoped_root:, file_abstraction_class:)
232
+ self.scoped_root = scoped_root
233
+ self.file_abstraction_class = file_abstraction_class
234
+ self.lookup = {}
235
+ @done = false
186
236
  end
187
237
 
188
- def assets
189
- Setter.new(@lookup) do |identifier, asset|
190
- @only_assets.push(asset)
191
- asset.url_path = identifier
192
- end
238
+ def done!
239
+ @done = true
193
240
  end
194
241
 
195
- def contents
196
- Setter.new(@lookup) do |identifier, content|
197
- @only_contents.push(content)
198
- content.url_path = identifier
242
+ def [](relpath)
243
+ abspath = into_abspath(relpath)
244
+
245
+ if !lookup.key?(abspath)
246
+ raise "Don't know about this blob: #{abspath.inspect}"
199
247
  end
200
- end
201
248
 
202
- def routes_getter
203
- LookupGetter.new(@lookup)
249
+ lookup[abspath]
204
250
  end
205
251
 
206
- def layouts_getter
207
- LookupGetter.new(@layouts_lookup)
252
+ def init(relpath, **initializer_options)
253
+ raise "Can't add more #{file_abstraction_class}s after the initial setup!" if @done
254
+
255
+ abspath = into_abspath(relpath)
256
+ lookup[abspath] ||= file_abstraction_class.new(input_path: abspath, **initializer_options)
257
+ yield lookup[abspath] if block_given?
258
+ lookup[abspath]
208
259
  end
209
260
 
210
- class Setter
211
- def initialize(lookup, &block)
212
- @lookup = lookup
213
- @block = block
261
+ def init_many(pattern)
262
+ files_lookup.filter_map do |relpath, abspath|
263
+ if pattern.match?(relpath)
264
+ lookup[abspath.to_s] ||= file_abstraction_class.new(input_path: abspath)
265
+ end
214
266
  end
267
+ end
215
268
 
216
- def []=(key, value)
217
- @block&.call(key, value)
269
+ private
218
270
 
219
- @lookup[key] = value
220
- end
271
+ def into_abspath(relpath)
272
+ scoped_root.concat(relpath).cleanpath
221
273
  end
222
274
 
223
- class LookupGetter
224
- def initialize(lookup)
225
- @lookup = lookup
226
- end
227
-
228
- def [](key)
229
- @lookup.fetch(key)
230
- end
275
+ def files_lookup
276
+ @files_lookup ||=
277
+ scoped_root
278
+ .glob("**/*")
279
+ .map { |path| [path.relative_path_from(scoped_root).to_s, path] }
280
+ .to_h
231
281
  end
282
+
283
+ attr_accessor :scoped_root
284
+ attr_accessor :file_abstraction_class
285
+ attr_accessor :lookup
232
286
  end
233
287
 
234
288
  module Blob
235
289
  attr_accessor :input_path
290
+ end
291
+
292
+ module RouteableBlob
236
293
  attr_accessor :output_path
237
294
  attr_reader :url_path
238
295
 
239
- def url_path=(path)
240
- if path.nil?
241
- @url_path = nil
242
- return
243
- end
296
+ def url_path=(new_url_path)
297
+ @url_path = new_url_path.normalize_for_route
298
+ end
299
+ end
244
300
 
245
- path = path.to_s
246
- if path[0] != "/"
247
- path = "/#{path}"
248
- end
301
+ module RenderableBlob
302
+ attr_reader :renderers
249
303
 
250
- @url_path = path
304
+ def renderers=(new_renderers)
305
+ @renderers = Array(new_renderers)
251
306
  end
252
307
  end
253
308
 
254
309
  class Asset
255
310
  include Blob
311
+ include RouteableBlob
256
312
 
257
313
  def initialize(input_path:, entrypoint:)
258
314
  self.input_path = input_path
259
-
260
315
  @entrypoint = entrypoint
261
- @url_path = nil
262
316
  end
263
317
 
264
- attr_accessor :rendered_body
318
+ attr_accessor :body
265
319
 
266
320
  def entrypoint?
267
321
  !!@entrypoint
@@ -270,48 +324,90 @@ module Confinement
270
324
 
271
325
  class Content
272
326
  include Blob
327
+ include RouteableBlob
328
+ include RenderableBlob
273
329
 
274
- def initialize(layout: nil, input_path: nil, locals: {}, renderers: [])
330
+ def initialize(input_path:, layout: nil, locals: {}, renderers: :guess)
275
331
  self.input_path = input_path
276
332
 
277
- @layout = layout
278
- @locals = locals
279
- @renderers = renderers
333
+ self.layout = layout
334
+ self.locals = locals
335
+ self.renderers = renderers
280
336
  end
281
337
 
282
- attr_reader :locals
283
- attr_reader :renderers
284
- attr_reader :layout
338
+ attr_accessor :locals
339
+ attr_accessor :layout
340
+
341
+ def body
342
+ parse_body_and_frontmatter
343
+ @body
344
+ end
345
+
346
+ def frontmatter
347
+ parse_body_and_frontmatter
348
+ @frontmatter
349
+ end
350
+
351
+ private
285
352
 
286
- attr_accessor :rendered_body
353
+ def parse_body_and_frontmatter
354
+ return if defined?(@frontmatter) && defined?(@body)
355
+ @frontmatter, @body = input_path.read.frontmatter_and_body
356
+ end
287
357
  end
288
358
 
289
359
  class Layout
290
- def initialize(renderers:)
291
- @renderers = renderers
360
+ include Blob
361
+ include RenderableBlob
362
+
363
+ def initialize(input_path:, renderers: :guess)
364
+ self.input_path = input_path
365
+ self.renderers = renderers
292
366
  end
293
367
 
294
- attr_reader :renderers
295
- attr_accessor :input_path
368
+ def body
369
+ @body ||= input_path.read
370
+ end
296
371
  end
297
372
 
298
373
  class Renderer
374
+ def self.guesses
375
+ @guesses ||= {
376
+ "erb" => -> { Erb.new }
377
+ }
378
+ end
379
+
299
380
  class Erb
300
- def call(source, view_context, &block)
301
- method_name = "_#{Digest::MD5.hexdigest(source)}"
381
+ def call(source, view_context, path:, &block)
382
+ method_name =
383
+ if path
384
+ "_#{Digest::MD5.hexdigest(source)}__#{path.to_s.tr("^A-Za-z", "_")}"
385
+ else
386
+ "_#{Digest::MD5.hexdigest(source)}"
387
+ end
302
388
 
303
- compile(method_name, source, view_context)
389
+ compile(method_name, source, view_context, path: path)
304
390
 
305
391
  view_context.public_send(method_name, &block)
306
392
  end
307
393
 
308
394
  private
309
395
 
310
- def compile(method_name, source, view_context)
396
+ def compile(method_name, source, view_context, path:)
311
397
  if !view_context.respond_to?(method_name)
312
- compiled_erb = Erubi::Engine.new(source).src
398
+ compiled_erb =
399
+ Erubi::CaptureEndEngine
400
+ .new(source, bufvar: :@_buf, ensure: true, yield_returns_buffer: true)
401
+ .src
402
+
403
+ eval_location =
404
+ if path
405
+ [path.to_s, 0]
406
+ else
407
+ []
408
+ end
313
409
 
314
- view_context.instance_eval(<<~RUBY, __FILE__, __LINE__ + 1)
410
+ view_context.instance_eval(<<~RUBY, *eval_location)
315
411
  def #{method_name}
316
412
  #{compiled_erb}
317
413
  end
@@ -322,56 +418,73 @@ module Confinement
322
418
  end
323
419
 
324
420
  class Rendering
421
+ class Guesser
422
+ def initialize(guessing_registry)
423
+ @guessing_registry = guessing_registry
424
+ end
425
+
426
+ def call(path)
427
+ basename = path.basename.to_s
428
+ extensions = basename.split(".")[1..-1]
429
+
430
+ extensions.reverse.filter_map do |extension|
431
+ next if !@guessing_registry.key?(extension)
432
+
433
+ guess = @guessing_registry[extension]
434
+ guess = guess.call if guess.is_a?(Proc)
435
+
436
+ guess
437
+ end
438
+ end
439
+ end
440
+
325
441
  class ViewContext
326
- def initialize(routes:, layouts:, locals:, frontmatter:, contents_path:, layouts_path:)
442
+ def initialize(routes:, layouts:, assets:, contents:, locals:, frontmatter:)
327
443
  @routes = routes
328
444
  @layouts = layouts
445
+ @assets = assets
446
+ @contents = contents
329
447
 
330
448
  @locals = locals
331
449
  @frontmatter = frontmatter
332
-
333
- @contents_path = contents_path
334
- @layouts_path = layouts_path
335
450
  end
336
451
 
337
452
  attr_reader :routes
338
453
  attr_reader :layouts
454
+ attr_reader :assets
455
+ attr_reader :contents
339
456
  attr_reader :locals
340
457
  attr_reader :frontmatter
341
- attr_reader :contents_path
342
- attr_reader :layouts_path
343
-
344
- def render(path = nil, inline: nil, layout: nil, renderers:, &block)
345
- body =
346
- if inline
347
- inline
348
- elsif path
349
- path.read
350
- else
351
- raise %(Must pass in either a Pathname or `inline: 'text'`)
352
- end
353
458
 
459
+ def capture
460
+ original_buffer = @_buf
461
+ @_buf = +""
462
+ yield
463
+ @_buf
464
+ ensure
465
+ @_buf = original_buffer
466
+ end
467
+
468
+ def render(blob, layout: nil, &block)
354
469
  render_chain = RenderChain.new(
355
- body: body,
356
- layout: layout,
357
- renderers: renderers,
470
+ body: blob.body,
471
+ path: blob.input_path,
472
+ renderers: blob.renderers,
358
473
  view_context: self
359
474
  )
360
- rendered_body = render_chain.call(&block)
361
-
362
- if layout
363
- layout =
364
- if layout.is_a?(Layout)
365
- layout
366
- elsif layout.is_a?(Pathname)
367
- layouts[layout]
368
- else
369
- raise "Expected layout to be a Layout or Pathname"
475
+ rendered_body =
476
+ if block_given?
477
+ render_chain.call do
478
+ capture { yield }
370
479
  end
480
+ else
481
+ render_chain.call
482
+ end
371
483
 
484
+ if layout
372
485
  layout_render_chain = RenderChain.new(
373
- body: layout.input_path.read,
374
- layout: nil,
486
+ body: layout.body,
487
+ path: layout.input_path,
375
488
  renderers: layout.renderers,
376
489
  view_context: self
377
490
  )
@@ -386,22 +499,22 @@ module Confinement
386
499
  end
387
500
 
388
501
  class RenderChain
389
- def initialize(body:, layout:, renderers:, view_context:)
502
+ def initialize(body:, path:, renderers:, view_context:)
390
503
  @body = body
391
- @layout = layout
504
+ @path = path
392
505
  @renderers = renderers
393
506
  @view_context = view_context
394
507
  end
395
508
 
396
509
  def call(&block)
397
510
  @renderers.reduce(@body) do |memo, renderer|
398
- renderer.call(memo, @view_context, &block)
511
+ renderer.call(memo, @view_context, path: @path, &block)
399
512
  end
400
513
  end
401
514
  end
402
515
  end
403
516
 
404
- class HesitantCompiler
517
+ class Compiler
405
518
  def initialize(site)
406
519
  @site = site
407
520
  @lock = Mutex.new
@@ -414,8 +527,8 @@ module Confinement
414
527
  # to worry about deadlocks or anything
415
528
  @lock.synchronize do
416
529
  # Assets first since it's almost always a dependency of contents
417
- compile_assets(site.representation.only_assets)
418
- compile_contents(site.representation.only_contents)
530
+ compile_assets(site.asset_blobs.send(:lookup))
531
+ compile_contents(site.route_identifiers.send(:lookup).values)
419
532
  end
420
533
  end
421
534
 
@@ -424,79 +537,73 @@ module Confinement
424
537
  PARCEL_FILES_OUTPUT_REGEX = /^✨[^\n]+\n\n(.*)Done in(?:.*)\z/m
425
538
  PARCEL_FILE_OUTPUT_REGEX = /^(?<page>.*?)\s+(?<size>[0-9\.]+\s*[A-Z]?B)\s+(?<time>[0-9\.]+[a-z]?s)$/
426
539
 
427
- def compile_assets(assets)
428
- if assets_dirty?
429
- out, status = Open3.capture2(
430
- "yarn",
431
- "run",
432
- "parcel",
433
- "build",
434
- "--dist-dir", site.assets_root.to_s,
435
- "--public-url", site.assets_root.basename.to_s,
436
- *assets.select(&:entrypoint?).map(&:input_path).map(&:to_s)
437
- )
438
-
439
- if !status.success?
440
- raise "Asset compilation failed"
441
- end
540
+ def compile_assets(asset_files)
541
+ asset_paths = asset_files.values
542
+
543
+ out, status = Open3.capture2(
544
+ "yarn",
545
+ "run",
546
+ "parcel",
547
+ "build",
548
+ "--no-cache",
549
+ "--dist-dir", site.assets_root.to_s,
550
+ "--public-url", site.assets_root.basename.to_s,
551
+ *asset_paths.select(&:entrypoint?).map(&:input_path).map(&:to_s)
552
+ )
442
553
 
443
- matches = PARCEL_FILES_OUTPUT_REGEX.match(out)[1]
554
+ if !status.success?
555
+ raise "Asset compilation failed"
556
+ end
444
557
 
445
- if !matches
446
- raise "Asset parsing failed"
447
- end
558
+ matches = PARCEL_FILES_OUTPUT_REGEX.match(out)[1]
448
559
 
449
- processed_file_paths = matches.split("\n\n")
560
+ if !matches
561
+ raise "Asset compilation output parsing failed"
562
+ end
450
563
 
451
- representation_by_input_path =
452
- site.representation.only_assets.filter_map do |page|
453
- next if page.input_path.nil?
564
+ processed_file_paths = matches.split("\n\n")
454
565
 
455
- [page.input_path, page]
456
- end
457
- .to_h
566
+ processed_file_paths.map do |file|
567
+ output_file, *input_files = file.strip.split(/\n(?:└|├)── /)
458
568
 
459
- processed_file_paths.map do |file|
460
- output_file, input_file = file.strip.split("\n└── ")
569
+ output_path = site.root.concat(output_file[PARCEL_FILE_OUTPUT_REGEX, 1])
461
570
 
462
- output_path = site.root.concat(output_file[PARCEL_FILE_OUTPUT_REGEX, 1])
571
+ input_files.each do |input_file|
463
572
  input_path = site.root.concat(input_file[PARCEL_FILE_OUTPUT_REGEX, 1])
464
573
 
465
- if !representation_by_input_path.key?(input_path)
574
+ if !asset_files.key?(input_path)
466
575
  next
467
576
  end
468
577
 
469
578
  url_path = output_path.relative_path_from(site.output_root)
470
- representation_by_input_path[input_path].url_path = url_path.to_s
471
- representation_by_input_path[input_path].output_path = output_path
472
- representation_by_input_path[input_path].rendered_body = output_path.read
579
+ asset_files[input_path].url_path = url_path.to_s
580
+ asset_files[input_path].output_path = output_path
581
+ asset_files[input_path].body = output_path.read
473
582
  end
474
583
  end
475
584
  end
476
585
 
477
- def compile_content(content)
478
- if content.rendered_body
479
- return
586
+ def compile_contents(contents)
587
+ contents.each do |content|
588
+ compile_content(content)
480
589
  end
590
+ end
481
591
 
482
- content_body = content.input_path.read
483
- frontmatter, content_body = content_body.frontmatter_and_body
484
-
592
+ def compile_content(content)
485
593
  view_context = Rendering::ViewContext.new(
486
- routes: site.representation.routes_getter,
487
- layouts: site.representation.layouts_getter,
594
+ routes: site.route_identifiers,
595
+ layouts: site.layout_blobs,
596
+ assets: site.asset_blobs,
597
+ contents: site.content_blobs,
488
598
  locals: content.locals,
489
- frontmatter: frontmatter,
490
- contents_path: site.contents_path,
491
- layouts_path: site.layouts_path
599
+ frontmatter: content.frontmatter
492
600
  )
493
601
 
494
- content.rendered_body = view_context.render(
495
- inline: content_body,
496
- layout: content.layout,
497
- renderers: content.renderers
498
- )
499
- content.rendered_body ||= ""
602
+ site.view_context_helpers.each do |helper|
603
+ view_context.extend(helper)
604
+ end
605
+
606
+ rendered_body = view_context.render(content, layout: content.layout) || ""
500
607
 
501
608
  content.output_path =
502
609
  if content.url_path[-1] == "/"
@@ -506,7 +613,7 @@ module Confinement
506
613
  end
507
614
 
508
615
  if content.output_path.exist?
509
- if content.output_path.read == content.rendered_body
616
+ if content.output_path.read == rendered_body
510
617
  return
511
618
  end
512
619
  end
@@ -519,38 +626,20 @@ module Confinement
519
626
  content.output_path.dirname.mkpath
520
627
  end
521
628
 
522
- content.output_path.write(content.rendered_body)
629
+ content.output_path.write(rendered_body)
523
630
 
524
631
  nil
525
632
  end
526
-
527
- def compile_contents(contents)
528
- return if !contents_dirty?
529
-
530
- contents.each do |content|
531
- compile_content(content)
532
- end
533
- end
534
-
535
- private
536
-
537
- def contents_dirty?
538
- true
539
- end
540
-
541
- def assets_dirty?
542
- true
543
- end
544
633
  end
545
634
 
546
635
  class Publish
547
636
  def initialize(site)
548
637
  @site = site
549
- @compiler = HesitantCompiler.new(@site)
638
+ @compiler = Compiler.new(@site)
550
639
  end
551
640
 
552
- def write(path)
553
- find_or_raise_or_mkdir(path)
641
+ def write
642
+ find_or_raise_or_mkdir(@site.output_root)
554
643
 
555
644
  @compiler.compile_everything
556
645
  end
@@ -1,3 +1,3 @@
1
1
  module Confinement
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: confinement
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Ahn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-29 00:00:00.000000000 Z
11
+ date: 2020-04-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler