pandocomatic 0.1.4.9 → 0.1.4.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|