liquidoc 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/liquidoc.rb +174 -85
- data/lib/liquidoc/version.rb +1 -1
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c893b7f373640a5bab823899f7236665074b94f2922bbb651fdddc859efffa9
|
4
|
+
data.tar.gz: b4574f73d3829fb88d005c4340917be3297d0bcc345e6a42870f959b9da69c55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1144cb86dcc7644e54f974a6d303e348f23250aa2015bc44a4b24d6e7627218da5485ca0bf09711136047a1f43df8682fdd504d90bd38f34779c8e52a37954e0
|
7
|
+
data.tar.gz: 3914f320195b2e9fe2376ff29d5730a8f17c38518b4f66f5cd6a5ee1a02ed054efe48bc69c25165ed795db2c813532501356db9ca2900ca824136518de9efe82
|
data/lib/liquidoc.rb
CHANGED
@@ -40,6 +40,7 @@ require 'highline'
|
|
40
40
|
@configs_dir = @base_dir + '_configs'
|
41
41
|
@templates_dir = @base_dir + '_templates/'
|
42
42
|
@data_dir = @base_dir + '_data/'
|
43
|
+
@data_file = nil
|
43
44
|
@attributes_file_def = '_data/asciidoctor.yml'
|
44
45
|
@attributes_file = @attributes_file_def
|
45
46
|
@pdf_theme_file = 'theme/pdf-theme.yml'
|
@@ -82,7 +83,9 @@ def config_build config_file, config_vars={}, parse=false
|
|
82
83
|
# If config variables are passed on the CLI, we want to parse the config file
|
83
84
|
# and use the parsed version for the rest fo this routine
|
84
85
|
config_out = "#{@build_dir}/pre/#{File.basename(config_file)}"
|
85
|
-
|
86
|
+
vars = DataObj.new()
|
87
|
+
vars.add_data!("vars", config_vars)
|
88
|
+
liquify(vars, config_file, config_out)
|
86
89
|
config_file = config_out
|
87
90
|
@logger.debug "Config parsed! Using #{config_out} for build."
|
88
91
|
validate_file_input(config_file, "config")
|
@@ -124,18 +127,46 @@ def iterate_build cfg
|
|
124
127
|
type = step.type
|
125
128
|
case type # a switch to evaluate the 'action' parameter for each step in the iteration...
|
126
129
|
when "parse"
|
130
|
+
builds = step.builds
|
131
|
+
data_obj = DataObj.new()
|
127
132
|
if step.data
|
128
|
-
|
133
|
+
data_files = DataFiles.new(step.data)
|
134
|
+
data_files.sources.each do |src|
|
135
|
+
begin
|
136
|
+
data = ingest_data(src) # Extract data from file
|
137
|
+
rescue Exception => ex
|
138
|
+
@logger.error "#{ex.class}: #{ex.message}"
|
139
|
+
raise "DataFileReadFail (#{src.file})"
|
140
|
+
end
|
141
|
+
begin # Create build.data
|
142
|
+
if data_files.sources.size == 1
|
143
|
+
data_obj.add_data!("", data) if data.is_a? Hash
|
144
|
+
# Insert arrays into the data. scope, and for backward compatibility, hashes as well
|
145
|
+
data_obj.add_data!("data", data)
|
146
|
+
else
|
147
|
+
data_obj.add_data!(src.name, data) # Insert object under self-named scope
|
148
|
+
end
|
149
|
+
rescue Exception => ex
|
150
|
+
@logger.error "#{ex.class}: #{ex.message}"
|
151
|
+
raise "DataIngestFail (#{src.file})"
|
152
|
+
end
|
153
|
+
end
|
129
154
|
end
|
130
|
-
builds = step.builds
|
131
155
|
builds.each do |bld|
|
132
|
-
build = Build.new(bld, type) # create an instance of the Build class; Build.new accepts a 'bld' hash & action 'type'
|
156
|
+
build = Build.new(bld, type, data_obj) # create an instance of the Build class; Build.new accepts a 'bld' hash & action 'type'
|
133
157
|
if build.template
|
158
|
+
# Prep & perform a Liquid-parsed build build
|
134
159
|
@explainer.info build.message
|
135
|
-
build.
|
136
|
-
liquify(data, build.template, build.output
|
137
|
-
else
|
138
|
-
|
160
|
+
build.add_data!("vars", build.variables) if build.variables
|
161
|
+
liquify(build.data, build.template, build.output) # perform the liquify operation
|
162
|
+
else # Prep & perform a direct conversion
|
163
|
+
# Delete nested data and vars objects
|
164
|
+
build.data.remove_scope("data")
|
165
|
+
build.data.remove_scope("vars")
|
166
|
+
# Add vars from CLI or config args
|
167
|
+
build.data.add_data!("", build.variables) unless build.variables.empty?
|
168
|
+
build.data.add_data!("", @passed_vars) unless @passed_vars.empty?
|
169
|
+
regurgidata(build.data, build.output)
|
139
170
|
end
|
140
171
|
end
|
141
172
|
when "migrate"
|
@@ -151,7 +182,7 @@ def iterate_build cfg
|
|
151
182
|
builds = step.builds
|
152
183
|
for bld in builds
|
153
184
|
doc = AsciiDocument.new(step.source)
|
154
|
-
attrs = ingest_attributes(step.data) if step.data # Set attributes from
|
185
|
+
attrs = ingest_attributes(step.data) if step.data # Set attributes from YAML files
|
155
186
|
doc.add_attrs!(attrs) # Set attributes from the action-level data file
|
156
187
|
build = Build.new(bld, type) # create an instance of the Build class; Build.new accepts a 'bld' hash & action 'type' string
|
157
188
|
build.set("backend", derive_backend(doc.type, build.output) ) unless build.backend
|
@@ -170,6 +201,10 @@ def iterate_build cfg
|
|
170
201
|
end
|
171
202
|
end
|
172
203
|
|
204
|
+
# ===
|
205
|
+
# Helper procs
|
206
|
+
# ===
|
207
|
+
|
173
208
|
# Verify files exist
|
174
209
|
def validate_file_input file, type
|
175
210
|
@logger.debug "Validating input file for #{type} file #{file}"
|
@@ -401,11 +436,12 @@ end #class Action
|
|
401
436
|
|
402
437
|
class Build
|
403
438
|
|
404
|
-
def initialize build, type
|
439
|
+
def initialize build, type, data=DataObj.new
|
405
440
|
build['attributes'] = Hash.new unless build['attributes']
|
406
441
|
build['props'] = build['properties'] if build['properties']
|
407
442
|
@build = build
|
408
443
|
@type = type
|
444
|
+
@data = data
|
409
445
|
@build['variables'] = {} unless @build['variables']
|
410
446
|
end
|
411
447
|
|
@@ -434,14 +470,23 @@ class Build
|
|
434
470
|
end
|
435
471
|
|
436
472
|
def variables
|
473
|
+
# Variables added in the config build:variables: param
|
474
|
+
# Not for manipulation
|
437
475
|
@build['variables']
|
438
476
|
end
|
439
477
|
|
440
|
-
def
|
441
|
-
|
442
|
-
|
478
|
+
def data
|
479
|
+
@data unless @data.nil?
|
480
|
+
end
|
481
|
+
|
482
|
+
def add_data! obj, scope
|
483
|
+
@data.add_data!(obj, scope)
|
443
484
|
end
|
444
485
|
|
486
|
+
# def vars
|
487
|
+
# self.data['vars']
|
488
|
+
# end
|
489
|
+
|
445
490
|
def message
|
446
491
|
# dynamically build a message, possibly appending a reason
|
447
492
|
unless @build['message']
|
@@ -504,10 +549,6 @@ class Build
|
|
504
549
|
end
|
505
550
|
end
|
506
551
|
|
507
|
-
# def prop_files_list # force the array back to a list of files (for CLI)
|
508
|
-
# props['files'].force_array if props['files']
|
509
|
-
# end
|
510
|
-
|
511
552
|
def search
|
512
553
|
props['search']
|
513
554
|
end
|
@@ -572,31 +613,28 @@ end # class Build
|
|
572
613
|
|
573
614
|
class DataSrc
|
574
615
|
# initialization means establishing a proper hash for the 'data' param
|
575
|
-
def initialize
|
616
|
+
def initialize sources
|
576
617
|
@datasrc = {}
|
577
|
-
@datasrc['file'] =
|
618
|
+
@datasrc['file'] = sources
|
578
619
|
@datasrc['ext'] = ''
|
579
|
-
@datasrc['
|
580
|
-
|
581
|
-
|
582
|
-
@datasrc['
|
583
|
-
|
584
|
-
|
585
|
-
@datasrc['pattern'] = datasrc['pattern']
|
620
|
+
@datasrc['pattern'] = nil
|
621
|
+
if sources.is_a? Hash # data var is a hash, so add 'ext' to it by extracting it from filename
|
622
|
+
@datasrc['file'] = sources['file']
|
623
|
+
@datasrc['ext'] = File.extname(sources['file'])
|
624
|
+
if (defined?(sources['pattern']))
|
625
|
+
@datasrc['pattern'] = sources['pattern']
|
586
626
|
end
|
587
|
-
if (defined?(
|
588
|
-
@datasrc['type'] =
|
627
|
+
if (defined?(sources['type']))
|
628
|
+
@datasrc['type'] = sources['type']
|
589
629
|
end
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
else
|
597
|
-
raise "InvalidDataSource"
|
598
|
-
end
|
630
|
+
elsif sources.is_a? String
|
631
|
+
@datasrc['ext'] = File.extname(sources)
|
632
|
+
elsif sources.is_a? Array
|
633
|
+
sources.each do |src|
|
634
|
+
@datasrc['name'] = File.basename(@datasrc['file'])
|
599
635
|
end
|
636
|
+
else
|
637
|
+
raise "InvalidDataSource"
|
600
638
|
end
|
601
639
|
end
|
602
640
|
|
@@ -608,6 +646,10 @@ class DataSrc
|
|
608
646
|
@datasrc['ext']
|
609
647
|
end
|
610
648
|
|
649
|
+
def name
|
650
|
+
File.basename(self.file,File.extname(self.file))
|
651
|
+
end
|
652
|
+
|
611
653
|
def type
|
612
654
|
if @datasrc['type'] # if we're carrying a 'type' setting for data, pass it along
|
613
655
|
datatype = @datasrc['type']
|
@@ -619,7 +661,7 @@ class DataSrc
|
|
619
661
|
# @logger.error "Data file extension must be one of: .yml, .json, .xml, or .csv or else declared in config file."
|
620
662
|
raise "FileExtensionUnknown"
|
621
663
|
end
|
622
|
-
datatype =
|
664
|
+
datatype = self.ext
|
623
665
|
datatype = datatype[1..-1] # removes leading dot char
|
624
666
|
end
|
625
667
|
unless datatype.downcase.match(/yml|json|xml|csv|regex/) # 'type' must be one of these permitted vals
|
@@ -632,6 +674,68 @@ class DataSrc
|
|
632
674
|
def pattern
|
633
675
|
@datasrc['pattern']
|
634
676
|
end
|
677
|
+
end # class DataSrc
|
678
|
+
|
679
|
+
# DataFiles
|
680
|
+
class DataFiles
|
681
|
+
# Accepts a single String, Hash, or Array
|
682
|
+
# String must be a filename
|
683
|
+
# Hash must contain :file and optionally :type and :pattern
|
684
|
+
# Array must contain filenames as strings
|
685
|
+
# Returns array of DataSrc objects
|
686
|
+
def initialize data_sources
|
687
|
+
@data_sources = []
|
688
|
+
if data_sources.is_a? Array
|
689
|
+
data_sources.each do |src|
|
690
|
+
@data_sources << DataSrc.new(src)
|
691
|
+
end
|
692
|
+
else # data_sources is String or Hash
|
693
|
+
@data_sources[0] = DataSrc.new(data_sources)
|
694
|
+
end
|
695
|
+
@src_class = data_sources.class
|
696
|
+
end
|
697
|
+
|
698
|
+
def sources
|
699
|
+
@data_sources
|
700
|
+
end
|
701
|
+
|
702
|
+
def type
|
703
|
+
# returns the original class of the object used to init this obj
|
704
|
+
@src_class
|
705
|
+
end
|
706
|
+
|
707
|
+
end
|
708
|
+
|
709
|
+
class DataObj
|
710
|
+
# DataObj
|
711
|
+
#
|
712
|
+
# Scoped variables for feeding a Liquid parsing operation
|
713
|
+
def initialize
|
714
|
+
@data = {"vars" => {}}
|
715
|
+
end
|
716
|
+
|
717
|
+
def add_data! scope="", data
|
718
|
+
# Merges data into existing scope or creates a new scope
|
719
|
+
if scope.empty? # store new object at root of this object
|
720
|
+
self.data.merge!data
|
721
|
+
else # store new object as a subordinate, named object
|
722
|
+
if self.data.key?(scope) # merge into existing key
|
723
|
+
self.data[scope].merge!data
|
724
|
+
else # create a new key named after the scope
|
725
|
+
scoped_hash = { scope => data }
|
726
|
+
self.data.merge!scoped_hash
|
727
|
+
end
|
728
|
+
end
|
729
|
+
end
|
730
|
+
|
731
|
+
def data
|
732
|
+
@data
|
733
|
+
end
|
734
|
+
|
735
|
+
def remove_scope scope
|
736
|
+
self.data.delete(scope)
|
737
|
+
end
|
738
|
+
|
635
739
|
end
|
636
740
|
|
637
741
|
class AsciiDocument
|
@@ -660,31 +764,15 @@ class AsciiDocument
|
|
660
764
|
end
|
661
765
|
end
|
662
766
|
|
663
|
-
class AsciiDoctorConfig
|
664
|
-
def initialize out, type, back
|
665
|
-
|
666
|
-
end
|
667
|
-
end
|
668
|
-
|
669
767
|
# ===
|
670
768
|
# Action-specific procs
|
671
769
|
# ===
|
672
770
|
# PARSE-type build procs
|
673
771
|
# ===
|
674
772
|
|
675
|
-
# Get data
|
676
|
-
def get_data datasrc
|
677
|
-
@logger.debug "Executing liquify parsing operation."
|
678
|
-
if datasrc.is_a? String
|
679
|
-
datasrc = DataSrc.new(datasrc)
|
680
|
-
end
|
681
|
-
validate_file_input(datasrc.file, "data")
|
682
|
-
return ingest_data(datasrc)
|
683
|
-
end
|
684
|
-
|
685
773
|
# Pull in a semi-structured data file, converting contents to a Ruby hash
|
686
774
|
def ingest_data datasrc
|
687
|
-
raise "
|
775
|
+
raise "InvalidDataSrcObject" unless datasrc.is_a? DataSrc
|
688
776
|
case datasrc.type
|
689
777
|
when "yml"
|
690
778
|
begin
|
@@ -724,9 +812,6 @@ def ingest_data datasrc
|
|
724
812
|
raise "MissingRegexPattern"
|
725
813
|
end
|
726
814
|
end
|
727
|
-
if data.is_a? Array
|
728
|
-
data = {"data" => data}
|
729
|
-
end
|
730
815
|
return data
|
731
816
|
end
|
732
817
|
|
@@ -757,29 +842,12 @@ def parse_regex data_file, pattern
|
|
757
842
|
end
|
758
843
|
|
759
844
|
# Parse given data using given template, generating given output
|
760
|
-
def liquify
|
761
|
-
if datasrc
|
762
|
-
input = get_data(datasrc)
|
763
|
-
nested = { "data" => get_data(datasrc)}
|
764
|
-
input.merge!nested
|
765
|
-
end
|
766
|
-
if variables
|
767
|
-
if input
|
768
|
-
input.merge!variables
|
769
|
-
else
|
770
|
-
input = variables
|
771
|
-
end
|
772
|
-
end
|
773
|
-
@logger.error "Parse operations need at least a data file or variables." unless input
|
845
|
+
def liquify data_obj, template_file, output
|
774
846
|
validate_file_input(template_file, "template")
|
775
|
-
if variables
|
776
|
-
vars = { "vars" => variables }
|
777
|
-
input.merge!vars
|
778
|
-
end
|
779
847
|
begin
|
780
848
|
template = File.read(template_file) # reads the template file
|
781
849
|
template = Liquid::Template.parse(template) # compiles template
|
782
|
-
rendered = template.render(
|
850
|
+
rendered = template.render(data_obj.data) # renders the output
|
783
851
|
rescue Exception => ex
|
784
852
|
message = "Problem rendering Liquid template. #{template_file}\n" \
|
785
853
|
"#{ex.class} thrown. #{ex.message}"
|
@@ -794,14 +862,33 @@ def liquify datasrc, template_file, output, variables=nil
|
|
794
862
|
end
|
795
863
|
end
|
796
864
|
|
797
|
-
def
|
798
|
-
|
865
|
+
def cli_liquify data_file=nil, template_file=nil, output_file=nil, passed_vars
|
866
|
+
# converts command-line options into liquify or regurgidata inputs
|
867
|
+
data_obj = DataObj.new()
|
868
|
+
if data_file
|
869
|
+
df = DataFiles.new(data_file)
|
870
|
+
ingested = ingest_data(df.sources[0])
|
871
|
+
data_obj.add_data!("", ingested)
|
872
|
+
end
|
873
|
+
if template_file
|
874
|
+
data_obj.add_data!("data", ingested) if df
|
875
|
+
data_obj.add_data!("vars", passed_vars) if passed_vars
|
876
|
+
liquify(data_obj, template_file, output_file)
|
877
|
+
else
|
878
|
+
data_obj.remove_scope("vars")
|
879
|
+
data_obj.add_data!("", passed_vars) if passed_vars
|
880
|
+
regurgidata(data_obj, output_file)
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
884
|
+
def regurgidata data_obj, output
|
885
|
+
# converts data files from one format directly to another
|
799
886
|
raise "UnrecognizedFileExtension" unless File.extname(output).match(/\.yml|\.json|\.xml|\.csv/)
|
800
887
|
case File.extname(output)
|
801
888
|
when ".yml"
|
802
|
-
new_data = data.to_yaml
|
889
|
+
new_data = data_obj.data.to_yaml
|
803
890
|
when ".json"
|
804
|
-
new_data = data.to_json
|
891
|
+
new_data = data_obj.data.to_json
|
805
892
|
when ".xml"
|
806
893
|
@logger.warn "XML output not yet implemented."
|
807
894
|
when ".csv"
|
@@ -809,9 +896,11 @@ def regurgidata datasrc, output
|
|
809
896
|
end
|
810
897
|
if new_data
|
811
898
|
begin
|
812
|
-
|
899
|
+
generate_file(new_data, output)
|
900
|
+
# File.open(output, 'w') { |file| file.write(new_data) }
|
813
901
|
@logger.info "Data converted and saved to #{output}."
|
814
|
-
rescue
|
902
|
+
rescue Exception => ex
|
903
|
+
@logger.error "#{ex.class}: #{ex.message}"
|
815
904
|
raise "FileWriteError"
|
816
905
|
end
|
817
906
|
end
|
@@ -879,7 +968,7 @@ def ingest_attributes attr_file
|
|
879
968
|
begin
|
880
969
|
new_attrs = new_attrs[block_name]
|
881
970
|
rescue
|
882
|
-
raise "InvalidAttributesBlock"
|
971
|
+
raise "InvalidAttributesBlock (#{filename}:#{block_name})"
|
883
972
|
end
|
884
973
|
end
|
885
974
|
rescue Exception => ex
|
@@ -1308,7 +1397,7 @@ explainer_init
|
|
1308
1397
|
unless @config_file
|
1309
1398
|
@logger.debug "Executing config-free build based on API/CLI arguments alone."
|
1310
1399
|
if @data_file
|
1311
|
-
|
1400
|
+
cli_liquify(@data_file, @template_file, @output_file, @passed_vars)
|
1312
1401
|
end
|
1313
1402
|
if @index_file
|
1314
1403
|
@logger.warn "Rendering via command line arguments is not yet implemented. Use a config file."
|
data/lib/liquidoc/version.rb
CHANGED
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: liquidoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.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: 2019-
|
11
|
+
date: 2019-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.15'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.15'
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -197,8 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
197
|
- !ruby/object:Gem::Version
|
198
198
|
version: 2.7.0
|
199
199
|
requirements: []
|
200
|
-
|
201
|
-
rubygems_version: 2.7.6
|
200
|
+
rubygems_version: 3.0.3
|
202
201
|
signing_key:
|
203
202
|
specification_version: 4
|
204
203
|
summary: A highly configurable command-line tool for parsing data and content in common
|