liquidoc 0.7.0 → 0.8.0

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
  SHA1:
3
- metadata.gz: 6066fed122738d3eb82ad92365208357bba0fc97
4
- data.tar.gz: 55acbe02d698fea8c72ebaae61daa8f3a23584cc
3
+ metadata.gz: 680eeb03f5bdca5f09d010b37c2ba8a4fa2f7060
4
+ data.tar.gz: c5b06675ef4d7e2fcdcf5e0e1838295864edf094
5
5
  SHA512:
6
- metadata.gz: 460472382d8369294a1857b16e1444610d540d5805ba95c7ceb72faa46962305720f45fdf7a9d5d65c724cfe541154a0cbf46853ca0a17d914dca62c9314ffac
7
- data.tar.gz: d234c41558f62429e2d23f06bafc01bc9db7302933d9ca5e09f58b0d8679a0a5caf90c80a98564ddc053b47b3aae7ced2d1dd062887d7426747a508906759284
6
+ metadata.gz: 9658b656c88006e9fae3d16e35c00f12132f19a57fc963241650bc5a6b2849ce7efa4198f101c51f319f0b674936d624c29cd67ae5d292082cda773bebe5e77b
7
+ data.tar.gz: d63050fcd42fce26362c7cf9300a75f2a51213da2606e3cfb2fed84792b249c7b9a317da21120dc91194657124e11fdb1e9dc0a2378f0aa41f2046b2382d0f8c
@@ -1,3 +1,3 @@
1
1
  module Liquidoc
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
data/lib/liquidoc.rb CHANGED
@@ -9,6 +9,7 @@ require 'logger'
9
9
  require 'csv'
10
10
  require 'crack/xml'
11
11
  require 'fileutils'
12
+ require 'jekyll'
12
13
 
13
14
  # ===
14
15
  # Table of Contents
@@ -32,6 +33,8 @@ require 'fileutils'
32
33
 
33
34
  @base_dir_def = Dir.pwd + '/'
34
35
  @base_dir = @base_dir_def
36
+ @build_dir_def = @base_dir + '_build'
37
+ @build_dir = @build_dir_def
35
38
  @configs_dir = @base_dir + '_configs'
36
39
  @templates_dir = @base_dir + '_templates/'
37
40
  @data_dir = @base_dir + '_data/'
@@ -43,12 +46,20 @@ require 'fileutils'
43
46
  @attributes = {}
44
47
  @passed_attrs = {}
45
48
  @verbose = false
49
+ @quiet = false
50
+ @explicit = false
46
51
 
52
+ # Instantiate the main Logger object, which is always running
47
53
  @logger = Logger.new(STDOUT)
48
- @logger.level = Logger::INFO
49
54
  @logger.formatter = proc do |severity, datetime, progname, msg|
50
55
  "#{severity}: #{msg}\n"
51
56
  end
57
+ @logger.level = Logger::INFO # suppresses DEBUG-level messages
58
+
59
+
60
+ FileUtils::mkdir_p("#{@build_dir}") unless File.exists?("#{@build_dir}")
61
+ FileUtils::mkdir_p("#{@build_dir}/pre") unless File.exists?("#{@build_dir}/pre")
62
+
52
63
 
53
64
  # ===
54
65
  # Executive procs
@@ -77,6 +88,7 @@ def iterate_build cfg
77
88
  for step in cfg.steps # iterate through each node in the 'config' object, which should start with an 'action' parameter
78
89
  stepcount = stepcount + 1
79
90
  step = BuildConfigStep.new(step) # create an instance of the Action class, validating the top-level step hash (now called 'step') in the process
91
+ @explainer.info step.message
80
92
  type = step.type
81
93
  case type # a switch to evaluate the 'action' parameter for each step in the iteration...
82
94
  when "parse"
@@ -85,7 +97,8 @@ def iterate_build cfg
85
97
  for bld in builds
86
98
  build = Build.new(bld, type) # create an instance of the Build class; Build.new accepts a 'bld' hash & action 'type'
87
99
  if build.template
88
- liquify(data, build.template, build.output) # perform the liquify operation
100
+ @explainer.info build.message
101
+ liquify(data, build.template, build.output, build.variables) # perform the liquify operation
89
102
  else
90
103
  regurgidata(data, build.output)
91
104
  end
