pandocfilters 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d03820dd1432a65258ce231a8c33965755bd6d7e
4
+ data.tar.gz: 3539e051a195ada06037daa752569b618033e725
5
+ SHA512:
6
+ metadata.gz: babf25b565f5fcb466f38afcb7baeecfc81c18a24f48c6fc473350803ddb2f028ea1d78ffdc81b981a4e16fdd1462aaf2423aa554ffeeb7654da91bacbe8d11c
7
+ data.tar.gz: 0da641977ceace8e8802afddb0a57bc8a99472188045b13b05d70da9b89a7670b4aee29c0616dd90b1a0d48f4dcef6486c8bd254127a477abdfb9fd53e8c03de
@@ -0,0 +1,115 @@
1
+ require 'json'
2
+ require_relative 'pandocfilters/node'
3
+
4
+ module PandocFilters
5
+
6
+ # Fetch prebuild filter.
7
+ #
8
+ # @param name [String] Filter name.
9
+ # @return [String] Path to the filter.
10
+ def self.filter(name)
11
+ glob = File.expand_path('../pandocfilters/filters/*' ,__FILE__)
12
+ filters = Dir.glob(glob).map { |f| File.basename(f) }
13
+
14
+ raise "No build-in filter names #{name}" unless filters.include?(name)
15
+
16
+ File.expand_path("../pandocfilters/filters/#{name}" ,__FILE__)
17
+ end
18
+
19
+ # Converts an action into a filter that reads a JSON-formatted
20
+ # pandoc document from stdin, transforms it by walking the tree
21
+ # with the action, and returns a new JSON-formatted pandoc document
22
+ # to stdout. The argument is a function action(key, value, format, meta),
23
+ # where key is the type of the pandoc object (e.g. 'Str', 'Para'),
24
+ # value is the contents of the object (e.g. a string for 'Str',
25
+ # a list of inline elements for 'Para'), format is the target
26
+ # output format (which will be taken for the first command line
27
+ # argument if present), and meta is the document's metadata.
28
+ # If the function returns None, the object to which it applies
29
+ # will remain unchanged. If it returns an object, the object will
30
+ # be replaced. If it returns a list, the list will be spliced in to
31
+ # the list to which the target object belongs. (So, returning an
32
+ # empty list deletes the object.)
33
+ #
34
+ # action Callable object
35
+ #
36
+ # Return Manuplated JSON
37
+ def self.process(&action)
38
+ doc = JSON.load($stdin.read)
39
+ if ARGV.size > 1
40
+ format = ARGV[1]
41
+ else
42
+ format = ""
43
+ end
44
+ altered = self.walk(doc, format, doc[0]['unMeta'], &action)
45
+ JSON.dump(altered, $stdout)
46
+ end
47
+
48
+ # Walks the tree x and returns concatenated string content,
49
+ # leaving out all formatting.
50
+ def self.stringify(x)
51
+ result = []
52
+
53
+ go = lambda do |key, val, format, meta|
54
+ if ['Str', 'MetaString'].include? key
55
+ result.push(val)
56
+ elsif key == 'Code'
57
+ result.push(val[1])
58
+ elsif key == 'Math'
59
+ result.push(val[1])
60
+ elsif key == 'LineBreak'
61
+ result.push(" ")
62
+ elsif key == 'Space'
63
+ result.push(" ")
64
+ end
65
+ end
66
+
67
+ self.walk(x, "", {}, &go)
68
+
69
+ result.join('')
70
+ end
71
+
72
+ # Returns an attribute list, constructed from the
73
+ # dictionary attrs.
74
+ def attributes(attrs)
75
+ attrs ||= {}
76
+ ident = attrs.fetch('id', '')
77
+ classes = attrs.fetch("classes", [])
78
+ keyvals = []
79
+ attrs.keep_if { |k, v| k != "classes" && k != "id" }.each do |k, v|
80
+ keyvals << [k, v]
81
+ end
82
+
83
+ [ident, classes, keyvals]
84
+ end
85
+
86
+ # Walk a tree, applying an action to every object.
87
+ # Returns a modified tree.
88
+ def self.walk(x, format, meta, &action)
89
+ if x.is_a? Array
90
+ array = []
91
+ x.each do |item|
92
+ if item.is_a?(Hash) && item.has_key?('t')
93
+ res = action.call(item['t'], item['c'], format, meta)
94
+ if res.nil?
95
+ array.push(self.walk(item, format, meta, &action))
96
+ elsif res.is_a? Array
97
+ res.each { |z| array.push(self.walk(z, format, meta, &action)) }
98
+ else
99
+ array.push(self.walk(res, format, meta, &action))
100
+ end
101
+ else
102
+ array.push(self.walk(item, format, meta, &action))
103
+ end
104
+ end
105
+ return array
106
+ elsif x.is_a? Hash
107
+ hash = {}
108
+ x.each { |k, _| hash[k] = self.walk(x[k], format, meta, &action) }
109
+ return hash
110
+ else
111
+ return x
112
+ end
113
+ end
114
+
115
+ end
@@ -0,0 +1,11 @@
1
+ class String
2
+
3
+ # Strips off underscores in string, then capitalize each words.
4
+ #
5
+ # @return [String] Camelized string.
6
+ def camelize
7
+ string = self
8
+ string.split('_').map(&:capitalize).join('')
9
+ end
10
+
11
+ end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Paragraph starts with `CITE:' act like blockquote cite.
4
+ # Align the cite to right.
5
+
6
+ require 'pandocfilters'
7
+
8
+ filter = lambda do |key, value, format, meta|
9
+ if key == 'Para' && (cite = PandocFilters.stringify(value)).start_with?('CITE:')
10
+ cite.sub!(/CITE:\s?/, '')
11
+ xml = %(<w:p>
12
+ <w:pPr>
13
+ <w:pStyle w:val="BlockquoteCite"/>
14
+ </w:pPr>
15
+ <w:r>
16
+ <w:t xml:space="preserve">#{cite}</w:t>
17
+ </w:r>
18
+ </w:p>)
19
+
20
+ return PandocFilters::Node.raw_block('openxml', xml)
21
+ end
22
+ end
23
+
24
+ PandocFilters.process &filter
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Identify paragraph starts with `DEDICATION:' as dedication.
4
+ # Then replace the dedication with raw OOXML xml, and trip off the `DEDICATION:'.
5
+ # THe dedication is placed on a new page, and center aligned.
6
+
7
+ require 'pandocfilters'
8
+
9
+ filter = lambda do |key, value, format, meta|
10
+ if key == 'Para'
11
+ if value[0]['c'] == 'DEDICATION:'
12
+ dedication = PandocFilters.stringify(value).sub(/DEDICATION:\s?/, '')
13
+ xml = %(<w:p>
14
+ <w:pPr>
15
+ <w:pStyle w:val="DedicationText"/>
16
+ </w:pPr>
17
+ <w:r>
18
+ <w:t xml:space="preserve">#{dedication}</w:t>
19
+ </w:r>
20
+ </w:p>)
21
+
22
+ PandocFilters::Node.raw_block('openxml', xml)
23
+ elsif value[0]['c'] == 'DEDICATION_FIRST:'
24
+ dedication = PandocFilters.stringify(value).sub(/DEDICATION_FIRST:\s?/, '')
25
+ xml = %(<w:p>
26
+ <w:pPr>
27
+ <w:pStyle w:val="DedicationTextFirst"/>
28
+ </w:pPr>
29
+ <w:r>
30
+ <w:t xml:space="preserve">#{dedication}</w:t>
31
+ </w:r>
32
+ </w:p>)
33
+
34
+ PandocFilters::Node.raw_block('openxml', xml)
35
+ end
36
+ end
37
+ end
38
+
39
+ PandocFilters.process &filter
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Identify paragraph contains `<!--PAGEBREAK-->' as page break in docx.
4
+ # Then replace the page break with raw OOXML xml'.
5
+
6
+ require 'pandocfilters'
7
+
8
+ filter = lambda do |key, value, format, meta|
9
+ if key == 'RawBlock' && value[1] == '<!--PAGEBREAK-->'
10
+ xml = %(<w:p><w:r><w:br w:type="page"/></w:r></w:p>)
11
+
12
+ return PandocFilters::Node.raw_block('openxml', xml)
13
+ end
14
+ end
15
+
16
+ PandocFilters.process &filter
@@ -0,0 +1,80 @@
1
+ require_relative 'core_ext/string'
2
+
3
+ module PandocFilters
4
+ class Node
5
+ # Pandoc build-in node types
6
+ # see http://hackage.haskell.org/package/pandoc-types-1.12.4.3/docs/Text-Pandoc-Definition.html
7
+ #
8
+ # key: node type
9
+ # value: expected arguments number
10
+ NODES = {
11
+ # block elements
12
+ plain: 1,
13
+ para: 1,
14
+ code_block: 2,
15
+ raw_block: 2,
16
+ block_quote: 1,
17
+ ordered_list: 2,
18
+ bullet_list: 1,
19
+ definition_list: 1,
20
+ header: 3,
21
+ horizontal_rule: 0,
22
+ table: 5,
23
+ div: 2,
24
+ null: 0,
25
+
26
+ # inline elements
27
+ str: 1,
28
+ emph: 1,
29
+ strong: 1,
30
+ strikeout: 1,
31
+ superscript: 1,
32
+ subscript: 1,
33
+ small_caps: 1,
34
+ quoted: 2,
35
+ cite: 2,
36
+ code: 2,
37
+ space: 0,
38
+ line_break: 0,
39
+ math: 2,
40
+ raw_inline: 2,
41
+ link: 2,
42
+ image: 2,
43
+ note: 1,
44
+ span: 2
45
+ }
46
+
47
+ class << self
48
+ def method_missing(name, *args)
49
+ raise "undefined #{name} node type" unless NODES.keys.include?(name)
50
+ unless args.size == NODES[name]
51
+ raise "#{name} expects #{NODES[name]} arguments, but given #{args.size}"
52
+ end
53
+
54
+ new(name.to_s.camelize, *args).to_hash
55
+ end
56
+ end
57
+
58
+ attr_reader :type
59
+ attr_reader :args
60
+
61
+ def initialize(type, *args)
62
+ @type = type
63
+ @args = args
64
+ end
65
+
66
+ def to_hash
67
+ xs = case args.size
68
+ when 0
69
+ []
70
+ when 1
71
+ args[0]
72
+ else
73
+ args
74
+ end
75
+
76
+ {'t': type, 'c': xs}
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ module PandocFilters
2
+ VERSION = '0.0.1.alpha'
3
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pandocfilters
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.alpha
5
+ platform: ruby
6
+ authors:
7
+ - Andor Chen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 10.4.2
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 10.4.2
27
+ description: A Ruby gem for writing pandoc filters.
28
+ email: andor.chen.27@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/pandocfilters.rb
34
+ - lib/pandocfilters/core_ext/string.rb
35
+ - lib/pandocfilters/filters/blockquote_cite
36
+ - lib/pandocfilters/filters/dedication
37
+ - lib/pandocfilters/filters/page_break
38
+ - lib/pandocfilters/node.rb
39
+ - lib/pandocfilters/version.rb
40
+ homepage: https://github.com/andorchen/pandocfilters.rb
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.9.3
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">"
56
+ - !ruby/object:Gem::Version
57
+ version: 1.3.1
58
+ requirements:
59
+ - pandoc >= 1.14
60
+ rubyforge_project:
61
+ rubygems_version: 2.4.5
62
+ signing_key:
63
+ specification_version: 2
64
+ summary: A Ruby gem for writing pandoc filters.
65
+ test_files: []