liquidoc 0.12.0.pre.rc5 → 0.12.0.pre.rc6

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.
data/lib/liquidoc.rb CHANGED
@@ -9,9 +9,11 @@ require 'logger'
9
9
  require 'csv'
10
10
  require 'crack/xml'
11
11
  require 'fileutils'
12
- require 'jekyll'
13
12
  require 'open3'
14
13
  require 'highline'
14
+ require 'liquid/tags/jekyll'
15
+ require 'liquid/filters/jekyll'
16
+ require 'sterile'
15
17
 
16
18
  # ===
17
19
  # Table of Contents
@@ -25,7 +27,8 @@ require 'highline'
25
27
  # 5a. parse procs def
26
28
  # 5b. migrate procs def
27
29
  # 5c. render procs def
28
- # 6. text manipulation modules/classes def
30
+ # 5d. execute procs def
31
+ # 6. text manipulation filters
29
32
  # 7. command/option parser def
30
33
  # 8. executive proc calls
31
34
 
@@ -39,6 +42,8 @@ require 'highline'
39
42
  @build_dir = @build_dir_def
40
43
  @configs_dir = @base_dir + '_configs'
41
44
  @templates_dir = @base_dir + '_templates/'
45
+ @includes_dirs_def = ['.','_templates','_templates/liquid','_templates/liquid/ops','_templates/ops','theme/_includes','_theme/layouts']
46
+ @includes_dirs = @includes_dirs_def
42
47
  @data_dir = @base_dir + '_data/'
43
48
  @data_files = nil
44
49
  @attributes_file_def = '_data/asciidoctor.yml'
@@ -79,7 +84,8 @@ FileUtils::mkdir_p("#{@build_dir}/pre") unless File.exists?("#{@build_dir}/pre")
79
84
  def config_build config_file, config_vars={}, data_files=nil, parse=false
80
85
  @logger.debug "Using config file #{config_file}."
81
86
  validate_file_input(config_file, "config")
82
- if config_vars.length > 0 or data_files or parse or contains_liquid(config_file)
87
+ config_base = File.read(config_file)
88
+ if config_vars.length > 0 or data_files or parse or config_base.contains_liquid?
83
89
  @logger.debug "Config_vars: #{config_vars.length}"
84
90
  # If config variables are passed on the CLI, we want to parse the config file
85
91
  # and use the parsed version for the rest fo this routine
@@ -93,8 +99,8 @@ def config_build config_file, config_vars={}, data_files=nil, parse=false
93
99
  liquify(data_obj, config_file, config_out)
94
100
  config_file = config_out
95
101
  @logger.debug "Config parsed! Using #{config_out} for build."
96
- validate_file_input(config_file, "config")
97
102
  end
103
+ validate_file_input(config_file, "config")
98
104
  begin
99
105
  config = YAML.load_file(config_file)
100
106
  rescue Exception => ex
@@ -105,6 +111,8 @@ def config_build config_file, config_vars={}, data_files=nil, parse=false
105
111
  end
106
112
  raise "ConfigFileError"
107
113
  end
114
+ # TESTS
115
+ # puts config[0].argify
108
116
  cfg = BuildConfig.new(config) # convert the config file to a new object called 'cfg'
109
117
  if @safemode
110
118
  commands = ""
@@ -145,6 +153,9 @@ def iterate_build cfg
145
153
  # Prep & perform a Liquid-parsed build
146
154
  @explainer.info build.message
147
155
  build.add_data!(build.variables, "vars") if build.variables
156
+ includes_dirs = @includes_dirs
157
+ includes_dirs = build.includes_dirs if build.includes_dirs
158
+ build.add_data!({:includes_dirs=>includes_dirs})
148
159
  liquify(build.data, build.template, build.output) # perform the liquify operation
149
160
  else # Prep & perform a direct conversion
150
161
  # Delete nested data and vars objects
@@ -152,7 +163,6 @@ def iterate_build cfg
152
163
  build.data.remove_scope("vars")
153
164
  # Add vars from CLI or config args
154
165
  build.data.add_data!(build.variables) unless build.variables.empty?