@@ -96,12 +109,14 @@ def iterate_build cfg
96
109
  copy_assets(step.source, step.target, inclusive)
97
110
  when "render"
98
111
  validate_file_input(step.source, "source") if step.source
99
- doc = AsciiDocument.new(step.source)
100
- attrs = ingest_attributes(step.data) if step.data # Set attributes in from YAML files
101
- doc.add_attrs!(attrs) # Set attributes from the action-level data file
102
112
  builds = step.builds
103
113
  for bld in builds
114
+ doc = AsciiDocument.new(step.source)
115
+ attrs = ingest_attributes(step.data) if step.data # Set attributes from from YAML files
116
+ doc.add_attrs!(attrs) # Set attributes from the action-level data file
104
117
  build = Build.new(bld, type) # create an instance of the Build class; Build.new accepts a 'bld' hash & action 'type' string
118
+ build.set("backend", derive_backend(doc.type, build.output) ) unless build.backend
119
+ @explainer.info build.message
105
120
  render_doc(doc, build) # perform the render operation
106
121
  end
107
122
  when "deploy"
@@ -145,6 +160,27 @@ def validate_config_structure config
145
160
  # TODO More validation needed
146
161
  end
147
162
 
163
+ def explainer_init out=nil
164
+ unless @explainer
165
+ if out == "STDOUT"
166
+ @explainer = Logger.new(STDOUT)
167
+ else
168
+ out = "#{@build_dir}/pre/config-explainer.adoc" if out.nil?
169
+ File.open(out, 'w') unless File.exists?(out)
170
+ file = File.open(out, File::WRONLY)
171
+ begin
172
+ @explainer = Logger.new(file)
173
+ rescue Exception => ex
174
+ @logger.error ex
175
+ raise "ExplainerCreateError"
176
+ end
177
+ end
178
+ @explainer.formatter = proc do |severity, datetime, progname, msg|
179
+ "#{msg}\n"
180
+ end
181
+ end
182
+ end
183
+
148
184
  # ===
149
185
  # Core classes
150
186
  # ===
@@ -211,10 +247,59 @@ class BuildConfigStep
211
247
  return @step['options']
212
248
  end
213
249
 
250
+ def stage
251
+ return @step['stage']
252
+ end
253
+
214
254
  def builds
215
255
  return @step['builds']
216
256
  end
217
257
 
258
+ def message
259
+ # dynamically build a human-friendly log message, possibly appending a reason
260
+ unless @step['message']
261
+ reason = ", #{@step['reason']}" if @step['reason']
262
+ noninclusively = ", without carrying the parent directory" if self.options.is_a?(Hash) && self.options['inclusive'] == false && File.directory?(self.source)
263
+ stage = "" ; stage = "[#{self.stage}] " if self.stage
264
+ case self.type
265
+ when "migrate"
266
+ text = ". #{stage}Copies `#{self.source}` to `#{self.target}`#{noninclusively}#{reason}."
267
+ when "parse"
268
+ if self.data.is_a? Array
269
+ if self.data.count > 1
270
+ text = ". Draws data from the following files:"
271
+ self.data.each do |file|
272
+ text.concat("\n * `#{file}`.")
273
+ end
274
+ text.concat("\n")
275
+ else
276
+ text = ". #{stage}Draws data from `#{self.data[0]}`"
277
+ end
278
+ else
279
+ text = ". #{stage}Draws data from `#{self.data['file']}`"
280
+ end
281
+ text.concat("#{reason},") if reason
282
+ text.concat(" and parses it as follows:")
283
+ return text
284
+ when "render"
285
+ if self.source
286
+ text = ". #{stage}Using the index file `#{self.source}` as a map#{reason}, and ingesting AsciiDoc attributes from "
287
+ if self.data.is_a? Array
288
+ text.concat("the following data files:")
289
+ self.data.each do |file|
290
+ text.concat("\n * `#{file}`.")
291
+ end
292
+ else
293
+ text.concat("`#{self.data}`")
294
+ end
295
+ return text
296
+ end
297
+ end
298
+ else
299
+ return @step['message']
300
+ end
301
+ end
302
+
218
303
  def validate
219
304
  case self.type
220
305
  when "parse"
@@ -267,6 +352,58 @@ class Build
267
352
  @build['props']
268
353
  end
269
354
 
