vizbuilder 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -9
  3. data/VERSION +1 -1
  4. data/lib/vizbuilder.rb +135 -86
  5. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 355a987affceba248fae74aa69124a43692fd4adf2e7b99c4630bcb23e171468
4
- data.tar.gz: 9fc566a7d1a66772a25120328fd9dd9c746c0fdeabf0d4df930b67231c42ec28
3
+ metadata.gz: e273e34c974ba38b41ede845375fde15653789fd4dfc5dd06b2c870b9b66852a
4
+ data.tar.gz: 261ebf230a9ef189707efeab09774837072058ab79aa0e16f854bcb145be62c5
5
5
  SHA512:
6
- metadata.gz: 4eeb652f8ebef7481efb3a817a66c3a859a0b3d98660c8753c68a8c9d5e1d22b1e72ac62eb4a2a49562305f8735657c876db106ee6270a88102ecb203294c300
7
- data.tar.gz: 64e29998acaa50cc9f8664618f569c4971c11f07b109ab2f02b3376c988c6f8320d9dd0e51c0d475a48c05da2f12e3c7cdf8b02ad574eacdaa639f94af4cba55
6
+ metadata.gz: 7a6503f0e5312e988b0636b54072ebf07de0dcd853a16aec190dd59a48d66ff8de6f0c5af814e83aa4b2560cdaef5e78d3ca50a2439391a18e9fe684db2da35e
7
+ data.tar.gz: 4e574ad770e138419ef08e0357ab1036d28c3a96f164213af3a0a29c1d7122b08fe340dc931f5541b77c7405d8216235f5e0a13d197d87f76d624c6cb7efe90c
data/README.md CHANGED
@@ -89,15 +89,7 @@ In `index.html.erb`:
89
89
 
90
90
  ## Configuration
91
91
 
92
- A new `VizBuilder` instance can be configured directly or via a block passed into the constructor:
93
-
94
- ```ruby
95
- app = VizBuilder.new
96
- app.set :some_global_config_thing, 'hello world'
97
- app.add_page 'index.html', template: 'index.html.erb'
98
- ```
99
-
100
- Or you can use a block:
92
+ A new `VizBuilder` instance is configured via a block passed into the constructor:
101
93
 
102
94
  ```ruby
103
95
  app = VizBuilder.new do
@@ -106,6 +98,14 @@ app = VizBuilder.new do
106
98
  end
107
99
  ```
108
100
 
101
+ You can add or adjust configuration directly on the `VizBuilder#config` instance, but
102
+ it may not work as expected:
103
+
104
+ ```ruby
105
+ app.config.set :some_global_config_thing, 'a different thing'
106
+ app.config.add_page 'index.html', template: 'index.html.erb'
107
+ ```
108
+
109
109
  There are a few config settings used by Viz Builder:
110
110
 
111
111
  #### http_prefix
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.2
1
+ 1.0.3
data/lib/vizbuilder.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'psych'
2
4
  require 'fileutils'
3
5
  require 'erb'
@@ -15,28 +17,24 @@ class VizBuilder
15
17
  attr_reader :config
16
18
  delegate :sitemap, :data, :hooks, :helper_modules, to: :config
17
19
 
18
- BUILD_DIR = 'build'.freeze
19
- PREBUILT_DIR = 'prebuild'.freeze
20
- DATA_DIR = 'data'.freeze
20
+ BUILD_DIR = 'build'
21
+ PREBUILT_DIR = 'prebuild'
22
+ DATA_DIR = 'data'
21
23
 
22
24
  def initialize(config = {}, &blk)
23
25
  # Config is an object used as the context for the given block
24
26
  @config = Config.new(config: config)
25
- # Load data into @data
26
- reload_data!
27
- # Execute the given block as a method of this class. The block can then use
28
- # the methods `add_page`, `add_data`, and `set`
29
- @config.instance_exec(&blk) if block_given?
30
- # Run any after load data hooks since they got added after the first load
31
- # data was called.
32
- run_hook!(:after_load_data)
33
- # Add helpers to the TemplateContext class
34
- TemplateContext.include(*helper_modules) unless helper_modules.empty?
27
+ @config_block = block_given? ? blk : nil
28
+ @config.helpers(Helpers)
29
+ @config.helpers(ConfigHelpers, type: :config)
30
+ @config.helpers(TemplateHelpers, type: :template)
31
+ @_configured = false
35
32
  end
