paru 0.2.4.4 → 0.2.4.5
Sign up to get free protection for your applications and to get access to all the features.
- 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/
|