liquidoc 0.2.0 → 0.3.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 +4 -4
- data/lib/liquidoc.rb +311 -133
- data/lib/liquidoc/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9adb50baa6b3a7c4f31b2de0cc7888bdb69e798f
|
4
|
+
data.tar.gz: '0392150cfd9c8a5b2ea35ac16116e1ae519bd874'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2762bc4215573e07f60bcc88d91c2fd2b62dc9995be94ac29b89fd96ec9f214d4135f6f7d66239b99acf3ee4fff57b21d3a599e54d14298073cd287ac4b96a95
|
7
|
+
data.tar.gz: b0c252cbc74af8f56ffdd03718713a7a193d9da94caa110cc68abd5a7f58e917ea611031b939aaca8a456a370f8da3a3fc13e770605279a60dbad22fff681c84
|
data/lib/liquidoc.rb
CHANGED
@@ -8,15 +8,32 @@ require 'logger'
|
|
8
8
|
require 'csv'
|
9
9
|
require 'crack/xml'
|
10
10
|
|
11
|
+
# ===
|
12
|
+
# Table of Contents
|
13
|
+
# ===
|
14
|
+
#
|
15
|
+
# 1. dependencies stack
|
16
|
+
# 2. default settings
|
17
|
+
# 3. general methods
|
18
|
+
# 4. object classes
|
19
|
+
# 5. action-specific methods
|
20
|
+
# 5a. parse methods
|
21
|
+
# 5b. migrate methods
|
22
|
+
# 5c. render methods
|
23
|
+
# 6. text manipulation
|
24
|
+
# 7. command/option parser
|
25
|
+
# 8. executive method calls
|
26
|
+
|
27
|
+
# ===
|
11
28
|
# Default settings
|
29
|
+
# ===
|
30
|
+
|
12
31
|
@base_dir_def = Dir.pwd + '/'
|
13
32
|
@base_dir = @base_dir_def
|
14
33
|
@configs_dir = @base_dir + '_configs'
|
15
34
|
@templates_dir = @base_dir + '_templates/'
|
16
35
|
@data_dir = @base_dir + '_data/'
|
17
36
|
@output_dir = @base_dir + '_output/'
|
18
|
-
@config_file_def = @base_dir + '_configs/cfg-sample.yml'
|
19
|
-
@config_file = @config_file_def
|
20
37
|
@attributes_file_def = '_data/asciidoctor.yml'
|
21
38
|
@attributes_file = @attributes_file_def
|
22
39
|
@pdf_theme_file = 'theme/pdf-theme.yml'
|
@@ -31,73 +48,10 @@ require 'crack/xml'
|
|
31
48
|
end
|
32
49
|
|
33
50
|
# ===
|
34
|
-
#
|
51
|
+
# Executive methods
|
35
52
|
# ===
|
36
53
|
|
37
|
-
# Pull in a semi-structured data file, converting contents to a Ruby hash
|
38
|
-
def get_data data
|
39
|
-
# data must be a hash produced by data_hashify()
|
40
|
-
if data['type']
|
41
|
-
if data['type'].downcase == "yaml"
|
42
|
-
data['type'] = "yml"
|
43
|
-
end
|
44
|
-
unless data['type'].downcase.match(/yml|json|xml|csv|regex/)
|
45
|
-
@logger.error "Declared data type must be one of: yaml, json, xml, csv, or regex."
|
46
|
-
raise "DataTypeUnrecognized"
|
47
|
-
end
|
48
|
-
else
|
49
|
-
unless data['ext'].match(/\.yml|\.json|\.xml|\.csv/)
|
50
|
-
@logger.error "Data file extension must be one of: .yml, .json, .xml, or .csv or else declared in config file."
|
51
|
-
raise "FileExtensionUnknown (#{data[ext]})"
|
52
|
-
end
|
53
|
-
data['type'] = data['ext']
|
54
|
-
data['type'].slice!(0) # removes leading dot char
|
55
|
-
end
|
56
|
-
case data['type']
|
57
|
-
when "yml"
|
58
|
-
begin
|
59
|
-
return YAML.load_file(data['file'])
|
60
|
-
rescue Exception => ex
|
61
|
-
@logger.error "There was a problem with the data file. #{ex.message}"
|
62
|
-
end
|
63
|
-
when "json"
|
64
|
-
begin
|
65
|
-
return JSON.parse(File.read(data['file']))
|
66
|
-
rescue Exception => ex
|
67
|
-
@logger.error "There was a problem with the data file. #{ex.message}"
|
68
|
-
end
|
69
|
-
when "xml"
|
70
|
-
begin
|
71
|
-
data = Crack::XML.parse(File.read(data['file']))
|
72
|
-
return data['root']
|
73
|
-
rescue Exception => ex
|
74
|
-
@logger.error "There was a problem with the data file. #{ex.message}"
|
75
|
-
end
|
76
|
-
when "csv"
|
77
|
-
output = []
|
78
|
-
i = 0
|
79
|
-
begin
|
80
|
-
CSV.foreach(data['file'], headers: true, skip_blanks: true) do |row|
|
81
|
-
output[i] = row.to_hash
|
82
|
-
i = i+1
|
83
|
-
end
|
84
|
-
output = {"data" => output}
|
85
|
-
return output
|
86
|
-
rescue
|
87
|
-
@logger.error "The CSV format is invalid."
|
88
|
-
end
|
89
|
-
when "regex"
|
90
|
-
if data['pattern']
|
91
|
-
return parse_regex(data['file'], data['pattern'])
|
92
|
-
else
|
93
|
-
@logger.error "You must supply a regex pattern with your free-form data file."
|
94
|
-
raise "MissingRegexPattern"
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
54
|
# Establish source, template, index, etc details for build jobs from a config file
|
100
|
-
# TODO This needs to be turned into a Class?
|
101
55
|
def config_build config_file
|
102
56
|
@logger.debug "Using config file #{config_file}."
|
103
57
|
validate_file_input(config_file, "config")
|
@@ -105,40 +59,38 @@ def config_build config_file
|
|
105
59
|
config = YAML.load_file(config_file)
|
106
60
|
rescue
|
107
61
|
unless File.exists?(config_file)
|
108
|
-
@logger.error "Config file not found."
|
62
|
+
@logger.error "Config file #{config_file} not found."
|
109
63
|
else
|
110
|
-
@logger.error "Problem loading config file. Exiting."
|
111
|
-
end
|
112
|
-
raise "Could not load #{config_file}"
|
113
|
-
end
|
114
|
-
validate_config_structure(config)
|
115
|
-
if config['compile']
|
116
|
-
for src in config['compile']
|
117
|
-
data = src['data']
|
118
|
-
for cfgn in src['builds']
|
119
|
-
template = @base_dir + cfgn['template']
|
120
|
-
unless cfgn['output'].downcase == "stdout"
|
121
|
-
output = @base_dir + cfgn['output']
|
122
|
-
else
|
123
|
-
output = "stdout"
|
124
|
-
end
|
125
|
-
liquify(data, template, output)
|
126
|
-
end
|
64
|
+
@logger.error "Problem loading config file #{config_file}. Exiting."
|
127
65
|
end
|
66
|
+
raise "ConfigFileError"
|
128
67
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
68
|
+
cfg = BuildConfig.new(config) # convert the config file to a new object called 'cfg'
|
69
|
+
iterate_build(cfg)
|
70
|
+
end
|
71
|
+
|
72
|
+
def iterate_build cfg
|
73
|
+
stepcount = 0
|
74
|
+
for step in cfg.steps # iterate through each node in the 'config' object, which should start with an 'action' parameter
|
75
|
+
stepcount = stepcount + 1
|
76
|
+
step = BuildConfigStep.new(step) # create an instance of the Action class, validating the top-level step hash (now called 'step') in the process
|
77
|
+
type = step.type
|
78
|
+
case type # a switch to evaluate the 'action' parameter for each step in the iteration...
|
79
|
+
when "parse"
|
80
|
+
data = DataSrc.new(step.data)
|
81
|
+
builds = step.builds
|
82
|
+
for bld in builds
|
83
|
+
build = Build.new(bld, type) # create an instance of the Build class; Build.new accepts a 'bld' hash & action 'type'
|
84
|
+
liquify(data, build.template, build.output) # perform the liquify operation
|
139
85
|
end
|
140
|
-
|
141
|
-
@logger.
|
86
|
+
when "migrate"
|
87
|
+
@logger.warn "Migrate actions not yet implemented."
|
88
|
+
when "render"
|
89
|
+
@logger.warn "Render actions not yet implemented."
|
90
|
+
when "deploy"
|
91
|
+
@logger.warn "Deploy actions not yet implemented."
|
92
|
+
else
|
93
|
+
@logger.warn "The action `#{type}` is not valid."
|
142
94
|
end
|
143
95
|
end
|
144
96
|
end
|
@@ -154,38 +106,258 @@ def validate_file_input file, type
|
|
154
106
|
error = "The #{type} file (#{file}) was not found."
|
155
107
|
end
|
156
108
|
end
|
157
|
-
|
158
|
-
@logger.debug "Input file validated for #{type} file #{file}."
|
159
|
-
else
|
109
|
+
if error
|
160
110
|
@logger.error "Could not validate input file: #{error}"
|
161
111
|
raise "InvalidInput"
|
162
112
|
end
|
163
113
|
end
|
164
114
|
|
165
115
|
def validate_config_structure config
|
166
|
-
unless config.is_a?
|
167
|
-
message = "The configuration file is not properly structured
|
116
|
+
unless config.is_a? Array
|
117
|
+
message = "The configuration file is not properly structured."
|
168
118
|
@logger.error message
|
169
|
-
raise
|
119
|
+
raise "ConfigStructError"
|
170
120
|
else
|
171
|
-
|
172
|
-
|
121
|
+
if (defined?(config['action'])).nil?
|
122
|
+
message = "Every listing in the configuration file needs an action type declaration."
|
123
|
+
@logger.error message
|
124
|
+
raise "ConfigStructError"
|
173
125
|
end
|
174
126
|
end
|
175
127
|
# TODO More validation needed
|
176
128
|
end
|
177
129
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
130
|
+
# ===
|
131
|
+
# Core classes
|
132
|
+
# ===
|
133
|
+
|
134
|
+
# For now BuildConfig is mostly to objectify the primary build 'action' steps
|
135
|
+
class BuildConfig
|
136
|
+
|
137
|
+
def initialize config
|
138
|
+
|
139
|
+
if (defined?(config['compile'][0])) # The config is formatted for vesions < 0.3.0; convert it
|
140
|
+
config = deprecated_format(config)
|
141
|
+
end
|
142
|
+
|
143
|
+
# validations
|
144
|
+
unless config.is_a? Array
|
145
|
+
raise "ConfigStructError"
|
146
|
+
end
|
147
|
+
|
148
|
+
@@cfg = config
|
149
|
+
end
|
150
|
+
|
151
|
+
def steps
|
152
|
+
@@cfg
|
153
|
+
end
|
154
|
+
|
155
|
+
def deprecated_format config # for backward compatibility with 0.1.0 and 0.2.0
|
156
|
+
puts "You are using a deprecated configuration file structure. Update your config files; support for this structure will be dropped in version 1.0.0."
|
157
|
+
# There's only ever one item in the 'compile' array, and only one action type ("parse")
|
158
|
+
config['compile'].each do |n|
|
159
|
+
n.merge!("action" => "parse") # the action type was not previously declared
|
160
|
+
end
|
161
|
+
return config['compile']
|
162
|
+
end
|
163
|
+
|
164
|
+
end #class BuildConfig
|
165
|
+
|
166
|
+
class BuildConfigStep
|
167
|
+
|
168
|
+
def initialize step
|
169
|
+
@@step = step
|
170
|
+
@@logger = Logger.new(STDOUT)
|
171
|
+
if (defined?(@@step['action'])).nil?
|
172
|
+
@logger.error "Every step in the configuration file needs an 'action' type declared."
|
173
|
+
raise "ConfigStructError"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def type
|
178
|
+
return @@step['action']
|
179
|
+
end
|
180
|
+
|
181
|
+
def data
|
182
|
+
return @@step['data']
|
183
|
+
end
|
184
|
+
|
185
|
+
def builds
|
186
|
+
return @@step['builds']
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.validate reqs
|
190
|
+
for req in reqs
|
191
|
+
if (defined?(@@step[req])).nil?
|
192
|
+
@@logger.error "Every #{@@step['action']}-type in the configuration file needs a '#{req}' declaration."
|
193
|
+
raise "ConfigStructError"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
end #class Action
|
199
|
+
|
200
|
+
class Build
|
201
|
+
|
202
|
+
def initialize build, type
|
203
|
+
@@build = build
|
204
|
+
@@type = type
|
205
|
+
@@logger = Logger.new(STDOUT)
|
206
|
+
required = []
|
207
|
+
case type
|
208
|
+
when "parse"
|
209
|
+
required = ["template,output"]
|
210
|
+
when "render"
|
211
|
+
required = ["index,output"]
|
212
|
+
when "migrate"
|
213
|
+
required = ["source,target"]
|
214
|
+
end
|
215
|
+
for req in required
|
216
|
+
if (defined?(req)).nil?
|
217
|
+
raise ActionSettingMissing
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def template
|
223
|
+
@@build['template']
|
224
|
+
end
|
225
|
+
|
226
|
+
def output
|
227
|
+
@@build['output']
|
228
|
+
end
|
229
|
+
|
230
|
+
def index
|
231
|
+
@@build['index']
|
232
|
+
end
|
233
|
+
|
234
|
+
def source
|
235
|
+
@@build['source']
|
236
|
+
end
|
237
|
+
|
238
|
+
def target
|
239
|
+
@@build['target']
|
240
|
+
end
|
241
|
+
|
242
|
+
end #class Build
|
243
|
+
|
244
|
+
class DataSrc
|
245
|
+
# initialization means establishing a proper hash for the 'data' param
|
246
|
+
def initialize datasrc
|
247
|
+
@@datasrc = {}
|
248
|
+
if datasrc.is_a? String # create a hash out of the filename
|
249
|
+
begin
|
250
|
+
@@datasrc['file'] = datasrc
|
251
|
+
@@datasrc['ext'] = File.extname(datasrc)
|
252
|
+
@@datasrc['type'] = false
|
253
|
+
@@datasrc['pattern'] = false
|
254
|
+
rescue
|
255
|
+
raise "InvalidDataFilename"
|
256
|
+
end
|
257
|
+
else
|
258
|
+
if datasrc.is_a? Hash # data var is a hash, so add 'ext' to it by extracting it from filename
|
259
|
+
@@datasrc['file'] = datasrc['file']
|
260
|
+
@@datasrc['ext'] = File.extname(datasrc['file'])
|
261
|
+
if (defined?(datasrc['pattern']))
|
262
|
+
@@datasrc['pattern'] = datasrc['pattern']
|
263
|
+
end
|
264
|
+
if (defined?(datasrc['type']))
|
265
|
+
@@datasrc['type'] = datasrc['type']
|
266
|
+
end
|
267
|
+
else # datasrc is neither String nor Hash
|
268
|
+
raise "InvalidDataSource"
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def file
|
274
|
+
@@datasrc['file']
|
275
|
+
end
|
276
|
+
|
277
|
+
def ext
|
278
|
+
@@datasrc['ext']
|
279
|
+
end
|
280
|
+
|
281
|
+
def type
|
282
|
+
if @@datasrc['type'] # if we're carrying a 'type' setting for data, pass it along
|
283
|
+
datatype = @@datasrc['type']
|
284
|
+
if datatype.downcase == "yaml" # This is an expected common error, so let's do the user a solid
|
285
|
+
datatype = "yml"
|
286
|
+
end
|
287
|
+
else # If there's no 'type' defined, extract it from the filename and validate it
|
288
|
+
unless @@datasrc['ext'].downcase.match(/\.yml|\.json|\.xml|\.csv/)
|
289
|
+
# @logger.error "Data file extension must be one of: .yml, .json, .xml, or .csv or else declared in config file."
|
290
|
+
raise "FileExtensionUnknown"
|
291
|
+
end
|
292
|
+
datatype = @@datasrc['ext']
|
293
|
+
datatype = datatype[1..-1] # removes leading dot char
|
294
|
+
end
|
295
|
+
unless datatype.downcase.match(/yml|json|xml|csv|regex/) # 'type' must be one of these permitted vals
|
296
|
+
# @logger.error "Declared data type must be one of: yaml, json, xml, csv, or regex."
|
297
|
+
raise "DataTypeUnrecognized"
|
298
|
+
end
|
299
|
+
datatype
|
300
|
+
end
|
301
|
+
|
302
|
+
def pattern
|
303
|
+
@@datasrc['pattern']
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# ===
|
308
|
+
# Action-specific methods
|
309
|
+
#
|
310
|
+
# PARSE-type build methods
|
311
|
+
# ===
|
312
|
+
|
313
|
+
# Pull in a semi-structured data file, converting contents to a Ruby hash
|
314
|
+
def ingest_data datasrc
|
315
|
+
# Must be passed a proper data object (there must be a better way to validate arg datatypes)
|
316
|
+
unless datasrc.is_a? Object
|
317
|
+
raise "InvalidDataObject"
|
318
|
+
end
|
319
|
+
# This method should really begin here, once the data object is in order
|
320
|
+
case datasrc.type
|
321
|
+
when "yml"
|
322
|
+
begin
|
323
|
+
return YAML.load_file(datasrc.file)
|
324
|
+
rescue Exception => ex
|
325
|
+
@logger.error "There was a problem with the data file. #{ex.message}"
|
326
|
+
end
|
327
|
+
when "json"
|
328
|
+
begin
|
329
|
+
return JSON.parse(File.read(datasrc.file))
|
330
|
+
rescue Exception => ex
|
331
|
+
@logger.error "There was a problem with the data file. #{ex.message}"
|
332
|
+
end
|
333
|
+
when "xml"
|
334
|
+
begin
|
335
|
+
data = Crack::XML.parse(File.read(datasrc.file))
|
336
|
+
return data['root']
|
337
|
+
rescue Exception => ex
|
338
|
+
@logger.error "There was a problem with the data file. #{ex.message}"
|
339
|
+
end
|
340
|
+
when "csv"
|
341
|
+
output = []
|
342
|
+
i = 0
|
343
|
+
begin
|
344
|
+
CSV.foreach(datasrc.file, headers: true, skip_blanks: true) do |row|
|
345
|
+
output[i] = row.to_hash
|
346
|
+
i = i+1
|
347
|
+
end
|
348
|
+
output = {"data" => output}
|
349
|
+
return output
|
350
|
+
rescue
|
351
|
+
@logger.error "The CSV format is invalid."
|
352
|
+
end
|
353
|
+
when "regex"
|
354
|
+
if datasrc.pattern
|
355
|
+
return parse_regex(datasrc.file, datasrc.pattern)
|
356
|
+
else
|
357
|
+
@logger.error "You must supply a regex pattern with your free-form data file."
|
358
|
+
raise "MissingRegexPattern"
|
359
|
+
end
|
360
|
+
end
|
189
361
|
end
|
190
362
|
|
191
363
|
def parse_regex data_file, pattern
|
@@ -214,17 +386,15 @@ def parse_regex data_file, pattern
|
|
214
386
|
return output
|
215
387
|
end
|
216
388
|
|
217
|
-
#
|
218
|
-
|
219
|
-
# ===
|
220
|
-
|
221
|
-
# Parse given data using given template, saving to given filename
|
222
|
-
def liquify data, template_file, output
|
389
|
+
# Parse given data using given template, generating given output
|
390
|
+
def liquify datasrc, template_file, output
|
223
391
|
@logger.debug "Executing liquify parsing operation."
|
224
|
-
|
225
|
-
|
392
|
+
if datasrc.is_a? String
|
393
|
+
datasrc = DataSrc.new(datasrc)
|
394
|
+
end
|
395
|
+
validate_file_input(datasrc.file, "data")
|
226
396
|
validate_file_input(template_file, "template")
|
227
|
-
data =
|
397
|
+
data = ingest_data(datasrc)
|
228
398
|
begin
|
229
399
|
template = File.read(template_file) # reads the template file
|
230
400
|
template = Liquid::Template.parse(template) # compiles template
|
@@ -253,6 +423,10 @@ def liquify data, template_file, output
|
|
253
423
|
end
|
254
424
|
end
|
255
425
|
|
426
|
+
# ===
|
427
|
+
# MIGRATE-type methods
|
428
|
+
# ===
|
429
|
+
|
256
430
|
# Copy images and other assets into output dir for HTML operations
|
257
431
|
def copy_assets src, dest
|
258
432
|
if @recursive
|
@@ -273,7 +447,7 @@ def copy_assets src, dest
|
|
273
447
|
end
|
274
448
|
|
275
449
|
# ===
|
276
|
-
#
|
450
|
+
# RENDER-type methods
|
277
451
|
# ===
|
278
452
|
|
279
453
|
# Gather attributes from a fixed attributes file
|
@@ -308,7 +482,7 @@ def publish pub, bld
|
|
308
482
|
end
|
309
483
|
|
310
484
|
# ===
|
311
|
-
#
|
485
|
+
# Text manipulation Classes, Modules, filters, etc
|
312
486
|
# ===
|
313
487
|
|
314
488
|
class String
|
@@ -336,7 +510,7 @@ class String
|
|
336
510
|
|
337
511
|
end
|
338
512
|
|
339
|
-
# Liquid
|
513
|
+
# Extending Liquid filters/text manipulation
|
340
514
|
module CustomFilters
|
341
515
|
def plainwrap input
|
342
516
|
input.wrap
|
@@ -382,11 +556,17 @@ module CustomFilters
|
|
382
556
|
|
383
557
|
end
|
384
558
|
|
559
|
+
# register custom Liquid filters
|
385
560
|
Liquid::Template.register_filter(CustomFilters)
|
386
561
|
|
562
|
+
|
563
|
+
# ===
|
564
|
+
# Command/options parser
|
565
|
+
# ===
|
566
|
+
|
387
567
|
# Define command-line option/argument parameters
|
388
568
|
# From the root directory of your project:
|
389
|
-
# $
|
569
|
+
# $ liquidoc --help
|
390
570
|
command_parser = OptionParser.new do|opts|
|
391
571
|
opts.banner = "Usage: liquidoc [options]"
|
392
572
|
|
@@ -442,7 +622,6 @@ command_parser = OptionParser.new do|opts|
|
|
442
622
|
|
443
623
|
end
|
444
624
|
|
445
|
-
# Parse options.
|
446
625
|
command_parser.parse!
|
447
626
|
|
448
627
|
# Upfront debug output
|
@@ -450,10 +629,9 @@ command_parser.parse!
|
|
450
629
|
@logger.debug "Config file: #{@config_file}"
|
451
630
|
@logger.debug "Index file: #{@index_file}"
|
452
631
|
|
453
|
-
#
|
454
|
-
#
|
455
|
-
#
|
456
|
-
# file establishes the structure.
|
632
|
+
# ===
|
633
|
+
# Execute
|
634
|
+
# ===
|
457
635
|
|
458
636
|
unless @config_file
|
459
637
|
if @data_file
|
data/lib/liquidoc/version.rb
CHANGED
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.
|
4
|
+
version: 0.3.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: 2017-10-
|
11
|
+
date: 2017-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|