confinement 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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