355
+ def variables
356
+ @build['variables']
357
+ end
358
+
359
+ def message
360
+ # dynamically build a message, possibly appending a reason
361
+ unless @build['message']
362
+ reason = ", #{@build['reason']}" if @build['reason']
363
+ case @type
364
+ when "parse"
365
+ text = ".. Builds `#{self.output}` pressed with the template `#{self.template}`#{reason}."
366
+ when "render"
367
+ case self.backend
368
+ when "pdf"
369
+ text = ".. Uses Asciidoctor/Prawn to generate a PDF file `#{self.output}`"
370
+ text.concat("#{reason}") if reason
371
+ text.concat(".")
372
+ when "html5"
373
+ text = ".. Compiles a standard Asciidoctor HTML5 file, `#{self.output}`"
374
+ text.concat("#{reason}") if reason
375
+ text.concat(".")
376
+ when "jekyll"
377
+ text = ".. Uses Jekyll config files:\n+\n--"
378
+ files = self.props['files']
379
+ if files.is_a? String
380
+ if files.include? ","
381
+ files = files.split(",")
382
+ else
383
+ files = files.split
384
+ end
385
+ else
386
+ unless files.is_a? Array
387
+ @logger.error "The Jekyll configuration file must be a single filename, a comma-separated list of filenames, or an array of filenames."
388
+ end
389
+ end
390
+ files.each do |file|
391
+ text.concat("\n * `#{file}`")
392
+ end
393
+ text.concat("\n\nto generate a static site")
394
+ if self.props && self.props['arguments']
395
+ text.concat(" at `#{self.props['arguments']['destination']}`")
396
+ end
397
+ text.concat("#{reason}") if reason
398
+ text.concat(".\n--\n")
399
+ end
400
+ return text
401
+ end
402
+ else
403
+ @build['message']
404
+ end
405
+ end
406
+
270
407
  def prop_files_array
271
408
  if props
272
409
  if props['files']
@@ -333,7 +470,7 @@ class Build
333
470
  end
334
471
  end
335
472
 
336
- end #class Build
473
+ end # class Build
337
474
 
338
475
  class DataSrc
339
476
  # initialization means establishing a proper hash for the 'data' param
@@ -355,8 +492,12 @@ class DataSrc
355
492
  else
356
493
  if datasrc.is_a? String
357
494
  @datasrc['ext'] = File.extname(datasrc)
358
- else # datasrc is neither string nor hash
359
- raise "InvalidDataSource"
495
+ else
496
+ if datasrc.is_a? Array
497
+
498
+ else
499
+ raise "InvalidDataSource"
500
+ end
360
501
  end
361
502
  end
362
503
  end
@@ -522,9 +663,13 @@ def parse_regex data_file, pattern
522
663
  end
523
664
 
524
665
  # Parse given data using given template, generating given output
525
- def liquify datasrc, template_file, output
666
+ def liquify datasrc, template_file, output, variables=nil
526
667
  data = get_data(datasrc)
527
668
  validate_file_input(template_file, "template")
669
+ if variables
670
+ vars = { "vars" => variables }
671
+ data.merge!vars
672
+ end
528
673
  begin
529
674
  template = File.read(template_file) # reads the template file
530
675
  template = Liquid::Template.parse(template) # compiles template
@@ -546,7 +691,7 @@ def liquify datasrc, template_file, output
546
691
  raise "FileNotBuilt"
547
692
  end
548
693
  if File.exists?(output_file)
549
- @logger.info "File built: #{File.basename(output_file)}"
694
+ @logger.info "File built: #{output_file}"
550
695
  else
551
696
  @logger.error "Hrmp! File not built."
552
697
  raise "FileNotBuilt"
@@ -638,7 +783,11 @@ def ingest_attributes attr_file
638
783
  raise "AttributeBlockError"
639
784
  end
640
785
  begin
641
- attrs.merge!new_attrs
786
+ if new_attrs.is_a? Hash
787
+ attrs.merge!new_attrs
788
+ else
789
+ @logger.warn "The AsciiDoc attributes file #{filename} is not formatted as a hash, so its data was not ingested."
790
+ end
642
791
  rescue Exception => ex
643
792
  raise "AttributesMergeError #{ex.message}"
644
793
  end
@@ -657,7 +806,6 @@ def derive_backend type, out_file
657
806
  end
658
807
 
659
808
  def render_doc doc, build