36
33
 
37
34
  # Generate all pages in the sitemap and save to `build/`
38
35
  def build!(silent: false)
39
- ctx = TemplateContext.new(:production, :build, @config)
36
+ configure!(mode: :build, target: :production)
37
+ ctx = TemplateContext.new(@config)
40
38
  index_prebuilt!
41
39
  # First we build prebuilt pages that need digests calculated by build_page
42
40
  digested = sitemap.select { |_path, page| page[:digest] == true }
@@ -48,6 +46,7 @@ class VizBuilder
48
46
 
49
47
  # Run this builder as a server
50
48
  def runserver!(host: '127.0.0.1', port: '3456')
49
+ configure!(mode: :server, target: :development)
51
50
  status = 0 # running: 0, reload: 1, exit: 2
52
51
  # spawn a thread to watch the status flag and trigger a reload or exit
53
52
  monitor = Thread.new do
@@ -79,6 +78,8 @@ class VizBuilder
79
78
 
80
79
  # Support the call method so an instance can act as a Rack app
81
80
  def call(env)
81
+ raise 'VizBuilder configuration incomplete!' unless @_configured
82
+
82
83
  # Only support GET, OPTIONS, HEAD
83
84
  unless env['REQUEST_METHOD'].in?(%w[GET HEAD OPTIONS])
84
85
  return [405, { 'Content-Type' => 'text/plain' }, ['METHOD NOT ALLOWED']]
@@ -108,7 +109,7 @@ class VizBuilder
108
109
  # Check our sitemap then our prebuilt folder for content to serve
109
110
  if sitemap[path].present?
110
111
  content_type = MimeMagic.by_path(path).to_s
111
- ctx = TemplateContext.new(:development, :server, @config)
112
+ ctx = TemplateContext.new(@config)
112
113
  content = build_page(path, ctx)
113
114
  status = 200
114
115
  elsif File.exist?(build_filename)
@@ -126,6 +127,31 @@ class VizBuilder
126
127
  data.merge!(load_data)
127
128
  # TODO: after load hooks only run once, not every time reload_data! is called
128
129
  run_hook!(:after_load_data)
130
+ # Chainable
131
+ self
132
+ end
133
+
134
+ # Complete the configuration for this app. Is used by build! and runserver!.
135
+ # You will only need this method if you're running VizBuilder as a rack app
136
+ # without using runserver!.
137
+ def configure!(kwargs = nil)
138
+ return self if @_configured
139
+ # Update config with any kwargs
140
+ @config.merge!(kwargs) if kwargs.present?
141
+ # Load data into @data
142
+ reload_data!
143
+ # Execute the given block as a method of this class. The block can then use
144
+ # the methods `add_page`, `add_data`, and `set`
145
+ @config.instance_exec(&@config_block) if @config_block.present?
146
+ # Run any after load data hooks since they got added after the first load
147
+ # data was called.
148
+ run_hook!(:after_load_data)
149
+ # Add helpers to the TemplateContext class
150
+ TemplateContext.include(*helper_modules) unless helper_modules.empty?
151
+ # Mark app configured
152
+ @_configured = true
153
+ # Chainable
154
+ self
129
155
  end
130
156
 
131
157
  # Like File.extname, but gets all extensions if multiple are present
@@ -152,7 +178,7 @@ class VizBuilder
152
178
  # Convenience methods for configuring the site
153
179
  class Config
154
180
  attr_accessor :data, :config, :sitemap, :hooks, :helper_modules
155
- delegate :[], :[]=, :key?, to: :config
181
+ delegate :[], :[]=, :key?, :update, :merge!, to: :config
156
182
 
157
183
  def initialize(config: {})
158
184
  # Config is a Hash of site wide configuration variables
@@ -204,12 +230,12 @@ class VizBuilder
204
230
  end
205
231
 
206
232
  # Add helper modules or define helpers in a block
207
- def helpers(*mods, &blk)
233
+ def helpers(*mods, type: nil, &blk)
208
234
  new_helpers = []
209
235
  # loop over the list of arguments, making sure they're all modules, and
210
236
  # then add them to the list of new helpers
211
237
  mods.each do |mod|