155
- build.data.add_data!(@passed_vars) unless @passed_vars.empty?
156
166
  regurgidata(build.data, build.output)
157
167
  end
158
168
  end
@@ -169,8 +179,10 @@ def iterate_build cfg
169
179
  builds = step.builds
170
180
  for bld in builds
171
181
  doc = AsciiDocument.new(step.source)
172
- attrs = ingest_attributes(step.data) if step.data # Set attributes from YAML files
173
- doc.add_attrs!(attrs) # Set attributes from the action-level data file
182
+ if step.data
183
+ attrs = ingest_attributes(step.data)
184
+ doc.add_attrs!(attrs) # Set attributes from the action-level data file
185
+ end
174
186
  build = Build.new(bld, type) # create an instance of the Build class; Build.new accepts a 'bld' hash & action 'type' string
175
187
  build.set("backend", derive_backend(doc.type, build.output) ) unless build.backend
176
188
  @explainer.info build.message
@@ -209,31 +221,6 @@ def validate_file_input file, type
209
221
  end
210
222
  end
211
223
 
212
- def validate_config_structure config
213
- unless config.is_a? Array
214
- message = "The configuration file is not properly structured."
215
- @logger.error message
216
- raise "ConfigStructError"
217
- else
218
- if (defined?(config['action'])).nil?
219
- message = "Every listing in the configuration file needs an action type declaration."
220
- @logger.error message
221
- raise "ConfigStructError"
222
- end
223
- end
224
- # TODO More validation needed
225
- end
226
-
227
- def contains_liquid filename
228
- File.open(filename, "r") do |file_proc|
229
- file_proc.each_line do |row|
230
- if row.match(/.*\{\%.*\%\}.*|.*\{\{.*\}\}.*/)
231
- return true
232
- end
233
- end
234
- end
235
- end
236
-
237
224
  def explainer_init out=nil
238
225
  unless @explainer
239
226
  if out == "STDOUT"
@@ -284,12 +271,7 @@ class BuildConfig
284
271
  if (defined?(config['compile'][0])) # The config is formatted for vesions < 0.3.0; convert it
285
272
  config = deprecated_format(config)
286
273
  end
287
-
288
- # validations
289
- unless config.is_a? Array
290
- raise "ConfigStructError"
291
- end
292
-
274
+ validate(config)
293
275
  @cfg = config
294
276
  end
295
277
 
@@ -306,6 +288,13 @@ class BuildConfig
306
288
  return config['compile']
307
289
  end
308
290
 
291
+ def validate config
292
+ unless config.is_a? Array
293
+ raise "ConfigStructError"
294
+ end
295
+ # TODO More validation needed
296
+ end
297
+
309
298
  end #class BuildConfig
310
299
 
311
300
  class BuildConfigStep
@@ -313,7 +302,7 @@ class BuildConfigStep
313
302
  def initialize step
314
303
  @step = step
315
304
  if (defined?(@step['action'])).nil?
316
- raise "ConfigStructError"
305
+ raise "StepStructError"
317
306
  end
318
307
  @step['options'] = nil unless defined?(step['options'])
319
308
  validate()
@@ -414,7 +403,7 @@ class BuildConfigStep
414
403
  for req in reqs
415
404
  if (defined?(@step[req])).nil?
416
405
  @logger.error "Every #{@step['action']}-type in the configuration file needs a '#{req}' declaration."
417
- raise "ConfigStructError"
406
+ raise "ConfigStepError"
418
407
  end
419
408
  end
420
409
  end
@@ -436,6 +425,10 @@ class Build
436
425
  @build['template']
437
426
  end
438
427
 
428
+ def includes_dirs
429
+ @build['includes_dirs']
430
+ end
431
+
439
432
  def output
440
433
  @build['output']
441
434
  end
@@ -645,14 +638,14 @@ class DataSrc
645
638
  datatype = "yml"
646
639
  end
647
640
  else # If there's no 'type' defined, extract it from the filename and validate it
648
- unless @datasrc['ext'].downcase.match(/\.yml|\.json|\.xml|\.csv/)
641
+ unless @datasrc['ext'].downcase.match(/\.yml|\.json|\.xml|\.csv|\.adoc/)
649
642
  # @logger.error "Data file extension must be one of: .yml, .json, .xml, or .csv or else declared in config file."
