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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49f91b95228c398d4ed7e752c9780d4a56bdb128
4
- data.tar.gz: 6096c105a736e686a02e2fc16f1d1985c55dfb05
3
+ metadata.gz: b681740521f95d8baa1e31caa9476e035ef65c72
4
+ data.tar.gz: d9af38ecf31b7116af24fc46ae232c0fa7fdcf4e
5
5
  SHA512:
6
- metadata.gz: 5cf262bca810cbae0f4dffae889de6cc4d53fcc466cc6ea3ad342484aef86a54878933cca5e120fac569b6938d92e5d1c14627f412546349b8bae898a282f77f
7
- data.tar.gz: a79687986c7709c5489efdb59bca496669d3ae1dd7b31397e64a9b5092d1f3b55a673c41463e68e400814066e49483c1db74243775e802affc85a4ffbaea9154
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
- require_relative "./pandoc2yaml.rb"
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
- metadata = YAML.load Pandoc2Yaml.extract_metadata(document)
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 #{input}"
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
- module Pandoc2Yaml
13
- require "json"
14
- require "paru/pandoc"
12
+ require "json"
13
+ require 'optparse'
14
+ require 'paru/pandoc2yaml'
15
15
 
16
- # Paru converters:
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
- puts opts
60
- exit
23
+ puts opts
24
+ exit
61
25
  end
62
26
 
63
27
  opts.on("-v", "--version", "Show version") do
64
- puts "pandoc2yaml.rb is part of paru version 0.2.3"
65
- exit
28
+ puts "pandoc2yaml.rb is part of paru version 0.2.3"
29
+ exit
66
30
  end
67
- end
31
+ end
68
32
 
69
- parser.parse! ARGV
33
+ parser.parse! ARGV
70
34
 
71
- input_document = ARGV.pop
35
+ input_document = ARGV.pop
72
36
 
73
- if ARGV.size != 0 then
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
- end
42
+ end
79
43
 
80
- document = File.expand_path input_document
81
- if not File.exist? document
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
- end
48
+ end
85
49
 
86
- if !File.readable? document
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
@@ -20,7 +20,8 @@ module Paru
20
20
  require "paru/pandoc"
21
21
  require "paru/error"
22
22
  require "paru/filter"
23
+ require "paru/pandoc2yaml"
23
24
 
24
25
  # Paru's current version
25
- VERSION = [0, 2, 4, 4]
26
+ VERSION = [0, 2, 4, 5]
26
27
  end
data/lib/paru/filter.rb CHANGED
@@ -198,11 +198,23 @@ module Paru
198
198
  #
199
199
  class Filter
200
200
 
201
- # Run the filter specified by block. In the block you specify
202
- # selectors and actions to be performed on selected nodes. In the
203
- # example below, the selector is "Image", which selects all image
204
- # nodes. The action is to prepend the contents of the image's caption
205
- # by the string "Figure. ".
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 $stdin.read
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
- puts @doc.to_JSON
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 = @children.find_index old_child
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
@@ -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
- @id, @classes, @data = attributes
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
@@ -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[0].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
@@ -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 Blocks
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
@@ -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
- if @children.key_exists?
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
- # Does this MetaMap node have key?
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 key [String] the key to find
133
+ # @param selector [String] a dot-separated sequence of property
134
+ # names denoting a sequence of descendants
66
135
  #
67
- # @return [Boolean] true if this MetaMap node contains this key
68
- def has_key?(key)
69
- @children.has_key? key
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 key-value pair from this MetaMap
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
- # @param key [String] the key to delete
75
- def delete(key)
76
- @children.delete key
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
@@ -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
@@ -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 children. Not
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
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-19 00:00:00.000000000 Z
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/