pandocomatic 0.1.4.9 → 0.1.4.10
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/pandocomatic/configuration.rb +367 -223
- data/lib/pandocomatic/pandoc_metadata.rb +131 -75
- data/lib/pandocomatic/pandocomatic.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: 11bf26bcbf6d79b0583eca48c30e1b685314f514
|
4
|
+
data.tar.gz: c26dd9a4433581a6154df33096d993fe56208338
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b1d7bcd5051193689a09812c45a7e4155d06e47ca9d6906b5d02ba0dbb628cdaa952ae613206b1eb59d3dfc3f21a81c102006743cc53895cc0b51500a078d9a
|
7
|
+
data.tar.gz: cc8a459844153351c30749c2d0ff215ec8ff64655661b74f893acffcd7ecf1fba447d7d063a399dbf43a89b94862cd964b6e2c52c3ebc50c6872b672472ea8b1
|
@@ -18,271 +18,415 @@
|
|
18
18
|
#++
|
19
19
|
module Pandocomatic
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
require 'yaml'
|
22
|
+
require 'paru/pandoc'
|
23
|
+
|
24
|
+
# The default configuration for pandocomatic is read from
|
25
|
+
# default_configuration.yaml.
|
26
|
+
DEFAULT_CONFIG = YAML.load_file File.join(__dir__, 'default_configuration.yaml')
|
27
|
+
|
28
|
+
# Maps pandoc output formats to an extension.
|
29
|
+
FORMAT_TO_EXT = {
|
30
|
+
'native' => 'hs',
|
31
|
+
'markdown' => 'md',
|
32
|
+
'markdown_strict' => 'md',
|
33
|
+
'markdown_phpextra' => 'md',
|
34
|
+
'markdown_github' => 'md',
|
35
|
+
'html5' => 'html',
|
36
|
+
'docx' => 'docx',
|
37
|
+
'latex' => 'tex'
|
38
|
+
}
|
39
|
+
|
40
|
+
# A Configuration object models a pandocomatic configuration.
|
41
|
+
class Configuration
|
42
|
+
|
43
|
+
# Create a new Configuration instance based on the command-line
|
44
|
+
# options, a data_dir, and a configuration file.
|
45
|
+
def initialize options, data_dir, configuration_file
|
46
|
+
@data_dir = data_dir
|
23
47
|
|
24
|
-
|
48
|
+
load configuration_file
|
49
|
+
end
|
25
50
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
51
|
+
# Read a configuration file and create a pandocomatic configuration object
|
52
|
+
#
|
53
|
+
# @param [String] filename Path to the configuration yaml file
|
54
|
+
# @return [Configuration] a pandocomatic configuration object
|
55
|
+
def load(filename)
|
56
|
+
begin
|
57
|
+
path = File.absolute_path filename
|
58
|
+
settings = YAML.load_file path
|
59
|
+
if settings['settings'] and settings['settings']['data-dir'] then
|
60
|
+
data_dir = settings['settings']['data-dir']
|
61
|
+
src_dir = File.dirname filename
|
62
|
+
if data_dir.start_with? '.' then
|
63
|
+
@data_dir = File.absolute_path data_dir, src_dir
|
64
|
+
else
|
65
|
+
@data_dir = data_dir
|
66
|
+
end
|
67
|
+
end
|
68
|
+
rescue StandardError => e
|
69
|
+
raise ConfigurationError.new(:unable_to_load_config_file, e, filename)
|
70
|
+
end
|
36
71
|
|
37
|
-
|
38
|
-
|
72
|
+
# hidden files will always be skipped, as will pandocomatic
|
73
|
+
# configuration files, unless explicitly set to not skip via the
|
74
|
+
# "unskip" option
|
39
75
|
|
40
|
-
|
41
|
-
@data_dir = data_dir
|
76
|
+
@settings = {'skip' => ['.*', 'pandocomatic.yaml']}
|
42
77
|
|
43
|
-
|
44
|
-
|
78
|
+
@templates = {}
|
79
|
+
@convert_patterns = {}
|
45
80
|
|
46
|
-
|
47
|
-
#
|
48
|
-
# @param [String] filename Path to the configuration yaml file
|
49
|
-
# @return [Configuration] a pandocomatic configuration object
|
50
|
-
def load(filename)
|
51
|
-
begin
|
52
|
-
path = File.absolute_path filename
|
53
|
-
settings = YAML.load_file path
|
54
|
-
if settings['settings'] and settings['settings']['data-dir'] then
|
55
|
-
data_dir = settings['settings']['data-dir']
|
56
|
-
src_dir = File.dirname filename
|
57
|
-
if data_dir.start_with? '.' then
|
58
|
-
@data_dir = File.absolute_path data_dir, src_dir
|
59
|
-
else
|
60
|
-
@data_dir = data_dir
|
61
|
-
end
|
81
|
+
configure settings
|
62
82
|
end
|
63
|
-
rescue StandardError => e
|
64
|
-
raise ConfigurationError.new(:unable_to_load_config_file, e, filename)
|
65
|
-
end
|
66
83
|
|
67
|
-
|
68
|
-
|
69
|
-
|
84
|
+
# Update this configuration with a configuration file
|
85
|
+
#
|
86
|
+
# @param [String] filename path to the configuration file
|
87
|
+
#
|
88
|
+
# @return [Configuration] a new configuration
|
89
|
+
def reconfigure(filename)
|
90
|
+
begin
|
91
|
+
settings = YAML.load_file filename
|
92
|
+
new_config = Marshal.load(Marshal.dump(self))
|
93
|
+
new_config.configure settings
|
94
|
+
new_config
|
95
|
+
rescue StandardError => e
|
96
|
+
raise ConfigurationError.new(:unable_to_load_config_file, e, filename)
|
97
|
+
end
|
98
|
+
end
|
70
99
|
|
71
|
-
|
100
|
+
# Configure pandocomatic based on a settings Hash
|
101
|
+
#
|
102
|
+
# @param settings [Hash] a settings Hash to mixin in this
|
103
|
+
# Configuration.
|
104
|
+
def configure(settings)
|
105
|
+
reset_settings settings['settings'] if settings.has_key? 'settings'
|
106
|
+
if settings.has_key? 'templates' then
|
107
|
+
settings['templates'].each do |name, template|
|
108
|
+
full_template = {
|
109
|
+
'extends' => [],
|
110
|
+
'glob' => [],
|
111
|
+
'setup' => [],
|
112
|
+
'preprocessors' => [],
|
113
|
+
'metadata' => {},
|
114
|
+
'pandoc' => {},
|
115
|
+
'postprocessors' => [],
|
116
|
+
'cleanup' => []
|
117
|
+
}
|
118
|
+
|
119
|
+
reset_template name, full_template.merge(template)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
72
123
|
|
73
|
-
|
74
|
-
|
124
|
+
# Convert this Configuration to a String
|
125
|
+
#
|
126
|
+
# @return [String]
|
127
|
+
def to_s()
|
128
|
+
marshal_dump
|
129
|
+
end
|
75
130
|
|
76
|
-
|
77
|
-
|
131
|
+
# Should the source file be skipped given this Configuration?
|
132
|
+
#
|
133
|
+
# @param src [String] path to a source file
|
134
|
+
# @return [Boolean] True if this source file matches the pattern in
|
135
|
+
# the 'skip' setting, false otherwise.
|
136
|
+
def skip?(src)
|
137
|
+
if @settings.has_key? 'skip' then
|
138
|
+
@settings['skip'].any? {|glob| File.fnmatch glob, File.basename(src)}
|
139
|
+
else
|
140
|
+
false
|
141
|
+
end
|
142
|
+
end
|
78
143
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
settings = YAML.load_file filename
|
87
|
-
new_config = Marshal.load(Marshal.dump(self))
|
88
|
-
new_config.configure settings
|
89
|
-
new_config
|
90
|
-
rescue StandardError => e
|
91
|
-
raise ConfigurationError.new(:unable_to_load_config_file, e, filename)
|
92
|
-
end
|
93
|
-
end
|
144
|
+
# Should the source file be converted given this Configuration?
|
145
|
+
#
|
146
|
+
# @param src [String] True if this source file matches the 'glob'
|
147
|
+
# patterns in a template, false otherwise.
|
148
|
+
def convert?(src)
|
149
|
+
@convert_patterns.values.flatten.any? {|glob| File.fnmatch glob, File.basename(src)}
|
150
|
+
end
|
94
151
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
'
|
101
|
-
'setup' => [],
|
102
|
-
'preprocessors' => [],
|
103
|
-
'metadata' => {},
|
104
|
-
'pandoc' => {},
|
105
|
-
'postprocessors' => [],
|
106
|
-
'cleanup' => []
|
107
|
-
}
|
108
|
-
|
109
|
-
reset_template name, full_template.merge(template)
|
152
|
+
# Should pandocomatic be run recursively given this Configuration?
|
153
|
+
#
|
154
|
+
# @return [Boolean] True if the setting 'recursive' is true, false
|
155
|
+
# otherwise
|
156
|
+
def recursive?()
|
157
|
+
@settings['recursive']
|
110
158
|
end
|
111
|
-
end
|
112
|
-
end
|
113
159
|
|
114
|
-
|
115
|
-
|
116
|
-
|
160
|
+
# Should pandocomatic follow symbolic links given this Configuration?
|
161
|
+
#
|
162
|
+
# @return [Boolean] True if the setting 'follow_links' is true, false
|
163
|
+
# otherwise
|
164
|
+
def follow_links?()
|
165
|
+
@settings['follow_links']
|
166
|
+
end
|
117
167
|
|
118
|
-
|
119
|
-
|
120
|
-
|
168
|
+
# Set the extension of the destination file given this Confguration,
|
169
|
+
# template, and metadata
|
170
|
+
#
|
171
|
+
# @param dst [String] path to a destination file
|
172
|
+
# @param template_name [String] the name of the template used to
|
173
|
+
# convert to destination
|
174
|
+
# @param metadata [PandocMetadata] the metadata in the source file
|
175
|
+
def set_extension(dst, template_name, metadata)
|
176
|
+
dir = File.dirname dst
|
177
|
+
ext = File.extname dst
|
178
|
+
basename = File.basename dst, ext
|
179
|
+
File.join dir, "#{basename}.#{find_extension(dst, template_name, metadata)}"
|
180
|
+
end
|
121
181
|
|
122
|
-
|
123
|
-
|
124
|
-
|
182
|
+
# Find the extension of the destination file given this Confguration,
|
183
|
+
# template, and metadata
|
184
|
+
#
|
185
|
+
# @param dst [String] path to a destination file
|
186
|
+
# @param template_name [String] the name of the template used to
|
187
|
+
# convert to destination
|
188
|
+
# @param metadata [PandocMetadata] the metadata in the source file
|
189
|
+
#
|
190
|
+
# @return [String] the extension to use for the destination file
|
191
|
+
def find_extension(dst, template_name, metadata)
|
192
|
+
extension = "html"
|
193
|
+
if template_name.nil? or template_name.empty? then
|
194
|
+
if metadata.has_pandocomatic?
|
195
|
+
pandocomatic = metadata.pandocomatic
|
196
|
+
if pandocomatic.has_key? "pandoc"
|
197
|
+
pandoc = pandocomatic["pandoc"]
|
198
|
+
|
199
|
+
if pandoc.has_key? "to"
|
200
|
+
extension = pandoc["to"]
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
else
|
205
|
+
# TODO: what if there is no pandoc.to?
|
206
|
+
if @templates[template_name].has_key? "pandoc"
|
207
|
+
pandoc = @templates[template_name]["pandoc"]
|
208
|
+
if pandoc.has_key? "to"
|
209
|
+
extension = pandoc["to"]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
125
213
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
else
|
130
|
-
false
|
131
|
-
end
|
132
|
-
end
|
214
|
+
extension = FORMAT_TO_EXT[extension] || extension
|
215
|
+
return extension
|
216
|
+
end
|
133
217
|
|
134
|
-
|
135
|
-
|
136
|
-
|
218
|
+
# Is there a template with template_name in this Configuration?
|
219
|
+
#
|
220
|
+
# @param template_name [String] a template's name
|
221
|
+
#
|
222
|
+
# @return [Boolean] True if there is a template with name equal to
|
223
|
+
# template_name in this Configuration
|
224
|
+
def has_template?(template_name)
|
225
|
+
@templates.has_key? template_name
|
226
|
+
end
|
137
227
|
|
138
|
-
|
139
|
-
|
140
|
-
|
228
|
+
# Get the template with template_name from this Configuration
|
229
|
+
#
|
230
|
+
# @param template_name [String] a template's name
|
231
|
+
#
|
232
|
+
# @return [Hash] The template with template_name.
|
233
|
+
def get_template(template_name)
|
234
|
+
@templates[template_name]
|
235
|
+
end
|
141
236
|
|
142
|
-
|
143
|
-
|
144
|
-
|
237
|
+
# Determine the template to use with this source document given this
|
238
|
+
# Configuration.
|
239
|
+
#
|
240
|
+
# @param src [String] path to the source document
|
241
|
+
# @return [String] the template's name to use
|
242
|
+
def determine_template(src)
|
243
|
+
@convert_patterns.select do |template_name, globs|
|
244
|
+
globs.any? {|glob| File.fnmatch glob, File.basename(src)}
|
245
|
+
end.keys.first
|
246
|
+
end
|
145
247
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
248
|
+
# Update the path to an executable processor or executor given this
|
249
|
+
# Configuration
|
250
|
+
#
|
251
|
+
# @param path [String] path to the executable
|
252
|
+
# @param src_dir [String] the source directory from which pandocomatic
|
253
|
+
# conversion process has been started
|
254
|
+
# @param check_executable [Booelan = false] Should the executable be
|
255
|
+
# verified to be executable? Defaults to false.
|
256
|
+
#
|
257
|
+
# @return [String] the updated path.
|
258
|
+
def update_path(path, src_dir, check_executable = false)
|
259
|
+
updated_path = path
|
260
|
+
if path.start_with? './'
|
261
|
+
# refers to a local (to file) dir
|
262
|
+
updated_path = File.join src_dir, path
|
263
|
+
else
|
264
|
+
if path.start_with? '/'
|
265
|
+
updated_path = path
|
266
|
+
else
|
267
|
+
if check_executable
|
268
|
+
updated_path = Configuration.which path
|
269
|
+
end
|
270
|
+
|
271
|
+
if updated_path.nil? or not updated_path.start_with? '/' then
|
272
|
+
# refers to data-dir
|
273
|
+
updated_path = File.join @data_dir, path
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
152
277
|
|
153
|
-
|
154
|
-
|
155
|
-
if template_name.nil? or template_name.empty? then
|
156
|
-
if metadata.has_pandocomatic?
|
157
|
-
pandocomatic = metadata.pandocomatic
|
158
|
-
if pandocomatic.has_key? "pandoc"
|
159
|
-
pandoc = pandocomatic["pandoc"]
|
278
|
+
updated_path
|
279
|
+
end
|
160
280
|
|
161
|
-
|
162
|
-
|
281
|
+
private
|
282
|
+
|
283
|
+
# Reset the settings for pandocomatic based on a new settings Hash
|
284
|
+
#
|
285
|
+
# @settings [Hash] the new settings to use to reset the settings in
|
286
|
+
# this Configuration with.
|
287
|
+
def reset_settings(settings)
|
288
|
+
settings.each do |setting, value|
|
289
|
+
case setting
|
290
|
+
when 'skip'
|
291
|
+
@settings['skip'] = @settings['skip'].concat(value).uniq
|
292
|
+
when 'data-dir'
|
293
|
+
next # skip data-dir setting; is set once in initialization
|
294
|
+
else
|
295
|
+
@settings[setting] = value
|
163
296
|
end
|
164
297
|
end
|
165
|
-
end
|
166
|
-
else
|
167
|
-
# TODO: what if there is no pandoc.to?
|
168
|
-
if @templates[template_name].has_key? "pandoc"
|
169
|
-
pandoc = @templates[template_name]["pandoc"]
|
170
|
-
if pandoc.has_key? "to"
|
171
|
-
extension = pandoc["to"]
|
172
|
-
end
|
173
298
|
end
|
174
|
-
end
|
175
|
-
|
176
|
-
extension = FORMAT_TO_EXT[extension] || extension
|
177
|
-
return extension
|
178
|
-
end
|
179
|
-
|
180
|
-
def has_template?(template_name)
|
181
|
-
@templates.has_key? template_name
|
182
|
-
end
|
183
299
|
|
184
|
-
|
185
|
-
|
186
|
-
|
300
|
+
# Merge two templates
|
301
|
+
#
|
302
|
+
# @param base_template [Hash] the base template
|
303
|
+
# @param mixin_template [Hash] the template to mixin into the base template
|
304
|
+
# @return [Hash] the merged templates
|
305
|
+
def merge(base_template, mixin_template)
|
306
|
+
fields = [
|
307
|
+
'extends',
|
308
|
+
'glob',
|
309
|
+
'metadata',
|
310
|
+
'setup',
|
311
|
+
'preprocessors',
|
312
|
+
'pandoc',
|
313
|
+
'postprocessors',
|
314
|
+
'cleanup'
|
315
|
+
]
|
316
|
+
|
317
|
+
fields.each do |field|
|
318
|
+
case field
|
319
|
+
when 'extends'
|
320
|
+
if mixin_template[field] and mixin_template[field].is_a? String
|
321
|
+
mixin_template[field] = [mixin_template[field]]
|
322
|
+
end
|
323
|
+
when
|
324
|
+
'cleanup',
|
325
|
+
'setup',
|
326
|
+
'preprocessors',
|
327
|
+
'postprocessors',
|
328
|
+
'glob'
|
329
|
+
|
330
|
+
if base_template[field] then
|
331
|
+
# If both templates have this field, concat the arrays
|
332
|
+
# and remove duplicates
|
333
|
+
if mixin_template[field] then
|
334
|
+
base_template[field].concat(mixin_template[field]).uniq!
|
335
|
+
end
|
336
|
+
else
|
337
|
+
# If the base does not have this fiel yet, assign it
|
338
|
+
# the mixin's
|
339
|
+
if mixin_template[field] then
|
340
|
+
base_template[field] = mixin_template[field]
|
341
|
+
end
|
342
|
+
end
|
343
|
+
when 'pandoc', 'metadata'
|
344
|
+
# Merge Hashes
|
345
|
+
if base_template[field] then
|
346
|
+
if mixin_template[field] then
|
347
|
+
base_template[field].merge! mixin_template[field]
|
348
|
+
end
|
349
|
+
else
|
350
|
+
if mixin_template[field] then
|
351
|
+
base_template[field] = mixin_template[field]
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
187
356
|
|
188
|
-
|
189
|
-
|
190
|
-
globs.any? {|glob| File.fnmatch glob, File.basename(src)}
|
191
|
-
end.keys.first
|
192
|
-
end
|
357
|
+
base_template
|
358
|
+
end
|
193
359
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
if
|
204
|
-
|
360
|
+
# Resolve the templates the templates extends and mixes them in, in
|
361
|
+
# order of occurrence.
|
362
|
+
#
|
363
|
+
# @param template [Hash] the template to extend
|
364
|
+
# @return [Hash] the resolved template
|
365
|
+
def extend_template(template)
|
366
|
+
resolved_template = {};
|
367
|
+
if template.has_key? 'extends' and not template['extends'].empty?
|
368
|
+
to_extend = template['extends']
|
369
|
+
to_extend = [to_extend] if to_extend.is_a? String
|
370
|
+
|
371
|
+
to_extend.each do |name|
|
372
|
+
if @templates.has_key? name
|
373
|
+
resolved_template = merge resolved_template, @templates[name]
|
374
|
+
else
|
375
|
+
warn "Cannot find template with name '#{parent_template_name}'. Skipping this template while extending: '#{template.to_s}'."
|
376
|
+
end
|
205
377
|
end
|
206
378
|
|
207
|
-
|
208
|
-
# refers to data-dir
|
209
|
-
updated_path = File.join @data_dir, path
|
210
|
-
end
|
379
|
+
resolved_template
|
211
380
|
end
|
212
|
-
end
|
213
381
|
|
214
|
-
|
215
|
-
end
|
216
|
-
|
217
|
-
private
|
218
|
-
|
219
|
-
def reset_settings(settings)
|
220
|
-
settings.each do |setting, value|
|
221
|
-
case setting
|
222
|
-
when 'skip'
|
223
|
-
@settings['skip'] = @settings['skip'].concat(value).uniq
|
224
|
-
when 'data-dir'
|
225
|
-
next # skip data-dir setting; is set once in initialization
|
226
|
-
else
|
227
|
-
@settings[setting] = value
|
382
|
+
merge resolved_template, template
|
228
383
|
end
|
229
|
-
end
|
230
|
-
end
|
231
384
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
385
|
+
# Reset the template with name in this Configuration based on a new
|
386
|
+
# template
|
387
|
+
#
|
388
|
+
# @param name [String] the name of the template in this Configuration
|
389
|
+
# @param template [Hash] the template to use to update the template in
|
390
|
+
# this Configuarion with
|
391
|
+
def reset_template(name, template)
|
392
|
+
extended_template = extend_template template
|
393
|
+
|
394
|
+
if @templates.has_key? name then
|
395
|
+
@templates[name] = merge @templates[name], extended_template
|
242
396
|
else
|
243
|
-
|
244
|
-
@templates[name][field] = template[field]
|
245
|
-
end
|
397
|
+
@templates[name] = extended_template
|
246
398
|
end
|
247
|
-
|
248
|
-
if
|
249
|
-
|
250
|
-
@templates[name][field].merge! template[field]
|
251
|
-
end
|
252
|
-
else
|
253
|
-
if template[field] then
|
254
|
-
@templates[name][field] = template[field]
|
255
|
-
end
|
399
|
+
|
400
|
+
if extended_template.has_key? 'glob' then
|
401
|
+
@convert_patterns[name] = extended_template['glob']
|
256
402
|
end
|
257
|
-
end
|
258
403
|
end
|
259
|
-
else
|
260
|
-
@templates[name] = template
|
261
|
-
end
|
262
|
-
|
263
|
-
if template.has_key? 'glob' then
|
264
|
-
@convert_patterns[name] = template['glob']
|
265
|
-
end
|
266
|
-
end
|
267
404
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
405
|
+
# Cross-platform way of finding an executable in the $PATH.
|
406
|
+
#
|
407
|
+
# which('ruby') #=> /usr/bin/ruby
|
408
|
+
#
|
409
|
+
# Taken from:
|
410
|
+
# http://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby#5471032
|
411
|
+
def self.which(cmd)
|
412
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
413
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
414
|
+
exts.each { |ext|
|
415
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
416
|
+
return exe if File.executable?(exe) &&
|
417
|
+
!File.directory?(exe)
|
418
|
+
}
|
419
|
+
end
|
420
|
+
return nil
|
421
|
+
end
|
422
|
+
|
423
|
+
def marshal_dump()
|
424
|
+
[@data_dir, @settings, @templates, @convert_patterns]
|
282
425
|
end
|
283
|
-
return nil
|
284
|
-
end
|
285
426
|
|
286
|
-
|
427
|
+
def marshal_load(array)
|
428
|
+
@data_dir, @settings, @templates, @convert_patterns = array
|
429
|
+
end
|
287
430
|
|
431
|
+
end
|
288
432
|
end
|
@@ -18,93 +18,149 @@
|
|
18
18
|
#++
|
19
19
|
module Pandocomatic
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
21
|
+
require 'json'
|
22
|
+
require 'yaml'
|
23
|
+
require 'paru'
|
24
|
+
|
25
|
+
require_relative './error/pandoc_error.rb'
|
26
|
+
require_relative './error/io_error.rb'
|
27
|
+
|
28
|
+
# PandocMetadata represents the metadata with pandoc options set in
|
29
|
+
# templates and input files.
|
30
|
+
class PandocMetadata < Hash
|
31
|
+
|
32
|
+
# Extract the metadata from an input file
|
33
|
+
#
|
34
|
+
# @param input_document [String] a path to an input file
|
35
|
+
# @return [String] the input document's metadata in the YAML format.
|
36
|
+
def self.extract_metadata input_document
|
37
|
+
begin
|
38
|
+
pandoc2yaml File.read(input_document)
|
39
|
+
rescue StandardError => e
|
40
|
+
raise IOError.new(:error_opening_file, e, input_document)
|
41
|
+
end
|
42
|
+
end
|
38
43
|
|
39
|
-
|
40
|
-
|
41
|
-
|
44
|
+
# Extract the YAML metadata from an input string
|
45
|
+
#
|
46
|
+
# @param input [String] the input string
|
47
|
+
# @return [String] the YAML data embedded in the input string
|
48
|
+
def self.pandoc2yaml(input)
|
49
|
+
input
|
50
|
+
.scan(/^---[ \t]*\n(.+?)^(?:---|\.\.\.)[ \t]*\n/m)
|
51
|
+
.flatten
|
52
|
+
.map{|yaml| yaml.strip}
|
53
|
+
.join("\n")
|
54
|
+
end
|
42
55
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
# Collect the metadata embedded in the src file and create a new
|
57
|
+
# PandocMetadata instance
|
58
|
+
#
|
59
|
+
# @param src [String] the path to the file to load metadata from
|
60
|
+
# @return [PandocMetadata] the metadata in the source file, or an empty
|
61
|
+
# one if no such metadata is contained in the source file.
|
62
|
+
def self.load_file src
|
63
|
+
yaml_metadata = extract_metadata src
|
64
|
+
|
65
|
+
if yaml_metadata.empty? then
|
66
|
+
return PandocMetadata.new
|
67
|
+
else
|
68
|
+
return PandocMetadata.new YAML.load(yaml_metadata)
|
69
|
+
end
|
70
|
+
end
|
54
71
|
|
55
|
-
|
56
|
-
|
57
|
-
|
72
|
+
# Creat e new PandocMetadata object based on the properties contained
|
73
|
+
# in a Hash
|
74
|
+
#
|
75
|
+
# @param hash [Hash] initial properties for this new PandocMetadata
|
76
|
+
# object
|
77
|
+
# @return [PandocMetadata]
|
78
|
+
def initialize hash = {}
|
79
|
+
super
|
80
|
+
merge! hash
|
81
|
+
end
|
58
82
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
83
|
+
# Does this PandocMetadata object use a template?
|
84
|
+
#
|
85
|
+
# @return [Boolean] true if it has a key 'use-template' among the
|
86
|
+
# pandocomatic template properties.
|
87
|
+
def has_template?()
|
88
|
+
has_pandocomatic? and pandocomatic.has_key? 'use-template' and not pandocomatic['use-template'].empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
# Get all the templates of this PandocMetadata oject
|
92
|
+
#
|
93
|
+
# @return [Array] an array of templates used in this PandocMetadata
|
94
|
+
# object
|
95
|
+
def templates()
|
96
|
+
if has_template?
|
97
|
+
if pandocomatic['use-template'].is_a? Array
|
98
|
+
pandocomatic['use-template']
|
99
|
+
else
|
100
|
+
[pandocomatic['use-template']]
|
101
|
+
end
|
63
102
|
else
|
64
|
-
[
|
103
|
+
[""]
|
65
104
|
end
|
66
|
-
else
|
67
|
-
[""]
|
68
105
|
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def template_name()
|
72
|
-
if has_template? then
|
73
|
-
pandocomatic['use-template']
|
74
|
-
else
|
75
|
-
''
|
76
|
-
end
|
77
|
-
end
|
78
106
|
|
79
|
-
|
80
|
-
|
107
|
+
# Get the used template's name
|
108
|
+
#
|
109
|
+
# @return [String] the name of the template used, if any, "" otherwise.
|
110
|
+
def template_name()
|
111
|
+
if has_template? then
|
112
|
+
pandocomatic['use-template']
|
113
|
+
else
|
114
|
+
''
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Does this PandocMetadata object have a pandocomatic property?
|
119
|
+
#
|
120
|
+
# @return [Boolean] True if this PandocMetadata object has a Hash
|
121
|
+
# property named "pandocomatic_". False otherwise.
|
122
|
+
#
|
123
|
+
# Note. For backward compatibility with older versions of
|
124
|
+
# pandocomatic, properties named "pandocomatic" (without the trailing
|
125
|
+
# underscore) are also accepted.
|
126
|
+
def has_pandocomatic?()
|
127
|
+
config = nil
|
128
|
+
if has_key? 'pandocomatic' or has_key? 'pandocomatic_'
|
129
|
+
config = self['pandocomatic'] if has_key? 'pandocomatic'
|
130
|
+
config = self['pandocomatic_'] if has_key? 'pandocomatic_'
|
131
|
+
end
|
132
|
+
config.is_a? Hash
|
133
|
+
end
|
81
134
|
|
82
|
-
|
83
|
-
|
84
|
-
|
135
|
+
# Get the pandoc options for this PandocMetadata object
|
136
|
+
#
|
137
|
+
# @return [Hash] the pandoc options if there are any, an empty Hash
|
138
|
+
# otherwise.
|
139
|
+
def pandoc_options()
|
140
|
+
if has_pandoc_options? then
|
141
|
+
pandocomatic['pandoc']
|
142
|
+
else
|
143
|
+
{}
|
144
|
+
end
|
145
|
+
end
|
85
146
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
147
|
+
# Get the pandocomatic property of this PandocMetadata object
|
148
|
+
#
|
149
|
+
# @return [Hash] the pandocomatic property as a Hash, if any, an empty
|
150
|
+
# Hash otherwise.
|
151
|
+
def pandocomatic()
|
152
|
+
return self['pandocomatic'] if has_key? 'pandocomatic'
|
153
|
+
return self['pandocomatic_'] if has_key? 'pandocomatic_'
|
154
|
+
end
|
93
155
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
156
|
+
# Does this PandocMetadata object has a pandoc options property?
|
157
|
+
#
|
158
|
+
# @return [Boolean] True if there is a pandoc options property in this
|
159
|
+
# PandocMetadata object. False otherwise.
|
160
|
+
def has_pandoc_options?()
|
161
|
+
has_pandocomatic? and pandocomatic.has_key? 'pandoc'
|
162
|
+
end
|
102
163
|
|
103
|
-
def pandocomatic()
|
104
|
-
return self['pandocomatic'] if has_key? 'pandocomatic'
|
105
|
-
return self['pandocomatic_'] if has_key? 'pandocomatic_'
|
106
164
|
end
|
107
165
|
|
108
|
-
end
|
109
|
-
|
110
166
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pandocomatic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.4.
|
4
|
+
version: 0.1.4.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Huub de Beer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-07-
|
11
|
+
date: 2017-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: paru
|