650
643
  raise "FileExtensionUnknown"
651
644
  end
652
645
  datatype = self.ext
653
646
  datatype = datatype[1..-1] # removes leading dot char
654
647
  end
655
- unless datatype.downcase.match(/yml|json|xml|csv|regex/) # 'type' must be one of these permitted vals
648
+ unless datatype.downcase.match(/yml|json|xml|csv|regex|adoc/) # 'type' must be one of these permitted vals
656
649
  # @logger.error "Declared data type must be one of: yaml, json, xml, csv, or regex."
657
650
  raise "DataTypeUnrecognized"
658
651
  end
@@ -833,6 +826,13 @@ def ingest_data datasrc
833
826
  @logger.error "You must supply a regex pattern with your free-form data file."
834
827
  raise "MissingRegexPattern"
835
828
  end
829
+ when "adoc"
830
+ begin
831
+ doc = Asciidoctor.load_file(datasrc.file)
832
+ data = doc.attributes
833
+ rescue
834
+ @logger.error "Problem with AsciiDoc source file. Attributes not ingested."
835
+ end
836
836
  end
837
837
  return data
838
838
  end
@@ -864,8 +864,10 @@ def parse_regex data_file, pattern
864
864
  end
865
865
 
866
866
  # Parse given data using given template, generating given output
867
- def liquify data_obj, template_file, output
867
+ def liquify data_obj, template_file, output="stdout"
868
868
  validate_file_input(template_file, "template")
869
+ # inject :includes_dirs as needed
870
+ data_obj.add_data!({'includes_dirs' => @includes_dirs}) unless data_obj.data['includes_dirs']
869
871
  begin
870
872
  template = File.read(template_file) # reads the template file
871
873
  template = Liquid::Template.parse(template) # compiles template
@@ -876,11 +878,11 @@ def liquify data_obj, template_file, output
876
878
  @logger.error message
877
879
  raise message
878
880
  end
879
- unless output.downcase == "stdout"
881
+ unless output == "stdout" || @output_type == "stdout"
880
882
  output_file = output
881
883
  generate_file(rendered, output_file)
882
884
  else # if stdout
883
- puts "========\nOUTPUT: Rendered with template #{template_file}:\n\n#{rendered}\n"
885
+ puts rendered
884
886
  end
885
887
  end
886
888
 
@@ -908,7 +910,7 @@ def cli_liquify data_files=nil, template_file=nil, output_file=nil, passed_vars
908
910
  end
909
911
 
910
912
  def regurgidata data_obj, output
911
- # converts data files from one format directly to another
913
+ # converts data object from one format directly to another
912
914
  raise "UnrecognizedFileExtension" unless File.extname(output).match(/\.yml|\.json|\.xml|\.csv/)
913
915
  case File.extname(output)
914
916
  when ".yml"
@@ -923,7 +925,6 @@ def regurgidata data_obj, output
923
925
  if new_data
924
926
  begin
925
927
  generate_file(new_data, output)
926
- # File.open(output, 'w') { |file| file.write(new_data) }
927
928
  @logger.info "Data converted and saved to #{output}."
928
929
  rescue Exception => ex
929
930
  @logger.error "#{ex.class}: #{ex.message}"
@@ -1144,7 +1145,7 @@ def jekyll_serve build
1144
1145
  @logger.debug "Attempting Jekyll serve operation."
1145
1146
  config_file = build.props['files'][0]
1146
1147
  if build.props['arguments']
1147
- opts_args = build.props['arguments'].to_opts_args
1148
+ opts_args = build.props['arguments'].argify
1148
1149
  end
1149
1150
  command = "bundle exec jekyll serve --config #{config_file} #{opts_args} --no-watch --skip-initial-build"
1150
1151
  system command
@@ -1186,7 +1187,7 @@ def execute_command cmd
1186
1187
  contents = stdout
1187
1188
  if cmd.options['outfile']
1188
1189
  contents = "#{cmd.options['outfile']['prepend']}\n#{stdout}" if cmd.options['outfile']['prepend']
