paru 1.5.0 → 1.5.1
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/error.rb +6 -4
- data/lib/paru/filter/ast_manipulation.rb +90 -91
- data/lib/paru/filter/attr.rb +75 -69
- data/lib/paru/filter/block.rb +15 -14
- data/lib/paru/filter/block_quote.rb +14 -12
- data/lib/paru/filter/bullet_list.rb +17 -16
- data/lib/paru/filter/caption.rb +50 -48
- data/lib/paru/filter/cell.rb +52 -50
- data/lib/paru/filter/citation.rb +53 -51
- data/lib/paru/filter/cite.rb +34 -33
- data/lib/paru/filter/code.rb +51 -49
- data/lib/paru/filter/code_block.rb +76 -76
- data/lib/paru/filter/col_spec.rb +58 -56
- data/lib/paru/filter/definition_list.rb +51 -52
- data/lib/paru/filter/definition_list_item.rb +45 -43
- data/lib/paru/filter/div.rb +37 -35
- data/lib/paru/filter/document.rb +112 -115
- data/lib/paru/filter/emph.rb +7 -5
- data/lib/paru/filter/empty_block.rb +17 -16
- data/lib/paru/filter/empty_inline.rb +23 -22
- data/lib/paru/filter/figure.rb +41 -39
- data/lib/paru/filter/header.rb +41 -39
- data/lib/paru/filter/horizontal_rule.rb +7 -5
- data/lib/paru/filter/image.rb +13 -12
- data/lib/paru/filter/inline.rb +27 -26
- data/lib/paru/filter/inner_markdown.rb +60 -62
- data/lib/paru/filter/int_value.rb +19 -18
- data/lib/paru/filter/line_block.rb +13 -11
- data/lib/paru/filter/line_break.rb +7 -5
- data/lib/paru/filter/link.rb +34 -33
- data/lib/paru/filter/list.rb +37 -37
- data/lib/paru/filter/list_attributes.rb +52 -51
- data/lib/paru/filter/math.rb +66 -64
- data/lib/paru/filter/meta.rb +40 -39
- data/lib/paru/filter/meta_blocks.rb +7 -5
- data/lib/paru/filter/meta_bool.rb +7 -5
- data/lib/paru/filter/meta_inlines.rb +9 -7
- data/lib/paru/filter/meta_list.rb +7 -5
- data/lib/paru/filter/meta_map.rb +50 -49
- data/lib/paru/filter/meta_string.rb +7 -6
- data/lib/paru/filter/meta_value.rb +26 -25
- data/lib/paru/filter/metadata.rb +150 -88
- data/lib/paru/filter/node.rb +400 -406
- data/lib/paru/filter/note.rb +29 -29
- data/lib/paru/filter/null.rb +7 -5
- data/lib/paru/filter/ordered_list.rb +50 -49
- data/lib/paru/filter/para.rb +21 -20
- data/lib/paru/filter/plain.rb +23 -21
- data/lib/paru/filter/quoted.rb +28 -26
- data/lib/paru/filter/short_caption.rb +7 -5
- data/lib/paru/filter/small_caps.rb +8 -7
- data/lib/paru/filter/soft_break.rb +7 -5
- data/lib/paru/filter/space.rb +7 -5
- data/lib/paru/filter/span.rb +29 -27
- data/lib/paru/filter/str.rb +33 -32
- data/lib/paru/filter/strikeout.rb +7 -6
- data/lib/paru/filter/strong.rb +7 -6
- data/lib/paru/filter/subscript.rb +7 -6
- data/lib/paru/filter/superscript.rb +7 -6
- data/lib/paru/filter/table.rb +201 -210
- data/lib/paru/filter/table_body.rb +67 -67
- data/lib/paru/filter/table_end.rb +53 -55
- data/lib/paru/filter/table_foot.rb +8 -7
- data/lib/paru/filter/table_head.rb +8 -7
- data/lib/paru/filter/target.rb +29 -27
- data/lib/paru/filter/underline.rb +7 -5
- data/lib/paru/filter/value.rb +74 -75
- data/lib/paru/filter/version.rb +23 -22
- data/lib/paru/filter.rb +355 -331
- data/lib/paru/filter_error.rb +7 -5
- data/lib/paru/info.rb +29 -30
- data/lib/paru/pandoc.rb +241 -248
- data/lib/paru/pandoc2yaml.rb +51 -42
- data/lib/paru/selector.rb +193 -184
- data/lib/paru.rb +3 -1
- metadata +4 -73
data/lib/paru/filter/metadata.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
#--
|
2
|
-
# Copyright 2015
|
4
|
+
# Copyright 2015--2025 Huub de Beer <Huub@heerdebeer.org>
|
3
5
|
#
|
4
6
|
# This file is part of Paru
|
5
7
|
#
|
@@ -16,99 +18,159 @@
|
|
16
18
|
# You should have received a copy of the GNU General Public License
|
17
19
|
# along with Paru. If not, see <http://www.gnu.org/licenses/>.
|
18
20
|
#++
|
19
|
-
require
|
20
|
-
require_relative
|
21
|
-
require_relative
|
21
|
+
require 'yaml'
|
22
|
+
require_relative '../pandoc'
|
23
|
+
require_relative '../filter_error'
|
22
24
|
|
23
25
|
module Paru
|
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
|
-
contents = YAML.safe_load yaml_string, permitted_classes: [Date]
|
53
|
-
end
|
54
|
-
|
55
|
-
if not contents
|
56
|
-
# Error parsing YAML
|
57
|
-
raise FilterError.new("Unable to convert YAML string '#{yaml_string}' to a Hash.")
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# Merge the contents with this newly created Metadata
|
62
|
-
contents.each do |key, value|
|
63
|
-
self[key] = value
|
64
|
-
end
|
65
|
-
end
|
26
|
+
module PandocFilter
|
27
|
+
# A Metadata object is a Ruby Hash representation of a pandoc metadata
|
28
|
+
# node.
|
29
|
+
class Metadata < Hash
|
30
|
+
# Create a new Metadata object based on the contents.
|
31
|
+
#
|
32
|
+
# @param contents [MetaMap|String|Hash] the initial contents of this
|
33
|
+
# metadata. If contents is a String, it is treated as a YAML string
|
34
|
+
# and converted to a Hash first.
|
35
|
+
# @param treat_metadata_strings_as_plain_strings [Boolean = false] treat
|
36
|
+
# metadata string values as plain strings instead of markdown strings if
|
37
|
+
# all AST leaf metadata string values have pandoc type "MetaString". This
|
38
|
+
# option is only relevant when you **only** set metadata string values via
|
39
|
+
# command-line option `--metadata` and not also via a YAML or title block.
|
40
|
+
# Using this option improves performance in this specific situation
|
41
|
+
# because metadata values don't have to be converted to string by pandoc
|
42
|
+
# in a separate process but can be collected as is.
|
43
|
+
#
|
44
|
+
# @raise Error when converting contents to a Hash fails
|
45
|
+
def initialize(contents = {}, treat_metadata_strings_as_plain_strings: false)
|
46
|
+
# When feature toggle treat_metadata_strings_as_plain_strings is on,
|
47
|
+
# try to map the MetaMap node to a Hash directly and use that as the
|
48
|
+
# contents of this Metadata object. We can only map the MetaMap node
|
49
|
+
# when all string values have pandoc type "MetaString".
|
50
|
+
if treat_metadata_strings_as_plain_strings && contents.is_a?(PandocFilter::MetaMap)
|
51
|
+
metadata_hash = meta_to_value(contents)
|
52
|
+
contents = metadata_hash unless metadata_hash.nil?
|
53
|
+
end
|
66
54
|
|
67
|
-
|
68
|
-
# metadata: {PandocFilter::Meta}
|
69
|
-
#
|
70
|
-
# @return [Meta] the pandoc AST representation as a {PandocFilter::Meta} node
|
71
|
-
def to_meta()
|
72
|
-
if self.empty?
|
73
|
-
PandocFilter::Meta.new {}
|
74
|
-
else
|
75
|
-
begin
|
76
|
-
yaml_string = "#{clean_hash.to_yaml}..."
|
77
|
-
yaml2json = Paru::Pandoc.new {from "markdown"; to "json"}
|
78
|
-
json_string = yaml2json << yaml_string
|
79
|
-
meta_doc = PandocFilter::Document.from_JSON json_string
|
80
|
-
meta_doc.meta
|
81
|
-
rescue
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
55
|
+
contents = convert_to_hash_via_yaml(contents) unless contents.is_a?(Hash)
|
85
56
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
begin
|
94
|
-
json2yaml = Paru::Pandoc.new {from "json"; to "markdown"; standalone}
|
95
|
-
meta = PandocFilter::Meta.from_meta_map(meta) unless meta.is_a? PandocFilter::Meta
|
96
|
-
meta_doc = PandocFilter::Document.new(PandocFilter::CURRENT_PANDOC_VERSION, meta.to_ast, [])
|
97
|
-
yaml_string = json2yaml << meta_doc.to_JSON
|
98
|
-
yaml_string.strip
|
99
|
-
rescue
|
100
|
-
end
|
101
|
-
end
|
57
|
+
# Merge the contents with this newly created Metadata
|
58
|
+
super()
|
59
|
+
|
60
|
+
contents.each do |key, value|
|
61
|
+
self[key] = value
|
62
|
+
end
|
63
|
+
end
|
102
64
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
65
|
+
# Convert this Metadata to a pandoc AST representation of
|
66
|
+
# metadata: {PandocFilter::Meta}
|
67
|
+
#
|
68
|
+
# @return [Meta] the pandoc AST representation as a {PandocFilter::Meta} node
|
69
|
+
def to_meta
|
70
|
+
if empty?
|
71
|
+
PandocFilter::Meta.new({})
|
72
|
+
else
|
73
|
+
begin
|
74
|
+
yaml_string = "#{clean_hash.to_yaml}..."
|
75
|
+
yaml2json = Paru::Pandoc.new do
|
76
|
+
from 'markdown'
|
77
|
+
to 'json'
|
111
78
|
end
|
79
|
+
json_string = yaml2json << yaml_string
|
80
|
+
meta_doc = PandocFilter::Document.from_JSON json_string
|
81
|
+
meta_doc.meta
|
82
|
+
rescue StandardError
|
83
|
+
# Ignore silently to not interfere with pandoc conversion
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Convert a {PandocFilter::Meta} node to a Metadata
|
91
|
+
#
|
92
|
+
# @param meta [Meta|MetaMap] the {PandocFilter::Meta} node to convert to a
|
93
|
+
# MetadataHash
|
94
|
+
def meta2yaml(meta)
|
95
|
+
json2yaml = Paru::Pandoc.new do
|
96
|
+
from 'json'
|
97
|
+
to 'markdown'
|
98
|
+
standalone
|
99
|
+
end
|
100
|
+
meta = PandocFilter::Meta.from_meta_map(meta) unless meta.is_a? PandocFilter::Meta
|
101
|
+
meta_doc = PandocFilter::Document.new(PandocFilter::CURRENT_PANDOC_VERSION, meta.to_ast, [])
|
102
|
+
yaml_string = json2yaml << meta_doc.to_JSON
|
103
|
+
yaml_string.strip
|
104
|
+
rescue StandardError
|
105
|
+
# Ignore silently to not interfere with pandoc conversion
|
106
|
+
end
|
107
|
+
|
108
|
+
# Create a true Hash from this Metadata to prevent the +to_yaml+
|
109
|
+
# method from mixing in the name of this class and confusing pandoc
|
110
|
+
def clean_hash
|
111
|
+
hash = {}
|
112
|
+
each do |key, value|
|
113
|
+
hash[key] = value
|
114
|
+
end
|
115
|
+
hash
|
116
|
+
end
|
117
|
+
|
118
|
+
def convert_to_hash_via_yaml(contents)
|
119
|
+
# If not a Hash, it is either a YAML string or can be
|
120
|
+
# converted to a YAML string
|
121
|
+
if contents.is_a? PandocFilter::MetaMap
|
122
|
+
yaml_string = meta2yaml contents
|
123
|
+
elsif contents.is_a? String
|
124
|
+
yaml_string = contents
|
125
|
+
else
|
126
|
+
raise FilterError, "Expected a Hash, MetaMap, or String, got '#{contents}' instead."
|
127
|
+
end
|
128
|
+
|
129
|
+
# Try to convert the YAML string to a Hash
|
130
|
+
contents = if yaml_string.empty?
|
131
|
+
{}
|
132
|
+
else
|
133
|
+
YAML.safe_load yaml_string, permitted_classes: [Date]
|
134
|
+
end
|
135
|
+
|
136
|
+
unless contents
|
137
|
+
# Error parsing YAML
|
138
|
+
raise FilterError, "Unable to convert YAML string '#{yaml_string}' to a Hash."
|
139
|
+
end
|
140
|
+
|
141
|
+
contents
|
142
|
+
end
|
143
|
+
|
144
|
+
def meta_to_value(value)
|
145
|
+
case value
|
146
|
+
when MetaBlocks, MetaInlines
|
147
|
+
# MetaBlocks and MetaInlines represent pandoc formatted markdown
|
148
|
+
# nodes. Needs to be converted by pandoc.
|
149
|
+
nil
|
150
|
+
when MetaValue
|
151
|
+
value.value.to_s
|
152
|
+
when MetaList
|
153
|
+
value.map do |m|
|
154
|
+
mapped = meta_to_value(m)
|
155
|
+
|
156
|
+
return nil if mapped.nil?
|
157
|
+
|
158
|
+
mapped
|
159
|
+
end
|
160
|
+
when MetaMap
|
161
|
+
mapped_map = {}
|
162
|
+
|
163
|
+
value.each do |k, m|
|
164
|
+
mapped = meta_to_value(m)
|
165
|
+
|
166
|
+
return nil if mapped.nil?
|
167
|
+
|
168
|
+
mapped_map[k] = mapped
|
169
|
+
end
|
170
|
+
|
171
|
+
mapped_map
|
112
172
|
end
|
173
|
+
end
|
113
174
|
end
|
175
|
+
end
|
114
176
|
end
|