660
- build.set("backend", derive_backend(doc.type, build.output) ) unless build.backend
661
809
  case build.backend
662
810
  when "html5", "pdf"
663
811
  asciidocify(doc, build)
@@ -734,15 +882,15 @@ def generate_site doc, build
734
882
  attrs.merge!(build.attributes) if build.attributes
735
883
  attrs = {"asciidoctor" => {"attributes" => attrs} }
736
884
  attrs_yaml = attrs.to_yaml # Convert it all back to Yaml, as we're going to write a file to feed back to Jekyll
737
- FileUtils::mkdir_p("build/pre") unless File.exists?("build/pre")
738
- File.open("build/pre/_attributes.yml", 'w') { |file| file.write(attrs_yaml) }
739
- build.add_config_file("build/pre/_attributes.yml")
885
+ File.open("#{@build_dir}/pre/_attributes.yml", 'w') { |file| file.write(attrs_yaml) }
886
+ build.add_config_file("#{@build_dir}/pre/_attributes.yml")
740
887
  config_list = build.prop_files_array.join(',') # flatten the Array back down for the CLI
741
888
  opts_args = ""
889
+ quiet = "--quiet" if @quiet || @explicit
742
890
  if build.props['arguments']
743
891
  opts_args = build.props['arguments'].to_opts_args
744
892
  end
745
- command = "bundle exec jekyll build --config #{config_list} #{opts_args}"
893
+ command = "bundle exec jekyll build --config #{config_list} #{opts_args} #{quiet}"
746
894
  end
747
895
  @logger.info "Running #{command}"
748
896
  @logger.debug "AsciiDoc attributes: #{doc.attributes.to_yaml} "
@@ -839,6 +987,8 @@ end
839
987
 
840
988
  # Extending Liquid filters/text manipulation
841
989
  module CustomFilters
990
+ include Jekyll::Filters
991
+
842
992
  def plainwrap input
843
993
  input.wrap
844
994
  end
@@ -875,7 +1025,7 @@ Liquid::Template.register_filter(CustomFilters)
875
1025
  command_parser = OptionParser.new do|opts|
876
1026
  opts.banner = "Usage: liquidoc [options]"
877
1027
 
878
- opts.on("-a KEY=VALUE", "For passing an AsciiDoc attribute parameter to Asciidoctor. Ex: -a basedir=some/path -a custom_var='my value'") do |n|
1028
+ opts.on("-a KEY=VALUE", "For passing an AsciiDoc attribute parameter to Asciidoctor. Ex: -a imagesdir=some/path -a custom_var='my value'") do |n|
879
1029
  pair = {}
880
1030
  k,v = n.split('=')
881
1031
  pair[k] = v
@@ -884,7 +1034,11 @@ command_parser = OptionParser.new do|opts|
884
1034
 
885
1035
  # Global Options
886
1036
  opts.on("-b PATH", "--base=PATH", "The base directory, relative to this script. Defaults to `.`, or pwd." ) do |n|
887
- @data_file = @base_dir + n
1037
+ @base_dir = n
1038
+ end
1039
+
1040
+ opts.on("-B PATH", "--build=PATH", "The directory under which LiquiDoc should save automatically preprocessed files. Defaults to #{@base_dir}_build. Can be absolute or relative to the base path (-b/--base=). Do NOT append '/' to the build path." ) do |n|
1041
+ @build_dir = n
888
1042
  end
889
1043
 
890
1044
  opts.on("-c", "--config=PATH", "Configuration file, enables preset source, template, and output.") do |n|
@@ -911,17 +1065,25 @@ command_parser = OptionParser.new do|opts|
911
1065
  @template_file = @base_dir + n
912
1066
  end
913
1067
 
914
- opts.on("--verbose", "Run verbose") do |n|
1068
+ opts.on("--verbose", "Run verbose debug logging.") do |n|
915
1069
  @logger.level = Logger::DEBUG
916
1070
  @verbose = true
917
1071
  end
918
1072
 