1189
- contents = "#{stdout}/n#{cmd.options['outfile']['append']}" if cmd.options['outfile']['append']
1190
+ contents = "#{stdout}\n#{cmd.options['outfile']['append']}" if cmd.options['outfile']['append']
1190
1191
  generate_file(contents, cmd.options['outfile']['path'])
1191
1192
  end
1192
1193
  if cmd.options['stdout']
@@ -1200,24 +1201,6 @@ end
1200
1201
  # Text manipulation Classes, Modules, procs, etc
1201
1202
  # ===
1202
1203
 
1203
- module HashMash
1204
-
1205
- def to_opts_args
1206
- out = ''
1207
- if self.is_a? Hash # TODO Should also be testing for flatness
1208
- self.each do |opt,arg|
1209
- out = out + " --#{opt} #{arg}"
1210
- end
1211
- end
1212
- return out
1213
- end
1214
-
1215
- end
1216
-
1217
- class Hash
1218
- include HashMash
1219
- end
1220
-
1221
1204
  module ForceArray
1222
1205
  # So we can accept a list string ("item1.yml,item2.yml") or a single item ("item1.yml")
1223
1206
  # and convert to array as needed
@@ -1231,73 +1214,361 @@ module ForceArray
1231
1214
  obj = Array.new.push(obj)
1232
1215
  end
1233
1216
  else
1234
- raise "ForceArrayFail"
1217
+ if obj.class == Hash
1218
+ obj = obj.to_array
1219
+ else
1220
+ raise "ForceArrayFail"
1221
+ end
1235
1222
  end
1236
1223
  end
1237
1224
  return obj.to_ary
1238
1225
  end
1239
1226
 
1227
+ def force_array!
1228
+ self.force_array
1229
+ end
1230
+
1240
1231
  end
1241
1232
 
1242
1233
  class String
1243
1234
  include ForceArray
1244
- # Adapted from Nikhil Gupta
1245
- # http://nikhgupta.com/code/wrapping-long-lines-in-ruby-for-display-in-source-files/
1235
+ # Adapted from Nikhil Gupta
1236
+ # http://nikhgupta.com/code/wrapping-long-lines-in-ruby-for-display-in-source-files/
1246
1237
  def wrap options = {}
1247
- width = options.fetch(:width, 76)
1248
- commentchar = options.fetch(:commentchar, '')
1238
+ width = options.fetch(:width, 76) # length to wrap at
1239
+ pre = options.fetch(:prepend, '') # text to prepend
1240
+ app = options.fetch(:append, '') # text to append
1241
+ chars = pre.size + app.size
1249
1242
  self.strip.split("\n").collect do |line|
