paru 0.2.4.2 → 0.2.4.3
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/paru.rb +8 -20
- data/lib/paru/error.rb +4 -6
- data/lib/paru/filter.rb +144 -110
- data/lib/paru/filter/ast_manipulation.rb +75 -39
- data/lib/paru/filter/attr.rb +72 -36
- data/lib/paru/filter/block.rb +14 -8
- data/lib/paru/filter/block_quote.rb +12 -9
- data/lib/paru/filter/bullet_list.rb +6 -6
- data/lib/paru/filter/citation.rb +51 -25
- data/lib/paru/filter/cite.rb +29 -20
- data/lib/paru/filter/code.rb +41 -24
- data/lib/paru/filter/code_block.rb +36 -21
- data/lib/paru/filter/definition_list.rb +19 -15
- data/lib/paru/filter/definition_list_item.rb +30 -17
- data/lib/paru/filter/div.rb +29 -21
- data/lib/paru/filter/document.rb +73 -46
- data/lib/paru/filter/emph.rb +6 -6
- data/lib/paru/filter/empty_block.rb +17 -13
- data/lib/paru/filter/empty_inline.rb +24 -17
- data/lib/paru/filter/header.rb +38 -23
- data/lib/paru/filter/image.rb +13 -11
- data/lib/paru/filter/inline.rb +21 -10
- data/lib/paru/filter/line_block.rb +6 -6
- data/lib/paru/filter/line_break.rb +6 -6
- data/lib/paru/filter/link.rb +33 -21
- data/lib/paru/filter/list.rb +26 -17
- data/lib/paru/filter/list_attributes.rb +53 -32
- data/lib/paru/filter/markdown.rb +102 -59
- data/lib/paru/filter/math.rb +65 -38
- data/lib/paru/filter/meta.rb +26 -16
- data/lib/paru/filter/meta_blocks.rb +12 -9
- data/lib/paru/filter/meta_bool.rb +6 -6
- data/lib/paru/filter/meta_inlines.rb +12 -9
- data/lib/paru/filter/meta_list.rb +6 -6
- data/lib/paru/filter/meta_map.rb +49 -33
- data/lib/paru/filter/meta_string.rb +6 -6
- data/lib/paru/filter/meta_value.rb +22 -14
- data/lib/paru/filter/node.rb +204 -129
- data/lib/paru/filter/note.rb +31 -20
- data/lib/paru/filter/null.rb +6 -6
- data/lib/paru/filter/ordered_list.rb +34 -18
- data/lib/paru/filter/para.rb +20 -13
- data/lib/paru/filter/plain.rb +21 -12
- data/lib/paru/filter/quoted.rb +27 -18
- data/lib/paru/filter/raw_block.rb +32 -19
- data/lib/paru/filter/raw_inline.rb +40 -22
- data/lib/paru/filter/small_caps.rb +7 -6
- data/lib/paru/filter/soft_break.rb +6 -6
- data/lib/paru/filter/space.rb +6 -6
- data/lib/paru/filter/span.rb +28 -18
- data/lib/paru/filter/str.rb +29 -18
- data/lib/paru/filter/strikeout.rb +6 -6
- data/lib/paru/filter/strong.rb +6 -6
- data/lib/paru/filter/subscript.rb +6 -6
- data/lib/paru/filter/superscript.rb +6 -6
- data/lib/paru/filter/table.rb +51 -29
- data/lib/paru/filter/table_row.rb +21 -14
- data/lib/paru/filter/target.rb +29 -15
- data/lib/paru/filter/version.rb +23 -14
- data/lib/paru/pandoc.rb +165 -111
- data/lib/paru/pandoc_options.yaml +3 -3
- data/lib/paru/selector.rb +176 -153
- metadata +2 -3
- data/lib/paru/filter/alignment.rb +0 -30
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright 2015, 2016 Huub de Beer <Huub@heerdebeer.org>
|
2
|
+
# Copyright 2015, 2016, 2017 Huub de Beer <Huub@heerdebeer.org>
|
3
3
|
#
|
4
4
|
# This file is part of Paru
|
5
5
|
#
|
@@ -16,7 +16,7 @@
|
|
16
16
|
# You should have received a copy of the GNU General Public License
|
17
17
|
# along with Paru. If not, see <http://www.gnu.org/licenses/>.
|
18
18
|
# See http://pandoc.org/README.html for an overview of all options
|
19
|
-
|
19
|
+
#++
|
20
20
|
# General options
|
21
21
|
from: ""
|
22
22
|
read: ""
|
@@ -41,7 +41,7 @@ file_scope: true
|
|
41
41
|
filter: [""]
|
42
42
|
metadata: [""]
|
43
43
|
normalize: true
|
44
|
-
preserve_tabs:
|
44
|
+
preserve_tabs: true
|
45
45
|
tab_stop: 4
|
46
46
|
track_changes: "accept"
|
47
47
|
extract_media: true
|
data/lib/paru/selector.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright 2015, 2016 Huub de Beer <Huub@heerdebeer.org>
|
2
|
+
# Copyright 2015, 2016, 2017 Huub de Beer <Huub@heerdebeer.org>
|
3
3
|
#
|
4
4
|
# This file is part of Paru
|
5
5
|
#
|
@@ -17,157 +17,180 @@
|
|
17
17
|
# along with Paru. If not, see <http://www.gnu.org/licenses/>.
|
18
18
|
#++
|
19
19
|
module Paru
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
20
|
+
require_relative './filter'
|
21
|
+
require_relative './error'
|
22
|
+
|
23
|
+
# SelectorParseError is thrown when there is an error parsing a selector
|
24
|
+
# used in a filter.
|
25
|
+
class SelectorParseError < Error
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
# A Selector models a relationship between Pandoc AST nodes, such as
|
30
|
+
# parent-child or sibling. Selectors in paru are like CSS selectors, but
|
31
|
+
# more limited because the Pandoc AST is quite simple.
|
32
|
+
#
|
33
|
+
# Given a selector expression, Selector determines if a node complies with
|
34
|
+
# that selector expression or not.
|
35
|
+
class Selector
|
36
|
+
|
37
|
+
# Create a new Selector based on the selector string
|
38
|
+
#
|
39
|
+
# @param selector [String] the selector string
|
40
|
+
def initialize(selector)
|
41
|
+
@type = 'Unknown'
|
42
|
+
@relations = []
|
43
|
+
parse selector
|
44
|
+
end
|
45
|
+
|
46
|
+
# Does node get selected by this Selector in the context of the already filtered
|
47
|
+
# nodes?
|
48
|
+
#
|
49
|
+
# @param node [Node] the node to check against this Selector
|
50
|
+
# @param filtered_nodes [Array<Node>] the context of filtered nodes to take
|
51
|
+
# into account as well
|
52
|
+
#
|
53
|
+
# @return [Boolean] True if the node in the context of the
|
54
|
+
# filtered_nodes is selected by this Selector
|
55
|
+
def matches? node, filtered_nodes
|
56
|
+
node.type == @type and
|
57
|
+
@classes.all? {|c| node.has_class? c } and
|
58
|
+
@relations.all? {|r| r.matches? node, filtered_nodes}
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
S = /\s*/
|
64
|
+
TYPE = /(?<type>(?<name>[A-Z][a-zA-Z]*)(?<classes>(\.[a-zA-Z-]+)*))/
|
65
|
+
OTHER_TYPE = /(?<other_type>(?<other_name>[A-Z][a-zA-Z]*)(?<other_classes>(\.[a-zA-Z-]+)*))/
|
66
|
+
OPERATOR = /(?<operator>\+|-|>)/
|
67
|
+
DISTANCE = /(?<distance>[1-9][0-9]*)/
|
68
|
+
RELATION = /(?<relation>#{S}#{OTHER_TYPE}#{S}#{OPERATOR}#{S}#{DISTANCE}?#{S})/
|
69
|
+
RELATIONS = /(?<relations>#{RELATION}+)/
|
70
|
+
SELECTOR = /\A#{S}(?<selector>#{RELATIONS}?#{S}#{TYPE})#{S}\Z/
|
71
|
+
|
72
|
+
# Parse the selector_string to construct this Selector
|
73
|
+
def parse(selector_string)
|
74
|
+
partial_match = expect_match SELECTOR, selector_string
|
75
|
+
@type, @classes = expect_pandoc_type partial_match
|
76
|
+
|
77
|
+
while continue_parsing? partial_match
|
78
|
+
operator = expect partial_match, :operator
|
79
|
+
distance = expect_integer partial_match, :distance
|
80
|
+
type, classes = expect_pandoc_other_type partial_match
|
81
|
+
|
82
|
+
@relations.push Relation.new(operator, distance, type, classes)
|
83
|
+
|
84
|
+
partial_match = rest partial_match
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Is type actually a Pandoc AST node type?
|
89
|
+
def is_pandoc_type(type)
|
90
|
+
Paru::PANDOC_TYPES.include? type
|
91
|
+
end
|
92
|
+
|
93
|
+
def expect(parts, part)
|
94
|
+
raise SelectorParseError.new "Expected #{part}" if parts[part].nil?
|
95
|
+
parts[part]
|
96
|
+
end
|
97
|
+
|
98
|
+
def expect_match(regexp, string)
|
99
|
+
match = regexp.match string
|
100
|
+
raise SelectorParseError.new "Unable to parse '#{string}'" if match.nil?
|
101
|
+
match
|
102
|
+
end
|
103
|
+
|
104
|
+
def expect_pandoc_type(parts)
|
105
|
+
type = expect parts, :name
|
106
|
+
classes = parts[:classes].split(".").select {|c| not c.empty?} if not parts[:classes].nil?
|
107
|
+
raise SelectorParseError.new "Expected a Pandoc type, got '#{type}' instead" if not is_pandoc_type type
|
108
|
+
[type, classes]
|
109
|
+
end
|
110
|
+
|
111
|
+
def expect_pandoc_other_type(parts)
|
112
|
+
type = expect parts, :other_name
|
113
|
+
classes = parts[:other_classes].split('.').select {|c| not c.empty?} if not parts[:other_classes].nil?
|
114
|
+
raise SelectorParseError.new "Expected a Pandoc type, got '#{type}' instead" if not is_pandoc_type type
|
115
|
+
[type, classes]
|
116
|
+
end
|
117
|
+
|
118
|
+
def expect_integer(parts, part)
|
119
|
+
if parts[part].nil?
|
120
|
+
number = 0
|
121
|
+
else
|
122
|
+
number = parts[part].to_i
|
123
|
+
raise SelectorParseError.new "Expected a positive #{part}, got '#{parts[part]}' instead" if number <= 0
|
124
|
+
end
|
125
|
+
number
|
126
|
+
end
|
127
|
+
|
128
|
+
def continue_parsing?(parts)
|
129
|
+
not parts.nil? and not parts[:relations].nil?
|
130
|
+
end
|
131
|
+
|
132
|
+
def rest(parts)
|
133
|
+
rest_string = parts[:relations].slice 0, parts[:relations].size - parts[:relation].size
|
134
|
+
RELATIONS.match rest_string
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# @private
|
139
|
+
class Relation
|
140
|
+
def initialize(selector, distance, type, classes)
|
141
|
+
@selector = selector
|
142
|
+
@distance = distance
|
143
|
+
@type = type
|
144
|
+
@classes = classes
|
145
|
+
end
|
146
|
+
|
147
|
+
def matches?(node, filtered_nodes)
|
148
|
+
level_nodes = filtered_nodes.keep_if do |n|
|
149
|
+
node.is_inline? == n.is_inline? or
|
150
|
+
node.can_act_as_both_block_and_inline?
|
151
|
+
end
|
152
|
+
previous_nodes = previous level_nodes, @distance
|
153
|
+
case @selector
|
154
|
+
when '+'
|
155
|
+
in_sequence? node, previous_nodes
|
156
|
+
when '-'
|
157
|
+
not_in_sequence? node, previous_nodes
|
158
|
+
when '>'
|
159
|
+
is_descendant? node
|
160
|
+
else
|
161
|
+
false
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def in_sequence?(node, previous_nodes)
|
166
|
+
previous_nodes.any? do |other|
|
167
|
+
other.type == @type and @classes.all? {|c| other.has_class? c}
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def not_in_sequence?(node, previous_nodes)
|
172
|
+
previous_nodes.all? do |other|
|
173
|
+
other.type != @type or not @classes.all? {|c| other.has_class? c}
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def is_descendant?(node)
|
178
|
+
distance = 0
|
179
|
+
begin
|
180
|
+
distance += 1 if @distance > 0
|
181
|
+
parent = node.parent
|
182
|
+
ancestry = parent.type == @type and @classes.all? {|c| parent.has_class? c}
|
183
|
+
end while not ancestry and not parent.is_root? and distance <= @distance
|
184
|
+
ancestry
|
185
|
+
end
|
186
|
+
|
187
|
+
def previous(filtered_nodes, distance)
|
188
|
+
distance = [distance, filtered_nodes.size - 1].min
|
189
|
+
if distance <= 0
|
190
|
+
filtered_nodes.slice(0, filtered_nodes.size - 1)
|
191
|
+
else
|
192
|
+
filtered_nodes.slice(-1 * distance - 1, distance)
|
193
|
+
end
|
194
|
+
end
|
73
195
|
end
|
74
|
-
|
75
|
-
def expect_match regexp, string
|
76
|
-
match = regexp.match string
|
77
|
-
raise SelectorParseError.new "Unable to parse '#{string}'" if match.nil?
|
78
|
-
match
|
79
|
-
end
|
80
|
-
|
81
|
-
def expect_pandoc_type parts
|
82
|
-
type = expect parts, :name
|
83
|
-
classes = parts[:classes].split(".").select {|c| not c.empty?} if not parts[:classes].nil?
|
84
|
-
raise SelectorParseError.new "Expected a Pandoc type, got '#{type}' instead" if not is_pandoc_type type
|
85
|
-
[type, classes]
|
86
|
-
end
|
87
|
-
|
88
|
-
def expect_pandoc_other_type parts
|
89
|
-
type = expect parts, :other_name
|
90
|
-
classes = parts[:other_classes].split(".").select {|c| not c.empty?} if not parts[:other_classes].nil?
|
91
|
-
raise SelectorParseError.new "Expected a Pandoc type, got '#{type}' instead" if not is_pandoc_type type
|
92
|
-
[type, classes]
|
93
|
-
end
|
94
|
-
|
95
|
-
def expect_integer parts, part
|
96
|
-
if parts[part].nil?
|
97
|
-
number = 0
|
98
|
-
else
|
99
|
-
number = parts[part].to_i
|
100
|
-
raise SelectorParseError.new "Expected a positive #{part}, got '#{parts[part]}' instead" if number <= 0
|
101
|
-
end
|
102
|
-
number
|
103
|
-
end
|
104
|
-
|
105
|
-
def continue_parsing? parts
|
106
|
-
not parts.nil? and not parts[:relations].nil?
|
107
|
-
end
|
108
|
-
|
109
|
-
def rest parts
|
110
|
-
rest_string = parts[:relations].slice 0, parts[:relations].size - parts[:relation].size
|
111
|
-
RELATIONS.match rest_string
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
class Relation
|
116
|
-
def initialize selector, distance, type, classes
|
117
|
-
@selector = selector
|
118
|
-
@distance = distance
|
119
|
-
@type = type
|
120
|
-
@classes = classes
|
121
|
-
end
|
122
|
-
|
123
|
-
def matches? node, filtered_nodes
|
124
|
-
level_nodes = filtered_nodes.keep_if do |n|
|
125
|
-
node.is_inline? == n.is_inline? or
|
126
|
-
node.can_act_as_both_block_and_inline?
|
127
|
-
end
|
128
|
-
previous_nodes = previous level_nodes, @distance
|
129
|
-
case @selector
|
130
|
-
when "+"
|
131
|
-
in_sequence? node, previous_nodes
|
132
|
-
when "-"
|
133
|
-
not_in_sequence? node, previous_nodes
|
134
|
-
when ">"
|
135
|
-
is_descendant? node
|
136
|
-
else
|
137
|
-
false
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def in_sequence? node, previous_nodes
|
142
|
-
previous_nodes.any? do |other|
|
143
|
-
other.type == @type and @classes.all? {|c| other.has_class? c}
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def not_in_sequence? node, previous_nodes
|
148
|
-
previous_nodes.all? do |other|
|
149
|
-
other.type != @type or not @classes.all? {|c| other.has_class? c}
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def is_descendant? node
|
154
|
-
distance = 0
|
155
|
-
begin
|
156
|
-
distance += 1 if @distance > 0
|
157
|
-
parent = node.parent
|
158
|
-
ancestry = parent.type == @type and @classes.all? {|c| parent.has_class? c}
|
159
|
-
end while not ancestry and not parent.is_root? and distance <= @distance
|
160
|
-
ancestry
|
161
|
-
end
|
162
|
-
|
163
|
-
def previous filtered_nodes, distance
|
164
|
-
distance = [distance, filtered_nodes.size - 1].min
|
165
|
-
if distance <= 0
|
166
|
-
filtered_nodes.slice(0, filtered_nodes.size - 1)
|
167
|
-
else
|
168
|
-
filtered_nodes.slice(-1 * distance - 1, distance)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
196
|
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.3
|
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-
|
11
|
+
date: 2017-05-19 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
|
@@ -23,7 +23,6 @@ files:
|
|
23
23
|
- lib/paru.rb
|
24
24
|
- lib/paru/error.rb
|
25
25
|
- lib/paru/filter.rb
|
26
|
-
- lib/paru/filter/alignment.rb
|
27
26
|
- lib/paru/filter/ast_manipulation.rb
|
28
27
|
- lib/paru/filter/attr.rb
|
29
28
|
- lib/paru/filter/block.rb
|
@@ -1,30 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright 2015, 2016 Huub de Beer <Huub@heerdebeer.org>
|
3
|
-
#
|
4
|
-
# This file is part of Paru
|
5
|
-
#
|
6
|
-
# Paru is free software: you can redistribute it and/or modify
|
7
|
-
# it under the terms of the GNU General Public License as published by
|
8
|
-
# the Free Software Foundation, either version 3 of the License, or
|
9
|
-
# (at your option) any later version.
|
10
|
-
#
|
11
|
-
# Paru is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
# GNU General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU General Public License
|
17
|
-
# along with Paru. If not, see <http://www.gnu.org/licenses/>.
|
18
|
-
#++
|
19
|
-
module Paru
|
20
|
-
module PandocFilter
|
21
|
-
|
22
|
-
class Alignment
|
23
|
-
ALIGNMENTS = ["AlignLeft", "AlignRight", "AlignCenter", "AlignDefault"]
|
24
|
-
|
25
|
-
def initialize config
|
26
|
-
@config = config
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|