212
- unless mods.is_a?(Module)
238
+ unless mod.is_a?(Module)
213
239
  raise ArgumentError, 'Helpers must be defined in a module or block'
214
240
  end
215
241
 
@@ -221,9 +247,9 @@ class VizBuilder
221
247
  if new_helpers.present?
222
248
  # extend the current Config instance with the helpers, making them available
223
249
  # to the rest of the configuration block
224
- extend(*new_helpers)
250
+ extend(*new_helpers) if type.nil? || type.to_sym == :config
225
251
  # add our new helpers to our array of all helpers
226
- @helper_modules += new_helpers
252
+ @helper_modules += new_helpers if type.nil? || type.to_sym == :template
227
253
  end
228
254
 
229
255
  self
@@ -248,11 +274,7 @@ class VizBuilder
248
274
  attr_accessor :page
249
275
  delegate :data, :sitemap, :config, to: :@config_obj
250
276
 
251
- def initialize(target, mode, config)
252
- # Target is development or production
253
- @target = target.to_sym
254
- # Mode is build or server
255
- @mode = mode.to_sym
277
+ def initialize(config)
256
278
  # Config is our Builder config object
257
279
  @config_obj = config
258
280
  # Page is a hash representing the page. Is the same as whats in sitemap
@@ -287,8 +309,49 @@ class VizBuilder
287
309
  end
288
310
  end
289
311
 
290
- # HELPERS
312
+ # Looks for an invoked method name in locals then in config, so locals
313
+ # and config vars can be used as if they're local vars in the template
314
+ def method_missing(sym)
315
+ return @locals[sym] if @locals.key?(sym)
316
+ return config[sym] if config.key?(sym)
317
+ super
318
+ end
319
+
320
+ def respond_to_missing?(sym, *)
321
+ @locals.key?(sym) || config.key?(sym) || super
322
+ end
323
+ end
324
+
325
+ # HELPERS
326
+
327
+ # The Helpers module holds methods that are added to both the config and
328
+ # template contexts. So you can use these in the config block and in
329
+ # templates.
330
+ module Helpers
331
+ # Are we running as a server?
332
+ def server?
333
+ config[:mode] == :server
334
+ end
335
+
336
+ # Are we building this app out?
337
+ def build?
338
+ config[:mode] == :build
339
+ end
340
+
341
+ # Is this in production?
342
+ def production?
343
+ config[:target] == :production
344
+ end
291
345
 
346
+ # Is this in development?
347
+ def development?
348
+ config[:target] == :development
349
+ end
350
+ end
351
+
352
+ # The TemplateHelpers modules hold methods that are added to the template
353
+ # context only. So you can only use these in templates.
354
+ module TemplateHelpers
292
355
  # Get the full URL to the root of this site
293
356
  def http_prefix
294
357
  return '/' if server? && development?
@@ -309,9 +372,12 @@ class VizBuilder
309
372
  def asset_path(*args)
310
373
  path = args.join('/')
311
374
  page = sitemap[path]
312
- if production? && page[:digest] == true
313
- raise "Missing digest for #{path}" if page[:digest_path].blank?
314
- path = page[:digest_path]
375
+ if production?
376
+ raise "Missing asset #{path}" if page.blank?
377
+ if page[:digest] == true
378
+ raise "Missing digest for #{path}" if page[:digest_path].blank?
379
+ path = page[:digest_path]
380
+ end
315
381
  end
316
382
  asset_http_prefix + path
317
383
  end
@@ -320,40 +386,12 @@ class VizBuilder
320
386
  def canonical_url(*args)
321
387
  http_prefix + args.join('/')
322
388
  end
323
-
324
- # Are we running as a server?
325
- def server?
326
- @mode == :server
327
- end
328
-
329
- # Are we building this app out?
330
- def build?
331
- @mode == :build
332
- end
333
-
334
- # Is this in production?
335
- def production?
336
- @target == :production
337
- end
338
-
339
- # Is this in development?
340
- def development?
341
- @target == :development
342
- end
343
-
344
- # Looks for an invoked method name in locals then in config, so locals
345
- # and config vars can be used as if they're local vars in the template
346
- def method_missing(sym)
347
- return @locals[sym] if @locals.key?(sym)
348
- return config[sym] if config.key?(sym)
349
- super
350
- end
351
-
352
- def respond_to_missing?(sym, *)
353
- @locals.key?(sym) || config.key?(sym) || super
354
- end
355
389
  end