1250
- line.length > width ? line.gsub(/(.{1,#{width}})(\s+|$)/, "\\1\n#{commentchar}") : line
1251
- end.map(&:strip).join("\n#{commentchar}")
1243
+ line.length + chars.size > width ? line.gsub(/(.{1,#{(width - chars)}})(\s+|$)/, "#{pre}\\1#{app}\n") : "#{pre}#{line}#{app}\n"
1244
+ end.map(&:rstrip).join("\n")
1252
1245
  end
1253
1246
 
1254
1247
  def indent options = {}
1255
- spaces = " " * options.fetch(:spaces, 4)
1256
- self.gsub(/^/, spaces).gsub(/^\s*$/, '')
1248
+ # TODO: does not allow tabs; inserts explicit `\t` string
1249
+ syms = options.fetch(:sym, ' ') * options.fetch(:by, 2)
1250
+ self.gsub!(/^/m, "#{syms}")
1251
+ self.sub!("#{syms}", "") unless options.fetch(:line1, false)
1252
+ end
1253
+
1254
+ def contains_liquid?
1255
+ self.each_line do |row|
1256
+ if row.match(/.*\{\%.*\%\}.*|.*\{\{.*\}\}.*/)
1257
+ return true
1258
+ end
1259
+ end
1260
+ return false
1257
1261
  end
1258
1262
 
1259
- def indent_with_wrap options = {}
1260
- spaces = options.fetch(:spaces, 4)
1261
- width = options.fetch(:width, 80)
1262
- width = width > spaces ? width - spaces : 1
1263
- self.wrap(width: width).indent(spaces: spaces)
1263
+ def quote_wrap options = {}
1264
+ # When a string contains a certain pattern, wrap it in certain quotes
1265
+ # Pass '\s' as pattern to wrap any string that contains 1 or more spaces or tabs
1266
+ # pass '.' as pattern to always wrap.
1267
+
1268
+ pattern = options.fetch(:pattern, '\s').to_s
1269
+ return self unless self.strip.match(/\s/)
1270
+ quotes = options.fetch(:quotes, "single")
1271
+ case quotes
1272
+ when "single"
1273
+ wrap = "''"
1274
+ when "double"
1275
+ wrap = '""'
1276
+ when "backtick"
1277
+ wrap = "``"
1278
+ when "bracket"
1279
+ wrap = "[]"
1280
+ else
1281
+ wrap = quotes
1282
+ end
1283
+ quotes << wrap[0] unless wrap[1]
1284
+ return wrap[0] + self.strip + wrap[1]
1264
1285
  end
1265
1286
 
1266
1287
  end
1267
1288
 
1268
1289
  class Array
1269
1290
  include ForceArray
1291
+
1292
+ def to_hash
1293
+ struct = {}
1294
+ self.each do |p|
1295
+ struct.merge!p if p.is_a? Hash
1296
+ end
1297
+ return struct
1298
+ end
1299
+
1300
+ # Get all unique values for each item in an array, or each unique value of a desigated
1301
+ # parameter in an array of hashes.
1302
+ #
1303
+ # @input : the object array
1304
+ # @property : (optional) parameter in which to select unique values (for hashes)
1305
+ def unique_property_values property=nil
1306
+ return self.uniq unless property
1307
+ new_ary = self.uniq { |i| i[property] }
1308
+ out = new_ary.map { |i| i[property] }.compact
1309
+ out
1310
+ end
1311
+
1312
+ def concatenate_property_instances property=String
1313
+ # flattens the values of instances of a given property throughout an array of Hashes
1314
+ all_arrays = []
1315
+ self.each do |i|
1316
+ all_arrays << i[property]
1317
+ end
1318
+ return all_arrays.flatten
1319
+ end
1320
+
1321
+ def repeated_property_values property=String
1322
+ # testing for uniqueness globally among all values in subarrays (list-formatted values) of all instances of the property across all nodes in the parent array
1323
+ # returns an array of duplicate items among all the tested arrays
1324
+ #
1325
+ # Example:
1326
+ # array_of_hashes[0]['cue'] = ['one','two','three']
1327
+ # array_of_hashes[1]['cue'] = ['three','four','five']
1328
+ # array_of_hashes.duplicate_property_values('cue')
1329
+ # #=> ['three']
1330
+ # Due to the apperance of 'three' in both instances of cue.
1331
+ firsts = []
1332
+ dupes = []
1333
+ self.each do |node|
1334
+ return ['non-array property value present'] unless node[property].is_a? Array
1335
+ node[property].each do |i|
1336
+ dupes << i if firsts.include? i
1337
+ firsts << i
1338
+ end
1339
+ end
1340
+ return dupes
1341
+ end
1342
+
1343
+ end
1344
+
1345
+ class Hash
1346
+ include ForceArray
1347
+
1348
+ def to_array op=nil
1349
+ # Converts a hash of key-value pairs to a flat array based on the first tier
1350
+ out = []
1351
+ self.each do |k,v|
1352
+ v = "<RemovedObject>" if v.is_a? Enumerable and op == "flatten"
1353
+ out << {k => v}
1354
+ end
1355
+ return out
1356
+ end
1357
+
1358
+ def argify options = {}
1359
+ # Converts a hash of key-value pairs to command-line option/argument listings
1360
+ # Can be called with optional arguments:
1361
+ # template :: Liquid-formatted parsing template string
1362
+ # Accepts:
1363
+ #
1364
+ # 'hyph' :: -<key> <value>
1365
+ # 'hyphhyph' :: --<key> <value> (default)
1366
+ # 'hyphchar' :: -<k> <value>
1367
+ # 'dump' :: <key> <value>
1368
+ # 'paramequal' :: <key>=<value>
1369
+ # 'valonly' :: <value>
1370
+ # delim :: Delimiter -- any ASCII characters that separate the arguments
1371
+ #
1372
+ # For template-based usage, express the variables:
1373
+ # opt (the keyname) as {{opt}}
1374
+ # arg (the value) as {{arg}}
1375
+ # EXAMPLES (my_hash = {"key1"=>"val1", "key2"=>"val2"})
1376
+ # my_hash.argify #=> key1 val1 key2 val2
1377
+ # my_hash.argify('hyphhyph') #=> --key1 val1 --key2 val2
1378
+ # my_hash.argify('paramequal') #=> key1=val1 key2=val2
1379
+ # my_hash.argify('-a {{opt}}={{arg}}')#=> -a key1=val1 -a key2=val2
1380
+ # my_hash.argify('valonly', '||') #=> val1||val2
1381
+ # my_hash.argify("{{opt}} `{{arg}}`") #=> key1 `val1` key2 `val2`
1382
+ raise "InvalidObject" unless self.is_a? Hash
1383
+ template = options.fetch(:template, 'hyphhyph')
1384
+ if template.contains_liquid?
1385
+ tp = template # use the passed Liquid template
1386
+ else
1387
+ case template # use a preset Liquid template by name
1388
+ when "dump"
1389
+ tp = "{{opt}} {{arg | quote_wrap: 'single', '\s|,' }}"
1390
+ when "hyph"
1391
+ tp = "-{{opt}} {{arg | quote_wrap: 'single', '\s|,' }}"
1392
+ when "hyphhyph"
1393
+ tp = "--{{opt}} {{arg | quote_wrap: 'single', '\s|,' }}"
1394
+ when "paramequal"
1395
+ tp = "{{opt}}={{arg | quote_wrap: 'single', '\s|,' }}"
1396
+ when "valonly"
1397
+ tp = "{{arg | quote_wrap: 'single', '\s|,' }}"
1398
+ else
1399
+ return "Liquid: Unrecognized argify template name: #{template}"
1400
+ end
1401
+ end
1402
+ begin
1403
+ tpl = Liquid::Template.parse(tp)
1404
+ first = true
1405
+ out = ''
1406
+ self.each do |k,v|
1407
+ # establish datasource
1408
+ v = "<Object>" if v.is_a? Hash
1409
+ v = v.join(',') if v.is_a? Array
1410
+ input = {"opt" => k.to_s, "arg" => v.to_s }
1411
+ if first
1412
+ dlm = ""
1413
+ first = false
1414
+ else
1415
+ dlm = options.fetch(:delim, ' ')
1416
+ end
1417
+ out += dlm + tpl.render(input)
1418
+ end
1419
+ rescue
1420
+ raise "Argify template processing failed"
1421
+ end
1422
+ return out
1423
+ end
1424
+
1425
+
1270
1426
  end
1271
1427
 
1272
1428
  # Extending Liquid filters/text manipulation
1273
- module CustomFilters
1429
+ module LiquiDocFilters
1274
1430
  include Jekyll::Filters
1431
+ #
1432
+ # sterile-based filters
1433
+ #
1434
+
1435
+ def to_slug input, delim='-'
1436
+ o = input.dup
1437
+ opts = {:delimiter=>delim}
1438
+ o.to_slug(opts)
1439
+ end
1440
+
1441
+ def transliterate input
1442
+ o = input.dup
1443
+ o.transliterate
1444
+ end
1445
+
1446
+ def smart_format input
1447
+ o = input.dup
1448
+ o.smart_format
1449
+ end
1450
+
1451
+ def encode_entities input
1452
+ o = input.dup
1453
+ o.encode_entities
1454
+ end
1275
1455
 
1276
- def plainwrap input
1277
- input.wrap
1456
+ def titlecase input
1457
+ o = input.dup
1458
+ o.titlecase
1278
1459
  end
1279
- def commentwrap input
1280
- input.wrap commentchar: "# "
1460
+
1461
+ def strip_tags input
1462
+ o = input.dup
1463
+ o.strip_tags
1464
+ end
1465
+
1466
+ def sterilize input
1467
+ o = input.dup
1468
+ o.sterilize
1281
1469
  end
1282
- def unwrap input # Not fully functional; inserts explicit '\n'
1470
+
1471
+ #
1472
+ # Custom Filters
1473
+ #
1474
+
1475
+ def where_uniq input, property, value
1476
+ o = input.where(input, property, value)
1477
+ o[0] if o.size == 1
1478
+ "No result" unless o.size
1479
+ "Multiple results" if o.size > 1
1480
+ end
1481
+
1482
+ def wrap input, width=80, prepend='', append='', vent=false
1483
+ input.wrap(:width => width, :prepend => prepend, :append => append)
1484
+ end
1485
+
1486
+ def plainwrap input, width=80
1487
+ input.wrap(:width => width)
1488
+ end
1489
+
1490
+ def commentwrap input, width=80, prepend='# '
1491
+ input.wrap(:width => width, :pre => prepend)
1492
+ end
1493
+
1494
+ def unwrap input, token1='&g59h%j1k;', token2='&ru8sf%df;'
1283
1495
  if input
1284
- token = "[g59hj1k]"
1285
- input.gsub(/\n\n/, token).gsub(/\n/, ' ').gsub(token, "\n\n")
1496
+ input.gsub(/(.)\n\n/, "\\1#{token1}").gsub(/([\."'])$\n([A-Z\(\_"'])/,"\\1#{token2}\\2").gsub(/\n/, '').gsub(token2,"\n").gsub(token1, "\n\n")
1286
1497
  end
1287
1498
  end
1288
1499
 
1289
- def slugify input
1290
- # Downcase
1291
- # Turn unwanted chars into the seperator
1500
+ def indent_lines input, by=2, sym=' ', line1=false
1501
+ input.indent(:by => by, :sym => "#{sym}", :line1 => line1)
1502
+ end
1503
+
1504
+ def slugify input, delim='-', snip=false
1292
1505
  s = input.to_s.downcase
1293
- s.gsub!(/[^a-zA-Z0-9\-_\+\/]+/i, "-")
1506
+ s.gsub!(/[^a-z0-9]/, delim)
1507
+ if snip
1508
+ while s.match("#{delim}#{delim}")
1509
+ s.gsub!("#{delim}#{delim}", "#{delim}")
1510
+ end
1511
+ s.gsub!(/^#{delim}+(.*)$/, "\\1")
1512
+ s.gsub!(/^(.*)#{delim}+$/, "\\1")
1513
+ end
1294
1514
  s
1295
1515
  end
1296
1516
 
1517
+ def asciidocify input
1518
+ Asciidoctor.convert(input, doctype: "inline")
1519
+ end
1520
+
1521
+ def quote_wrap input, quotes="''", pattern="\s"
1522
+ input.quote_wrap(:quotes => quotes, :pattern => pattern)
1523
+ end
1524
+
1525
+ def to_cli_args input, template="paramequal", delim=" "
1526
+ input.argify(:template => template, :delim => delim)
1527
+ end
1528
+
1529
+ def hash_to_array input, op=nil
1530
+ o = input.dup
1531
+ o.to_array(op)
1532
+ end
1533
+
1534
+ def holds_liquid input
1535
+ o = false
1536
+ o = true if input.contains_liquid?
1537
+ o
1538
+ end
1539
+
1540
+ def store_list_uniq input, property=nil
1541
+ input.unique_property_values(property)
1542
+ end
1543
+
1544
+ def store_list_concat input, property=String
1545
+ input.concatenate_property_instances(property)
1546
+ end
1547
+
1548
+ def store_list_dupes input, property=String
1549
+ input.repeated_property_values(property)
1550
+ end
1551
+
1297
1552
  def regexreplace input, regex, replacement=''
1553
+ # deprecated in favor of re_replace as of 0.12.0
1298
1554
  input.to_s.gsub(Regexp.new(regex), replacement.to_s)
1299
1555
  end
1300
1556
 
1557
+ def replace_regex input, regex, replacement='', multiline=true, global=true
1558
+ pattern = Regexp.new(regex, Regexp::MULTILINE) if multiline
1559
+ pattern = Regexp.new(regex) unless multiline
1560
+ o = input.to_s.gsub(pattern, replacement.to_s) if global
1561
+ o = input.to_s.sub(pattern, replacement.to_s) unless global
1562
+ o
1563
+ end
1564
+
1565
+ def match input, regex, multiline=true, global=true
1566
+ pattern = Regexp.new(regex, Regexp::MULTILINE) if multiline
1567
+ pattern = Regexp.new(regex) unless multiline
1568
+ return true if input.to_s.match(pattern)
1569
+ return false
1570
+ end
1571
+
1301
1572
  def to_yaml input
1302
1573
  o = input.to_yaml
1303
1574
  o = o.gsub(/^\-\-\-$\n/, "")
@@ -1310,8 +1581,8 @@ module CustomFilters
1310
1581
  end
1311
1582
  end
1312
1583
 
1313
- # register custom Liquid filters
1314
- Liquid::Template.register_filter(CustomFilters)
1584
+ # Register custom Liquid filters
1585
+ Liquid::Template.register_filter(LiquiDocFilters)
1315
1586
 
1316
1587
  # ===
1317
1588
  # Command/options parser
@@ -1331,15 +1602,15 @@ command_parser = OptionParser.new do|opts|
1331
1602
  end
1332
1603
 
1333
1604
  # Global Options
1334
- opts.on("-b PATH", "--base=PATH", "The base directory, relative to this script. Defaults to `.`, or pwd." ) do |n|
1605
+ opts.on("-b PATH", "--base PATH", "The base directory, relative to this script. Defaults to `.`, or pwd." ) do |n|
1335
1606
  @base_dir = n
1336
1607
  end
1337
1608
 
1338
- 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|
1609
+ 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|
1339
1610
  @build_dir = n
1340
1611
  end
1341
1612
 
1342
- opts.on("-c", "--config=PATH", "Configuration file, enables preset source, template, and output.") do |n|
1613
+ opts.on("-c", "--config PATH", "Configuration file, enables preset source, template, and output.") do |n|
1343
1614
  @config_file = @base_dir + n
1344
1615
  end
1345
1616
 
@@ -1349,11 +1620,11 @@ command_parser = OptionParser.new do|opts|
1349
1620
  @data_files = DataFiles.new(data_files)
1350
1621
  end
1351
1622
 
1352
- opts.on("-f PATH", "--from=PATH", "Directory to copy assets from." ) do |n|
1623
+ opts.on("-f PATH", "--from PATH", "Directory to copy assets from." ) do |n|
1353
1624
  @attributes_file = n
1354
1625
  end
1355
1626
 
1356
- opts.on("-i PATH", "--index=PATH", "An AsciiDoc index file for mapping an Asciidoctor build." ) do |n|
1627
+ opts.on("-i PATH", "--index PATH", "An AsciiDoc index file for mapping an Asciidoctor build." ) do |n|
1357
1628
  @index_file = n
1358
1629
  end
1359
1630
 
@@ -1361,10 +1632,16 @@ command_parser = OptionParser.new do|opts|
1361
1632
  @output = @base_dir + n
1362
1633
  end
1363
1634
 
1364
- opts.on("-t PATH", "--template=PATH", "Path to liquid template. Required unless --configuration is called." ) do |n|
1635
+ opts.on("-t PATH", "--template PATH", "Path to liquid template. Required unless --configuration is called." ) do |n|
1365
1636
  @template_file = @base_dir + n
1366
1637
  end
1367
1638
 
1639
+ opts.on("--includes PATH[,PATH]", "Paths to directories where includes (partials) can be found." ) do |n|
1640
+ n = n.force_array
1641
+ # n.map { |p| @base_dir + p }
1642
+ @includes_dirs = @includes_dirs.concat n
1643
+ end
1644
+
1368
1645
  opts.on("--verbose", "Run verbose debug logging.") do |n|
1369
1646
  @logger.level = Logger::DEBUG
1370
1647
  @verbose = true