paru 0.2.4.4 → 0.2.4.5
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/bin/do-pandoc.rb +5 -5
- data/bin/pandoc2yaml.rb +23 -58
- data/lib/paru.rb +2 -1
- data/lib/paru/filter.rb +39 -12
- data/lib/paru/filter/ast_manipulation.rb +10 -1
- data/lib/paru/filter/attr.rb +10 -3
- data/lib/paru/filter/markdown.rb +19 -2
- data/lib/paru/filter/meta.rb +10 -9
- data/lib/paru/filter/meta_blocks.rb +1 -9
- data/lib/paru/filter/meta_inlines.rb +1 -9
- data/lib/paru/filter/meta_map.rb +144 -17
- data/lib/paru/filter/node.rb +41 -0
- data/lib/paru/filter/plain.rb +3 -3
- data/lib/paru/pandoc2yaml.rb +101 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b681740521f95d8baa1e31caa9476e035ef65c72
|
4
|
+
data.tar.gz: d9af38ecf31b7116af24fc46ae232c0fa7fdcf4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3763a3862f2d2cf6e45adf513dffea00f9888180d1a1d1fb42cd04776aba5fc0c567d73bc8a4a79ac3db5bfaad78bba37178bbb5232a7cd7e95d5f39b49a0548
|
7
|
+
data.tar.gz: 4f1a09ecb5fd986cc205f7fbaa8d0e03ddbd493ade3d0bcacb5e52a446db2e4e2eee4d6185c22da19003c8feaa583f1e1d2ce729120756b644aa6c7fcebbef61
|
data/bin/do-pandoc.rb
CHANGED
@@ -2,9 +2,7 @@
|
|
2
2
|
require "yaml"
|
3
3
|
require 'optparse'
|
4
4
|
require "paru/pandoc"
|
5
|
-
|
6
|
-
|
7
|
-
include Pandoc2Yaml
|
5
|
+
require "paru/pandoc2yaml"
|
8
6
|
|
9
7
|
parser = OptionParser.new do |opts|
|
10
8
|
opts.banner = "do-pandoc.rb runs pandoc on an input file using the pandoc configuration specified in that input file."
|
@@ -44,7 +42,9 @@ if !File.readable? document
|
|
44
42
|
warn "Cannot read file: #{input_document}"
|
45
43
|
exit
|
46
44
|
end
|
47
|
-
|
45
|
+
|
46
|
+
yaml = Paru::Pandoc2Yaml.extract_metadata(document)
|
47
|
+
metadata = YAML.load yaml
|
48
48
|
|
49
49
|
if metadata.has_key? "pandoc" then
|
50
50
|
begin
|
@@ -65,5 +65,5 @@ if metadata.has_key? "pandoc" then
|
|
65
65
|
warn "Something went wrong while using pandoc:\n\n#{e.message}"
|
66
66
|
end
|
67
67
|
else
|
68
|
-
warn "Unsure what to do: no pandoc options in #{
|
68
|
+
warn "Unsure what to do: no pandoc options in #{input_document}"
|
69
69
|
end
|
data/bin/pandoc2yaml.rb
CHANGED
@@ -9,86 +9,51 @@
|
|
9
9
|
# pandoc2yaml.rb input_file
|
10
10
|
#
|
11
11
|
##
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
require "json"
|
13
|
+
require 'optparse'
|
14
|
+
require 'paru/pandoc2yaml'
|
15
15
|
|
16
|
-
|
17
|
-
# Note. When converting metadata back to the pandoc markdown format, you have
|
18
|
-
# to use the option "standalone", otherwise the metadata is skipped
|
19
|
-
PANDOC_2_JSON = Paru::Pandoc.new {from "markdown"; to "json"}
|
20
|
-
JSON_2_PANDOC = Paru::Pandoc.new {from "json"; to "markdown"; standalone}
|
21
|
-
|
22
|
-
# When converting a pandoc document to JSON, or vice versa, the JSON object
|
23
|
-
# has the following three properties:
|
24
|
-
VERSION = "pandoc-api-version"
|
25
|
-
META = "meta"
|
26
|
-
BLOCKS = "blocks"
|
27
|
-
|
28
|
-
def extract_metadata input_document
|
29
|
-
json = JSON.parse(PANDOC_2_JSON << File.read(input_document))
|
30
|
-
yaml = ""
|
31
|
-
|
32
|
-
version, metadata = json.values_at(VERSION, META)
|
33
|
-
|
34
|
-
if not metadata.empty? then
|
35
|
-
metadata_document = {
|
36
|
-
VERSION => version,
|
37
|
-
META => metadata,
|
38
|
-
BLOCKS => []
|
39
|
-
}
|
40
|
-
|
41
|
-
yaml = JSON_2_PANDOC << JSON.generate(metadata_document)
|
42
|
-
end
|
43
|
-
|
44
|
-
yaml
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
if __FILE__ == $0
|
49
|
-
include Pandoc2Yaml
|
50
|
-
require 'optparse'
|
51
|
-
|
52
|
-
parser = OptionParser.new do |opts|
|
16
|
+
parser = OptionParser.new do |opts|
|
53
17
|
opts.banner = "pandoc2yaml.rb mines a pandoc markdown file for its YAML metadata"
|
54
18
|
opts.banner << "\n\nUsage: pandoc2yaml.rb some-pandoc-markdownfile.md"
|
55
19
|
opts.separator ""
|
56
20
|
opts.separator "Common options"
|
57
21
|
|
58
22
|
opts.on_tail("-h", "--help", "Show this message") do
|
59
|
-
|
60
|
-
|
23
|
+
puts opts
|
24
|
+
exit
|
61
25
|
end
|
62
26
|
|
63
27
|
opts.on("-v", "--version", "Show version") do
|
64
|
-
|
65
|
-
|
28
|
+
puts "pandoc2yaml.rb is part of paru version 0.2.3"
|
29
|
+
exit
|
66
30
|
end
|
67
|
-
|
31
|
+
end
|
68
32
|
|
69
|
-
|
33
|
+
parser.parse! ARGV
|
70
34
|
|
71
|
-
|
35
|
+
input_document = ARGV.pop
|
72
36
|
|
73
|
-
|
37
|
+
if ARGV.size != 0 then
|
74
38
|
warn "Expecting exactly one argument: the pandoc file to strip for metadata"
|
75
39
|
puts ""
|
76
40
|
puts parser
|
77
41
|
exit
|
78
|
-
|
42
|
+
end
|
79
43
|
|
80
|
-
|
81
|
-
|
44
|
+
document = File.expand_path input_document
|
45
|
+
if not File.exist? document
|
82
46
|
warn "Cannot find file: #{input_document}"
|
83
47
|
exit
|
84
|
-
|
48
|
+
end
|
85
49
|
|
86
|
-
|
50
|
+
if !File.readable? document
|
87
51
|
warn "Cannot read file: #{input_document}"
|
88
52
|
exit
|
89
|
-
end
|
90
|
-
|
91
|
-
output_metadata = Pandoc2Yaml.extract_metadata document
|
92
|
-
|
93
|
-
puts output_metadata
|
94
53
|
end
|
54
|
+
|
55
|
+
yaml = Paru::Pandoc2Yaml.extract_metadata(document)
|
56
|
+
|
57
|
+
yaml = "---\n..." if yaml.empty?
|
58
|
+
|
59
|
+
puts yaml
|
data/lib/paru.rb
CHANGED
data/lib/paru/filter.rb
CHANGED
@@ -198,11 +198,23 @@ module Paru
|
|
198
198
|
#
|
199
199
|
class Filter
|
200
200
|
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
#
|
205
|
-
#
|
201
|
+
# Create a new Filter instance. For convenience, {run} creates a new
|
202
|
+
# {Filter} and runs it immediately. Use this constructor if you want
|
203
|
+
# to run a filter on different input and output streams that STDIN and
|
204
|
+
# STDOUT respectively.
|
205
|
+
#
|
206
|
+
# @param input [IO = $stdin] the input stream to read, defaults to
|
207
|
+
# STDIN
|
208
|
+
# @param output [IO = $stdout] the output stream to write, defaults to
|
209
|
+
# STDOUT
|
210
|
+
def initialize(input = $stdin, output = $stdout)
|
211
|
+
@input = input
|
212
|
+
@output = output
|
213
|
+
end
|
214
|
+
|
215
|
+
# Run the filter specified by block. This is a convenience method that
|
216
|
+
# creates a new {Filter} using input stream STDIN and output stream
|
217
|
+
# STDOUT and immediately runs {filter} with the block supplied.
|
206
218
|
#
|
207
219
|
# @param block [Proc] the filter specification
|
208
220
|
#
|
@@ -213,23 +225,39 @@ module Paru
|
|
213
225
|
# end
|
214
226
|
# end
|
215
227
|
def self.run(&block)
|
216
|
-
Filter.new().filter(&block)
|
228
|
+
Filter.new($stdin, $stdout).filter(&block)
|
217
229
|
end
|
218
230
|
|
219
|
-
|
220
231
|
# The Document node from JSON formatted pandoc document structure
|
221
232
|
# on STDIN that is being filtered
|
222
233
|
#
|
223
234
|
# @return [Document] create a new Document node from a pandoc AST from
|
224
235
|
# JSON from STDIN
|
225
236
|
def document()
|
226
|
-
PandocFilter::Document.from_JSON
|
237
|
+
PandocFilter::Document.from_JSON @input.read
|
227
238
|
end
|
228
239
|
|
229
|
-
# Create a filter using +block+.
|
240
|
+
# Create a filter using +block+. In the block you specify
|
241
|
+
# selectors and actions to be performed on selected nodes. In the
|
242
|
+
# example below, the selector is "Image", which selects all image
|
243
|
+
# nodes. The action is to prepend the contents of the image's caption
|
244
|
+
# by the string "Figure. ".
|
245
|
+
#
|
246
|
+
# @param block [Proc] the filter specification
|
230
247
|
#
|
231
|
-
# @param block [Proc] a block specifying selectors and actions
|
232
248
|
# @return [JSON] a JSON string with the filtered pandoc AST
|
249
|
+
#
|
250
|
+
# @example Add 'Figure' to each image's caption
|
251
|
+
# input = IOString.new(File.read("my_report.md")
|
252
|
+
# output = IOString.new
|
253
|
+
#
|
254
|
+
# Paru::Filter.new(input, output).filter do
|
255
|
+
# with "Image" do |image|
|
256
|
+
# image.inner_markdown = "Figure. #{image.inner_markdown}"
|
257
|
+
# end
|
258
|
+
# end
|
259
|
+
#
|
260
|
+
# # do something with output.string
|
233
261
|
def filter(&block)
|
234
262
|
@selectors = Hash.new
|
235
263
|
@filtered_nodes = []
|
@@ -240,10 +268,9 @@ module Paru
|
|
240
268
|
instance_eval(&block)
|
241
269
|
end
|
242
270
|
|
243
|
-
|
271
|
+
@output.write @doc.to_JSON
|
244
272
|
end
|
245
273
|
|
246
|
-
|
247
274
|
# +current_node+ points to the node that is *now* being processed while
|
248
275
|
# running this filter.
|
249
276
|
#
|
@@ -24,6 +24,15 @@ module Paru
|
|
24
24
|
# nodes, and so on.
|
25
25
|
module ASTManipulation
|
26
26
|
|
27
|
+
# Find index of child
|
28
|
+
#
|
29
|
+
# @param child [Node] the child to find the index for
|
30
|
+
#
|
31
|
+
# @return [Number] the index of child or nil
|
32
|
+
def find_index(child)
|
33
|
+
@children.find_index child
|
34
|
+
end
|
35
|
+
|
27
36
|
# Insert child node among this node's children at position index.
|
28
37
|
#
|
29
38
|
# @param index [Integer] the position to insert the child
|
@@ -66,7 +75,7 @@ module Paru
|
|
66
75
|
# @param old_child [Node] the child to replace
|
67
76
|
# @param new_child [Node] the replacement child
|
68
77
|
def replace(old_child, new_child)
|
69
|
-
old_child_index =
|
78
|
+
old_child_index = find_index old_child
|
70
79
|
if old_child_index then
|
71
80
|
replace_at old_child_index, new_child
|
72
81
|
end
|
data/lib/paru/filter/attr.rb
CHANGED
@@ -36,10 +36,17 @@ module Paru
|
|
36
36
|
|
37
37
|
# Create a new attributes object
|
38
38
|
#
|
39
|
-
# @param attributes [Array] the attributes as [id, [class names],
|
39
|
+
# @param attributes [Array = []] the attributes as [id, [class names],
|
40
40
|
# [key-value pairs]]
|
41
|
-
def initialize(attributes)
|
42
|
-
|
41
|
+
def initialize(attributes = [])
|
42
|
+
id, classes, data = attributes
|
43
|
+
|
44
|
+
@id = id || ""
|
45
|
+
|
46
|
+
@classes = classes || []
|
47
|
+
@classes = [@classes] unless @classes.is_a? Array
|
48
|
+
|
49
|
+
@data = data || {}
|
43
50
|
end
|
44
51
|
|
45
52
|
# For each key-value pair of this attributes object
|
data/lib/paru/filter/markdown.rb
CHANGED
@@ -45,7 +45,9 @@ module Paru
|
|
45
45
|
end
|
46
46
|
|
47
47
|
# Set the markdown representation of this Node: replace this Node
|
48
|
-
# by the Node represented by the markdown string
|
48
|
+
# by the Node represented by the markdown string. If an inline
|
49
|
+
# node is being replaced and the replacement has more than one
|
50
|
+
# paragraph, only the contents of the first paragraph is used
|
49
51
|
#
|
50
52
|
# @param markdown [String] the markdown string to replace this
|
51
53
|
# Node
|
@@ -67,6 +69,20 @@ module Paru
|
|
67
69
|
# replace current node by new nodes
|
68
70
|
# There is a difference between inline and block nodes
|
69
71
|
current_index = parent.find_index self
|
72
|
+
|
73
|
+
# By default, pandoc creates a Block level node when
|
74
|
+
# converting a string. However, if the original is a
|
75
|
+
# inline level node, so should its replacement node(s) be.
|
76
|
+
# Only using first block node (paragraph?)
|
77
|
+
if is_inline?
|
78
|
+
temp_doc = temp_doc.children.first
|
79
|
+
|
80
|
+
if not temp_doc.children.all? {|node| node.is_inline?}
|
81
|
+
raise Error.new "Cannot replace the inline level node represented by '#{outer_markdown}' with markdown that converts to block level nodes: '#{markdown}'."
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
70
86
|
index = current_index
|
71
87
|
temp_doc.each do |child|
|
72
88
|
index += 1
|
@@ -119,7 +135,7 @@ module Paru
|
|
119
135
|
temp_doc.children.each {|c| c.parent = @parent}
|
120
136
|
|
121
137
|
if has_inline?
|
122
|
-
@children = temp_doc.children
|
138
|
+
@children = temp_doc.children.first.children
|
123
139
|
elsif has_block?
|
124
140
|
@children = temp_doc.children
|
125
141
|
else
|
@@ -128,6 +144,7 @@ module Paru
|
|
128
144
|
end
|
129
145
|
end
|
130
146
|
end
|
147
|
+
|
131
148
|
end
|
132
149
|
end
|
133
150
|
end
|
data/lib/paru/filter/meta.rb
CHANGED
@@ -19,20 +19,12 @@
|
|
19
19
|
module Paru
|
20
20
|
module PandocFilter
|
21
21
|
require_relative "./meta_map"
|
22
|
-
|
22
|
+
|
23
23
|
# A Meta node represents the metadata of a document. It is a MetaMap
|
24
24
|
# node.
|
25
25
|
#
|
26
26
|
# @see http://hackage.haskell.org/package/pandoc-types-1.17.0.4/docs/Text-Pandoc-Definition.html#t:Meta
|
27
27
|
class Meta < MetaMap
|
28
|
-
include Enumerable
|
29
|
-
|
30
|
-
# Create a new Meta node based on the contents
|
31
|
-
#
|
32
|
-
# @param value [String]
|
33
|
-
def initialize(value)
|
34
|
-
super value
|
35
|
-
end
|
36
28
|
|
37
29
|
# The type of a Meta is "meta"
|
38
30
|
#
|
@@ -46,6 +38,15 @@ module Paru
|
|
46
38
|
ast_contents
|
47
39
|
end
|
48
40
|
|
41
|
+
# Convert this Meta node to an {MetaMap} node
|
42
|
+
#
|
43
|
+
# @return [MetaMap] a MetaMap representation of this metadata
|
44
|
+
def to_meta_map()
|
45
|
+
map = MetaMap.new []
|
46
|
+
map.children = @children
|
47
|
+
map
|
48
|
+
end
|
49
|
+
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
@@ -18,18 +18,10 @@
|
|
18
18
|
#++
|
19
19
|
module Paru
|
20
20
|
module PandocFilter
|
21
|
-
|
22
21
|
require_relative "./node"
|
23
22
|
|
24
|
-
# A MetaBlocks Node contains a list of
|
23
|
+
# A MetaBlocks Node contains a list of {Block} nodes
|
25
24
|
class MetaBlocks < Node
|
26
|
-
|
27
|
-
# Create a MetaBlocks node based on the contents
|
28
|
-
#
|
29
|
-
# @param value [String] the contents of the MetaBlocks
|
30
|
-
def initialize(value)
|
31
|
-
super value
|
32
|
-
end
|
33
25
|
end
|
34
26
|
end
|
35
27
|
end
|
@@ -18,18 +18,10 @@
|
|
18
18
|
#++
|
19
19
|
module Paru
|
20
20
|
module PandocFilter
|
21
|
-
|
22
21
|
require_relative "./node"
|
23
22
|
|
24
|
-
# A MetaInlines node contains a list of Inline nodes
|
23
|
+
# A MetaInlines node contains a list of {Inline} nodes
|
25
24
|
class MetaInlines < Node
|
26
|
-
|
27
|
-
# Create a new MetaInlines Node based on the contents
|
28
|
-
#
|
29
|
-
# @param value [String] the contents of this MetaInlines node
|
30
|
-
def initialize(value)
|
31
|
-
super value
|
32
|
-
end
|
33
25
|
end
|
34
26
|
end
|
35
27
|
end
|
data/lib/paru/filter/meta_map.rb
CHANGED
@@ -20,9 +20,11 @@ module Paru
|
|
20
20
|
module PandocFilter
|
21
21
|
|
22
22
|
require_relative "./node"
|
23
|
+
require_relative "../pandoc.rb"
|
23
24
|
|
24
25
|
# A MetaMap Node is a map of String keys with MetaValue values
|
25
26
|
class MetaMap < Node
|
27
|
+
include Enumerable
|
26
28
|
|
27
29
|
# Create a new MetaMap based on the contents
|
28
30
|
#
|
@@ -39,41 +41,118 @@ module Paru
|
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
42
|
-
# Get the value belonging to key
|
44
|
+
# Get the value belonging to key. Prefer to use the {has?}, {get},
|
45
|
+
# {replace} and {delete} methods to manipulate metadata.
|
43
46
|
#
|
44
47
|
# @param key [String] the key
|
45
48
|
#
|
46
49
|
# @return [MetaValue] the value belonging to the key
|
47
50
|
def [](key)
|
48
|
-
|
49
|
-
@children[key]
|
50
|
-
end
|
51
|
+
@children[key]
|
51
52
|
end
|
52
53
|
|
53
|
-
# Set a value with a key
|
54
|
+
# Set a value with a key. It is easier to use the {yaml} method to set
|
55
|
+
# metadata properties; the {yaml} method is the preferred method
|
56
|
+
# to set the metadata.
|
54
57
|
#
|
55
58
|
# @param key [String] the key to set
|
56
|
-
# @param value
|
57
|
-
# [MetaBlocks|MetaBool|MetaInline|MetaList|MetaMap|MetaString|MetaValue]
|
58
|
-
# the value to set
|
59
|
+
# @param value [MetaBlocks|MetaBool|MetaInlines|MetaList|MetaMap|MetaString|MetaValue] the value to set
|
59
60
|
def []=(key, value)
|
60
61
|
@children[key] = value
|
61
62
|
end
|
62
63
|
|
63
|
-
#
|
64
|
+
# Execute block for each key-value pair
|
65
|
+
def each()
|
66
|
+
@children.each do |key, value|
|
67
|
+
yield(key, value)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Mixin the YAML code into this metadata object
|
72
|
+
#
|
73
|
+
# @param yaml_string [YAML] A string with YAML data
|
74
|
+
# @return [MetaMap] this MetaMap object
|
75
|
+
#
|
76
|
+
# @example Set some properties in the metadata
|
77
|
+
# #!/usr/bin/env ruby
|
78
|
+
# require "paru/filter"
|
79
|
+
# require "date"
|
80
|
+
#
|
81
|
+
# Paru::Filter.run do
|
82
|
+
# metadata.yaml <<~YAML
|
83
|
+
# ---
|
84
|
+
# date: #{Date.today.to_s}
|
85
|
+
# title: This **is** the title
|
86
|
+
# pandoc_options:
|
87
|
+
# from: markdown
|
88
|
+
# toc: true
|
89
|
+
# keywords:
|
90
|
+
# - metadata
|
91
|
+
# - pandoc
|
92
|
+
# - filter
|
93
|
+
# ...
|
94
|
+
# YAML
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
def yaml(yaml_string)
|
98
|
+
meta_from_yaml(yaml_string).each do |key, value|
|
99
|
+
self[key] = value
|
100
|
+
end
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
# Replace the property in this MetaMap matching the selector with
|
105
|
+
# metadata specified by second parameter. If that parameter is a
|
106
|
+
# String, it is treated as a YAML string.
|
107
|
+
#
|
108
|
+
# @param selector [String] a dot-separated sequence of property
|
109
|
+
# names denoting a sequence of descendants.
|
110
|
+
#
|
111
|
+
# @param value [MetaBlocks|MetaBool|MetaInlines|MetaList|MetaMap|MetaString|MetaValue|String]
|
112
|
+
# if value is a String, it is treated as a yaml string
|
113
|
+
def replace(selector, value)
|
114
|
+
parent = select(selector, true)
|
115
|
+
if value.is_a? String
|
116
|
+
value = meta_from_yaml(value)
|
117
|
+
end
|
118
|
+
parent.children[last_key(selector)] = value
|
119
|
+
end
|
120
|
+
|
121
|
+
# Get the property in this MetaMap matching the selector
|
122
|
+
#
|
123
|
+
# @param selector [String] a dot-separated sequence of property
|
124
|
+
# names denoting a sequence of descendants.
|
125
|
+
#
|
126
|
+
# @return [MetaBlocks|MetaBool|MetaInlines|MetaList|MetaMap|MetaString|MetaValue] the value matching the selected property, nil if it cannot be found
|
127
|
+
def get(selector)
|
128
|
+
select(selector)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Has this MetaMap a descendant matching selector?
|
64
132
|
#
|
65
|
-
# @param
|
133
|
+
# @param selector [String] a dot-separated sequence of property
|
134
|
+
# names denoting a sequence of descendants
|
66
135
|
#
|
67
|
-
# @return [Boolean]
|
68
|
-
|
69
|
-
|
136
|
+
# @return [Boolean] True if this MetaMap contains a descendant
|
137
|
+
# matching selector, false otherwise
|
138
|
+
def has?(selector)
|
139
|
+
not select(selector).nil?
|
70
140
|
end
|
71
141
|
|
72
|
-
# Delete the
|
142
|
+
# Delete the property in this MetaMap that matches the selector
|
143
|
+
#
|
144
|
+
# @param selector [String] a dot-separated sequence of property
|
145
|
+
# names denoting a sequence of descendants
|
146
|
+
#
|
147
|
+
# @return [MetaBlocks|MetaBool|MetaInlines|MetaList|MetaMap|MetaString|MetaValue] the value of the deleted property, nil if it cannot be found
|
73
148
|
#
|
74
|
-
|
75
|
-
|
76
|
-
|
149
|
+
def delete(selector)
|
150
|
+
if has?(selector)
|
151
|
+
parent = select(selector, true)
|
152
|
+
parent.children.delete(last_key(selector))
|
153
|
+
else
|
154
|
+
nil
|
155
|
+
end
|
77
156
|
end
|
78
157
|
|
79
158
|
# The AST contents
|
@@ -84,6 +163,54 @@ module Paru
|
|
84
163
|
end
|
85
164
|
ast
|
86
165
|
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
# Select a node given a selector as a dot separated sequence of
|
170
|
+
# descendant names.
|
171
|
+
#
|
172
|
+
# @param selector [String] Dot separated sequence of property
|
173
|
+
# names
|
174
|
+
#
|
175
|
+
# @param get_parent [Boolean = false] Get the parent MetaMap
|
176
|
+
# of the selected property instead of its value
|
177
|
+
#
|
178
|
+
# @return [MetaBlocks|MetaBool|MetaInlines|MetaList|MetaMap|MetaString|MetaValue] the value of the deleted property, nil if it cannot be found
|
179
|
+
def select(selector, get_parent = false)
|
180
|
+
keys = selector.split(".")
|
181
|
+
level = self
|
182
|
+
|
183
|
+
while not keys.empty?
|
184
|
+
key = keys.shift
|
185
|
+
if not level.children.has_key? key
|
186
|
+
return nil
|
187
|
+
else
|
188
|
+
if get_parent and keys.empty?
|
189
|
+
return level
|
190
|
+
else
|
191
|
+
level = level[key]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
level
|
197
|
+
end
|
198
|
+
|
199
|
+
# Get the last key in this selector
|
200
|
+
def last_key(selector)
|
201
|
+
selector.split(".").last
|
202
|
+
end
|
203
|
+
|
204
|
+
# Convert a yaml string to a MetaMap
|
205
|
+
def meta_from_yaml(yaml_string)
|
206
|
+
json_string = Pandoc.new do
|
207
|
+
from "markdown"
|
208
|
+
to "json"
|
209
|
+
end << yaml_string
|
210
|
+
|
211
|
+
meta_doc = PandocFilter::Document.from_JSON json_string
|
212
|
+
meta_doc.meta.to_meta_map
|
213
|
+
end
|
87
214
|
end
|
88
215
|
end
|
89
216
|
end
|
data/lib/paru/filter/node.rb
CHANGED
@@ -69,6 +69,32 @@ module Paru
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
72
|
+
|
73
|
+
# Create a new node from a markdown string. This is always a block
|
74
|
+
# level node. If more
|
75
|
+
# than one new node is created, a {Div} is created as a parent for
|
76
|
+
# the newly created block nodes..
|
77
|
+
#
|
78
|
+
# @param markdown_string [String] the markdown string to convert
|
79
|
+
# to a AST node
|
80
|
+
#
|
81
|
+
# @return [Block|Div] The {Block} node created by converting
|
82
|
+
# markdown_string with pandoc; A {Div} node if this conversion
|
83
|
+
# holds more than one {Block} node.
|
84
|
+
def self.from_markdown(markdown_string)
|
85
|
+
node = Node.new []
|
86
|
+
node.outer_markdown = markdown_string
|
87
|
+
|
88
|
+
if node.children.size == 1
|
89
|
+
node = node.children.first
|
90
|
+
else
|
91
|
+
container = from_markdown "<div></div>"
|
92
|
+
container.children = node.children
|
93
|
+
node = container
|
94
|
+
end
|
95
|
+
|
96
|
+
return node
|
97
|
+
end
|
72
98
|
|
73
99
|
# For each child of this Node, yield the child
|
74
100
|
#
|
@@ -184,6 +210,21 @@ module Paru
|
|
184
210
|
false
|
185
211
|
end
|
186
212
|
|
213
|
+
# Convert this Node to a metadata value. If this Node
|
214
|
+
# {is_inline?}, it is converted to {MetaInlines} if it is
|
215
|
+
# {is_block?}, it is converted to {MetaBlocks}.
|
216
|
+
#
|
217
|
+
# @return [MetaInlines|MetaBlocks]
|
218
|
+
def toMetadata()
|
219
|
+
if is_inline? then
|
220
|
+
MetaInlines.new to_ast, true
|
221
|
+
elsif is_blocks? then
|
222
|
+
MetaBlocks.new to_ast, false
|
223
|
+
else
|
224
|
+
# ?
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
187
228
|
# If this node has attributes with classes, is name among them?
|
188
229
|
#
|
189
230
|
# @param name [String] the class name to search for
|
data/lib/paru/filter/plain.rb
CHANGED
@@ -20,9 +20,9 @@ module Paru
|
|
20
20
|
module PandocFilter
|
21
21
|
require_relative "./block"
|
22
22
|
|
23
|
-
# A Plain node is a basic Block level node with Inline
|
24
|
-
# to be confused with Para, which represents a paragraph. A Plain
|
25
|
-
# is more general.
|
23
|
+
# A Plain node is a basic {Block} level node with {Inline} child nodes. Not
|
24
|
+
# to be confused with {Para}, which represents a paragraph. A Plain
|
25
|
+
# is a more general type of block level node.
|
26
26
|
class Plain < Block
|
27
27
|
|
28
28
|
# Create a new Plain node based on contents
|
@@ -0,0 +1,101 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
##
|
3
|
+
# pandoc2yaml.rb extracts the metadata from a pandoc markdown file and prints
|
4
|
+
# that metadata out again as a pandoc markdown file with nothing in it but that
|
5
|
+
# metadata
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# pandoc2yaml.rb input_file
|
10
|
+
#
|
11
|
+
##
|
12
|
+
module Paru
|
13
|
+
module Pandoc2Yaml
|
14
|
+
require "json"
|
15
|
+
require_relative "./pandoc.rb"
|
16
|
+
|
17
|
+
# Paru converters:
|
18
|
+
# Note. When converting metadata back to the pandoc markdown format, you have
|
19
|
+
# to use the option "standalone", otherwise the metadata is skipped
|
20
|
+
PANDOC_2_JSON = Paru::Pandoc.new {from "markdown"; to "json"}
|
21
|
+
JSON_2_PANDOC = Paru::Pandoc.new {from "json"; to "markdown"; standalone}
|
22
|
+
|
23
|
+
# When converting a pandoc document to JSON, or vice versa, the JSON object
|
24
|
+
# has the following three properties:
|
25
|
+
VERSION = "pandoc-api-version"
|
26
|
+
META = "meta"
|
27
|
+
BLOCKS = "blocks"
|
28
|
+
|
29
|
+
# Extract the YAML metadata from input document
|
30
|
+
#
|
31
|
+
# @param input_document [String] path to input document
|
32
|
+
# @return [String] YAML metadata from input document on STDOUT
|
33
|
+
def self.extract_metadata input_document
|
34
|
+
json = JSON.parse(PANDOC_2_JSON << File.read(input_document))
|
35
|
+
yaml = ""
|
36
|
+
|
37
|
+
version, metadata = json.values_at(VERSION, META)
|
38
|
+
|
39
|
+
if not metadata.empty? then
|
40
|
+
metadata_document = {
|
41
|
+
VERSION => version,
|
42
|
+
META => metadata,
|
43
|
+
BLOCKS => []
|
44
|
+
}
|
45
|
+
|
46
|
+
yaml = JSON_2_PANDOC << JSON.generate(metadata_document)
|
47
|
+
end
|
48
|
+
|
49
|
+
yaml
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if __FILE__ == $0
|
54
|
+
require 'optparse'
|
55
|
+
|
56
|
+
parser = OptionParser.new do |opts|
|
57
|
+
opts.banner = "pandoc2yaml.rb mines a pandoc markdown file for its YAML metadata"
|
58
|
+
opts.banner << "\n\nUsage: pandoc2yaml.rb some-pandoc-markdownfile.md"
|
59
|
+
opts.separator ""
|
60
|
+
opts.separator "Common options"
|
61
|
+
|
62
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
63
|
+
puts opts
|
64
|
+
exit
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on("-v", "--version", "Show version") do
|
68
|
+
puts "pandoc2yaml.rb is part of paru version 0.2.3"
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
parser.parse! ARGV
|
74
|
+
|
75
|
+
input_document = ARGV.pop
|
76
|
+
|
77
|
+
if ARGV.size != 0 then
|
78
|
+
warn "Expecting exactly one argument: the pandoc file to strip for metadata"
|
79
|
+
puts ""
|
80
|
+
puts parser
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
|
84
|
+
document = File.expand_path input_document
|
85
|
+
if not File.exist? document
|
86
|
+
warn "Cannot find file: #{input_document}"
|
87
|
+
exit
|
88
|
+
end
|
89
|
+
|
90
|
+
if !File.readable? document
|
91
|
+
warn "Cannot read file: #{input_document}"
|
92
|
+
exit
|
93
|
+
end
|
94
|
+
|
95
|
+
yaml = Pandoc2Yaml.extract_metadata(document)
|
96
|
+
|
97
|
+
yaml = "---\n..." if yaml.empty?
|
98
|
+
|
99
|
+
puts yaml
|
100
|
+
end
|
101
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paru
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.4.
|
4
|
+
version: 0.2.4.5
|
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-05-
|
11
|
+
date: 2017-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Use Pandoc (http://www.pandoc.org) with ruby
|
14
14
|
email: Huub@heerdebeer.org
|
@@ -81,6 +81,7 @@ files:
|
|
81
81
|
- lib/paru/filter/target.rb
|
82
82
|
- lib/paru/filter/version.rb
|
83
83
|
- lib/paru/pandoc.rb
|
84
|
+
- lib/paru/pandoc2yaml.rb
|
84
85
|
- lib/paru/pandoc_options.yaml
|
85
86
|
- lib/paru/selector.rb
|
86
87
|
homepage: https://heerdebeer.org/Software/markdown/paru/
|