356
390
 
391
+ # The ConfigHelpers modules hold methods that are added to the config block
392
+ # context only. So you can only use these with the config object instance.
393
+ module ConfigHelpers; end
394
+
357
395
  private
358
396
 
359
397
  # Generate one page from the sitemap and save to `build/`
@@ -362,25 +400,35 @@ class VizBuilder
362
400
  out_fname = File.join(BUILD_DIR, path)
363
401
  puts "Rendering #{out_fname}..." unless silent
364
402
 
403
+ # Check if we have a layout defined, use it
404
+ layout = ctx.page['layout'] || config['layout'] || nil
405
+
365
406
  # Check page data for info on how to build this path
366
407
  if ctx.page['template'].present?
367
- content = ctx.render(ctx.page['template'])
368
- elsif ctx.page['json'].present?
369
- content = ctx.page['json'].to_json
370
- elsif ctx.page['yaml'].present?
371
- content = ctx.page['yaml'].to_yaml
372
- elsif ctx.page['file'].present?
373
- content = File.read(ctx.page['file'])
408
+ # Make sure to render the template inside the layout render so code in the
409
+ # erb layout and template are executed in a sensible order.
410
+ content = \
411
+ if layout.present?
412
+ ctx.render(layout) { ctx.render(ctx.page['template']) }
413
+ else
414
+ ctx.render(ctx.page['template'])
415
+ end
374
416
  else
375
- raise(
376
- ArgumentError,
377
- "Page '#{path}' missing one of required attributes: 'template', 'json', 'yaml', 'file'."
378
- )
379
- end
417
+ # Everything else static data and not executable, so we don't have to load
418
+ # the content inside the layout execution.
419
+ if ctx.page['json'].present?
420
+ content = ctx.page['json'].to_json
421
+ elsif ctx.page['file'].present?
422
+ content = File.read(ctx.page['file'])
423
+ else
424
+ raise(
425
+ ArgumentError,
426
+ "Page '#{path}' missing one of required attributes: 'template', 'json', 'file'."
427
+ )
428
+ end
380
429
 
381
- # Check if we have a layout defined, use it
382
- layout_fname = ctx.page['layout'] || config['layout']
383
- content = ctx.render(layout_fname) { content } if layout_fname.present?
430
+ content = ctx.render(layout) { content } if layout.present?
431
+ end
384
432
 
385
433
  # If page data includes a digest flag, add sha1 digest to output filename
386
434
  if ctx.page['digest'] == true
@@ -403,16 +451,17 @@ class VizBuilder
403
451
  def load_data
404
452
  data = {}.with_indifferent_access
405
453
 
406
- Dir.glob("#{DATA_DIR}/*.json") do |fname|
407
- key = File.basename(fname, '.json').to_sym
408
- puts "Loading data[:#{key}] from #{fname}..."
409
- data[key] = JSON.parse(File.read(fname))
410
- end
411
-
412
- Dir.glob("#{DATA_DIR}/*.yaml") do |fname|
413
- key = File.basename(fname, '.yaml').to_sym
414
- puts "Loading data[:#{key}] from #{fname}..."
415
- data[key] = Psych.parse(fname)
454
+ %w[.json .yaml].each do |ext|
455
+ Dir.glob("#{DATA_DIR}/*#{ext}") do |fname|
456
+ key = File.basename(fname, ext).to_sym
457
+ puts "Loading data[:#{key}] from #{fname}..."
458
+ data[key] = \
459
+ if ext == '.json'
460
+ JSON.parse(File.read(fname))
461
+ else
462
+ Psych.parse(fname)
463
+ end
464
+ end
416
465
  end
417
466
 
418
467
  data
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vizbuilder
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Mark
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-30 00:00:00.000000000 Z
11
+ date: 2019-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -146,7 +146,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
146
  - !ruby/object:Gem::Version
147
147
  version: '0'
148
148
  requirements: []
149
- rubygems_version: 3.0.1
149
+ rubyforge_project:
150
+ rubygems_version: 2.7.6.2
150
151
  signing_key:
151
152
  specification_version: 4
152
153
  summary: Simple and fast static site generator