919
- opts.on("--stdout", "Puts the output in STDOUT instead of writing to a file.") do
920
- @output_type = "stdout"
1073
+ opts.on("--quiet", "Run with only WARN- and error-level logs written to console.") do |n|
1074
+ @logger.level = Logger::WARN
1075
+ @quiet = true
1076
+ end
1077
+
1078
+ opts.on("--explicit", "Log explicit step descriptions to console as build progresses. (Otherwise writes to file at #{@build_dir}/pre/config-explainer.adoc .)") do |n|
1079
+ explainer_init("STDOUT")
1080
+ @explainer.level = Logger::INFO
1081
+ @logger.level = Logger::WARN # Suppress all those INFO-level messages
1082
+ @explicit = true
921
1083
  end
922
1084
 
923
- opts.on("--clean PATH", "Force deletes the designated directory and all its contents WITHOUT WARNING.") do |n|
924
- @clean_dir = n
1085
+ opts.on("--stdout", "Puts the output in STDOUT instead of writing to a file.") do
1086
+ @output_type = "stdout"
925
1087
  end
926
1088
 
927
1089
  opts.on("--deploy", "EXPERIMENTAL: Trigger a jekyll serve operation against the destination dir of a Jekyll render step.") do
@@ -938,21 +1100,21 @@ end
938
1100
  command_parser.parse!
939
1101
 
940
1102
  # Upfront debug output
941
- @logger.debug "Base dir: #{@base_dir}"
942
- @logger.debug "Config file: #{@config_file}"
1103
+ @logger.debug "Base dir: #{@base_dir} (The path from which LiquiDoc CLI commands are relative.)"
1104
+
1105
+ explainer_init
943
1106
 
944
1107
  # ===
945
1108
  # Execute
946
1109
  # ===
947
- if @clean_dir
948
- FileUtils.remove_dir(@clean_dir)
949
- end
1110
+
950
1111
  unless @config_file
1112
+ @logger.debug "Executing config-free build based on API/CLI arguments alone."
951
1113
  if @data_file
952
1114
  liquify(@data_file, @template_file, @output_file)
953
1115
  end
954
1116
  if @index_file
955
- @logger.warn "Publishing via command line arguments not yet implemented. Use a config file."
1117
+ @logger.warn "Rendering via command line arguments is not yet implemented. Use a config file."
956
1118
  end
957
1119
  else
958
1120
  @logger.debug "Executing... config_build"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: liquidoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Dominick
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-05 00:00:00.000000000 Z
11
+ date: 2018-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -51,7 +51,6 @@ files:
51
51
  - bin/liquidoc
52
52
  - lib/liquidoc.rb
53
53
  - lib/liquidoc/version.rb
54
- - lib/yaml_plus.rb
55
54
  homepage: https://github.com/scalingdata/liquidoc
56
55
  licenses:
57
56
  - MIT
data/lib/yaml_plus.rb DELETED
@@ -1,60 +0,0 @@
1
- require 'safe_yaml/load'
2
- module YamlPlus
3
-
4
- def self.parse data
5
- puts data
6
- return
7
- # self.new.load((::SafeYAML.load raw_data), theme_data)
8
- # input_data ||= ::OpenStruct.new
9
- # return input_data unless ::Hash === data
10
- # data.inject(input_data) {|data, (key, val)| process_entry key, val, data }
11
- # input_data.base_align ||= 'left'
12
- # input_data
13
- end
14
-
15
- def process_entry key, val, data
16
- if ::Hash === val
17
- val.each do |key2, val2|
18
- process_entry %(#{key}_#{key2.tr '-', '_'}), val2, data
19
- end
20
- else
21
- data[key] = evaluate val, data
22
- end
23
- data
24
- end
25
-
26
- def evaluate expr, vars
27
- case expr
28
- when ::String
29
- evaluate_math(expand_vars expr, vars)
30
- when ::Array
31
- expr.map {|e| evaluate e, vars }
32
- else
33
- expr
34
- end
35
- end
36
-
37
- def expand_vars expr, vars
38
- if (idx = (expr.index '$'))
39
- if idx == 0 && expr =~ LoneVariableRx
40
- if vars.respond_to? $1
41
- vars[$1]
42
- else
43
- warn %(asciidoctor: WARNING: unknown variable reference: $#{$1})
44
- expr
45
- end
46
- else
47
- expr.gsub(VariableRx) {
48
- if vars.respond_to? $1
49
- vars[$1]
50
- else
51
- warn %(asciidoctor: WARNING: unknown variable reference: $#{$1})
52
- $&
53
- end
54
- }
55
- end
56
- else
57
- expr
58
- end
59
- end
60
- end