pandocomatic 0.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9bb00b9f3b336ff545db723e8148c4328f31523f
4
+ data.tar.gz: 5efa1bc50a8f98269467ef14b72e41715f4f4706
5
+ SHA512:
6
+ metadata.gz: a0c11901a985c60c0103cd53796fb884c180568cabb35ce001b476c661f07553c9c14bd027603a0cc66f21b233294f60fc46cfd8944ec758b7fe0c8e5596ce7d
7
+ data.tar.gz: a19731270d23f2ca21acf6fdf5fe017fe8a629aff100661669c69f758396ff59ba0fe33dcd25d7f40aafe853645a7f328860aaaf335b6105f605c7c6ce42135d
data/bin/pandoc2yaml ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'trollop'
4
+ require 'yaml'
5
+
6
+ require_relative '../lib/pandocomatic/pandoc_metadata.rb'
7
+
8
+ opts = Trollop::options do
9
+ version "pandoc2yaml 1"
10
+ banner <<-EOB
11
+
12
+ pandoc2yaml collects the metadata in a pandoc markdown file and exports it to
13
+ yaml.
14
+
15
+ Usage:
16
+
17
+ pandoc2yaml [-o output.yaml] input.markdown
18
+
19
+ Options:
20
+ EOB
21
+
22
+ opt :output, "optional output file, use STDOUT as default", :type => :string
23
+ end
24
+
25
+ begin
26
+ if ARGV.length != 1 then
27
+ Trollop::die "pandoc2yaml expects one input file as argument"
28
+ end
29
+
30
+ input = ARGV.first
31
+
32
+ Trollop::die "#{input} does not exist" if not File.exist? input
33
+ Trollop::die "#{input} is not a file" if not File.file? input
34
+ Trollop::die "#{input} is not readable" if not File.readable? input
35
+
36
+ metadata = YAML.dump Pandocomatic::PandocMetadata.load_file input
37
+
38
+ if opts[:output].nil? then
39
+ $stdout << metadata
40
+ else
41
+ File.open(opts[:output], "w") do |file|
42
+ file << metadata
43
+ end
44
+ end
45
+
46
+ rescue Exception => e
47
+ warn "Error while collecting metadata: #{e.message}"
48
+ end
data/bin/pandocomatic ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'trollop'
4
+ require 'yaml'
5
+
6
+ require_relative '../lib/pandocomatic/dir_converter.rb'
7
+ require_relative '../lib/pandocomatic/file_converter.rb'
8
+ require_relative '../lib/pandocomatic/configuration.rb'
9
+
10
+ def convert_file input, opts
11
+ puts "converting file"
12
+ end
13
+
14
+ def convert_dir input, opts
15
+ puts "converting dir"
16
+ end
17
+
18
+ def convert_tree input, opts
19
+ puts "Converting tree"
20
+ end
21
+
22
+ opts = Trollop::options do
23
+ version "pandocomatic 0.0.1"
24
+ banner <<-EOB
25
+
26
+ Pandocomatic automates the use of pandoc (<http://www.pandoc.org>). It can be
27
+ used to convert a file, a directory, or a directory tree.
28
+
29
+ Usage:
30
+
31
+ Convert a file
32
+
33
+ pandocomatic [--config file.yaml] --output output.file input.file
34
+
35
+ Convert a directory or directory tree
36
+
37
+ pandocomatic [--config file.yaml] [--recursive] --output output.dir input.dir
38
+
39
+ Options:
40
+ EOB
41
+ opt :config, "pandocomatic configuration file", :type => :string
42
+ opt :recursive, "apply pandocomatic recursively"
43
+ opt :target, "named conversion target", :type => :string
44
+ opt :output, "output file or directory", :type => :string
45
+ end
46
+
47
+ # input file/directory
48
+ Trollop::die "Expect exactly one input file or directory" if ARGV.length != 1
49
+ input = ARGV.first
50
+
51
+ Trollop::die "Expect an output file or directory" if opts[:output].nil?
52
+ output = opts[:output]
53
+
54
+ # Configuration
55
+ if opts[:config].nil? then
56
+ config = Pandocomatic::Configuration.new
57
+ else
58
+ if not File.exist? opts[:config] or not File.readable? opts[:config] then
59
+ Trollop::die "Cannot read configuration file #{opts[:config]}" if File
60
+ end
61
+
62
+ config = Pandocomatic::Configuration.new YAML.load_file opts[:config]
63
+ end
64
+
65
+
66
+ if File.directory? input then
67
+ if File.exist? output and not File.directory? output then
68
+ Trollop::die "Expected an output directory, found a file instead"
69
+ end
70
+
71
+ config.configure({'recursive' => true}) if opts[:recursive]
72
+ Pandocomatic::DirConverter.new(input, output, config).convert
73
+
74
+ else
75
+ # input is one file
76
+ Pandocomatic::FileConverter.new.convert input, output, config
77
+ end
@@ -0,0 +1,124 @@
1
+ module Pandocomatic
2
+
3
+ require 'paru/pandoc'
4
+
5
+ DEFAULT_CONFIG = {
6
+ 'recursive' => true,
7
+ 'follow_links' => false,
8
+ 'skip' => ['.*', 'pandocomatic.yaml'],
9
+ 'targets' => {
10
+ 'markdown' => {
11
+ 'pattern' => ['*.markdown', '*.md'],
12
+ 'pandoc' => {
13
+ 'from' => 'markdown',
14
+ 'to' => 'html5'
15
+ }
16
+ }
17
+ }
18
+ }
19
+
20
+ FORMAT_TO_EXT = {
21
+ 'native' => 'hs',
22
+ 'markdown_strict' => 'markdown',
23
+ 'markdown_phpextra' => 'markdown',
24
+ 'markdown_github' => 'markdown',
25
+ 'html5' => 'html',
26
+ 'docx' => 'docx',
27
+ 'latex' => 'tex'
28
+ }
29
+
30
+ class Configuration
31
+
32
+ def initialize hash = DEFAULT_CONFIG
33
+ @config = {
34
+ 'recursive' => true,
35
+ 'follow_links' => false,
36
+ 'skip' => ['.*'],
37
+ 'targets' => {}
38
+ }
39
+ @convert_patterns = {}
40
+ configure hash
41
+ end
42
+
43
+ def configure options
44
+ options.each do |key, value|
45
+ if key == 'targets' then
46
+ update_targets value
47
+ else
48
+ @config[key] = value
49
+ end
50
+ end
51
+ end
52
+
53
+ def reconfigure options
54
+ new_config = Marshal.load(Marshal.dump(self))
55
+ new_config.configure options
56
+ new_config
57
+ end
58
+
59
+ def marshal_dump
60
+ [@config, @convert_patterns]
61
+ end
62
+
63
+ def marshal_load array
64
+ @config, @convert_patterns = array
65
+ end
66
+
67
+ def update_targets targets
68
+ targets.each do |name, options|
69
+ @config['targets'][name] = options
70
+ @convert_patterns[name] = options['pattern']
71
+ end
72
+ end
73
+
74
+ def skip? src
75
+ @config['skip'].any? {|pattern| File.fnmatch pattern, File.basename(src)}
76
+ end
77
+
78
+ def convert? src
79
+ @convert_patterns.values.flatten.any? {|pattern| File.fnmatch pattern, File.basename(src)}
80
+ end
81
+
82
+ def recursive?
83
+ @config['recursive']
84
+ end
85
+
86
+ def follow_links?
87
+ @config['follow_links']
88
+ end
89
+
90
+ def set_extension dst
91
+ dir = File.dirname dst
92
+ ext = File.extname dst
93
+ basename = File.basename dst, ext
94
+ File.join dir, "#{basename}.#{find_extension dst}"
95
+ end
96
+
97
+ def find_extension dst
98
+ target = determine_target dst
99
+ if target.nil? then
100
+ extension = 'html'
101
+ else
102
+ to = @config['targets'][target]['pandoc']['to']
103
+ extension = FORMAT_TO_EXT[to] || to
104
+ end
105
+ end
106
+
107
+
108
+ def get_target_config target
109
+ @config['targets'][target]
110
+ end
111
+
112
+ def determine_target src
113
+ @convert_patterns.select do |target, patterns|
114
+ patterns.any? {|pattern| File.fnmatch pattern, File.basename(src)}
115
+ end.keys.first
116
+ end
117
+
118
+ def to_s
119
+ @config
120
+ end
121
+
122
+ end
123
+
124
+ end
@@ -0,0 +1,107 @@
1
+ module Pandocomatic
2
+
3
+ require 'fileutils'
4
+
5
+ require_relative 'file_converter.rb'
6
+
7
+ CONFIG_FILE = 'pandocomatic.yaml'
8
+
9
+ class DirConverter
10
+
11
+ def initialize src, dst, config
12
+ @src_root = src
13
+ @dst_root = dst
14
+ @config = config
15
+ end
16
+
17
+ def convert src_dir = @src_root, dst_dir = @dst_root, config = @config
18
+
19
+ ensure_directory dst_dir
20
+ config = reconfigure config, src_dir
21
+
22
+ # Convert each file and subdirectory according to the specifications set in config
23
+ Dir.foreach src_dir do |filename|
24
+ src = File.join src_dir, filename
25
+
26
+ next if config.skip? src
27
+
28
+ dst = File.join dst_dir, filename
29
+
30
+ if File.directory? src and config.recursive?
31
+
32
+ # Convert subdirectories only when the recursivity is set in the
33
+ # configuration.
34
+ convert src, dst, config
35
+
36
+ elsif File.symlink? src and not config.follow_links
37
+
38
+ recreate_link src, dst
39
+
40
+ elsif File.file? src
41
+
42
+ raise "Cannot read file #{src}" if not File.readable? src
43
+ raise "Cannot write file #{dst}" if File.exist? dst and not File.writable? dst
44
+
45
+ # Check if the source file has to be converted. If so, convert;
46
+ # otherwise, copy it to the destination tree
47
+ if config.convert? src then
48
+ dst = config.set_extension dst
49
+ Pandocomatic::FileConverter.new.convert src, dst, config
50
+ else
51
+ # copy file
52
+ FileUtils.cp src, dst
53
+ end
54
+
55
+ else
56
+ warn "Unclear what to do with #{src}, skipping this file"
57
+ next
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+
64
+ private
65
+
66
+ # If the source directory contains a configuration file, use it to
67
+ # reconfigure the converter. Otherwise, use the current configuration
68
+ def reconfigure current_config, src_dir
69
+ config_file = File.join src_dir, CONFIG_FILE
70
+ if File.exist? config_file then
71
+ require 'yaml'
72
+ current_config.reconfigure YAML.load_file config_file
73
+ else
74
+ current_config
75
+ end
76
+ end
77
+
78
+ # Ensure that dir exist (and is a directory)
79
+ def ensure_directory dir
80
+ if Dir.exist? dir then
81
+ raise "#{dir} is not a directory" if not File.directory? dir
82
+ else
83
+ begin
84
+ Dir.mkdir dir
85
+ rescue SystemCallError => e
86
+ raise "Error trying to create directory #{dir}: #{e.message}"
87
+ end
88
+ end
89
+ end
90
+
91
+ # Recreate source link in destination tree if it points to somewhere inside
92
+ # the source tree
93
+ def recreate_link src, dst
94
+ src_target = File.readlink(src)
95
+ full_src_target = File.realpath src_target
96
+ if full_src_target.start_with? @src_root
97
+ dst_target = File.join @dst_root, src_target
98
+ File.symlink dst_target, dst
99
+ else
100
+ warn "Skipping link #{src} because it points to outside the source tree"
101
+ end
102
+ end
103
+
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,74 @@
1
+ module Pandocomatic
2
+
3
+
4
+ require 'paru/pandoc'
5
+ require_relative 'pandoc_metadata.rb'
6
+
7
+ class FileConverter
8
+
9
+ def initialize
10
+ end
11
+
12
+ def convert src, dst, current_config
13
+ metadata = PandocMetadata.load_file src
14
+
15
+ if metadata.has_target? then
16
+ target = metadata.target
17
+ else
18
+ target = current_config.determine_target src
19
+ end
20
+
21
+ config = current_config.get_target_config target
22
+ pandoc_options = (config['pandoc'] || {}).merge(metadata.pandoc_options || {})
23
+
24
+ input = File.read src
25
+ input = preprocess input, config
26
+ input = pandoc input, pandoc_options
27
+ output = postprocess input, config
28
+
29
+ if dst.to_s.empty? and metadata.pandoc_options.has_key? 'output'
30
+ dst = metadata.pandoc_options['output']
31
+ end
32
+
33
+ File.open( dst, 'w') do |file|
34
+ file << output
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def pandoc input, options
41
+ converter = Paru::Pandoc.new
42
+ options.each do |option, value|
43
+ converter.send option, value unless option == 'output'
44
+ # don't let pandoc write the output to enable postprocessing
45
+ end
46
+ converter << input
47
+ end
48
+
49
+ def preprocess input, config
50
+ process input, 'preprocessors', config
51
+ end
52
+
53
+ def postprocess input, config
54
+ process input, 'postprocessors', config
55
+ end
56
+
57
+ # Run the input string through a list of filters called processors. There
58
+ # are to types: preprocessors and postprocessors
59
+ def process input, type, config
60
+ if config.has_key? type then
61
+ processors = config[type]
62
+ output = input
63
+ processors.each do |processor|
64
+ output = processor << output
65
+ end
66
+ else
67
+ input
68
+ end
69
+ end
70
+
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,63 @@
1
+ module Pandocomatic
2
+
3
+ require 'json'
4
+ require 'yaml'
5
+ require 'paru/pandoc'
6
+
7
+ require_relative 'configuration.rb'
8
+
9
+ class PandocMetadata < Hash
10
+
11
+ def initialize hash = {}
12
+ super
13
+ merge! hash
14
+ end
15
+
16
+ # Collect the metadata embedded in the src file
17
+ def self.load_file src
18
+ begin
19
+ json_reader = Paru::Pandoc.new {from 'markdown'; to 'json'}
20
+ json_document = JSON.parse json_reader << File.read(src)
21
+ if json_document.first["unMeta"].empty? then
22
+ return PandocMetadata.new
23
+ else
24
+ json_metadata = [json_document.first, []]
25
+ json_writer = Paru::Pandoc.new {from 'json'; to 'markdown'; standalone}
26
+ yaml_metadata = json_writer << JSON.generate(json_metadata)
27
+ return PandocMetadata.new YAML.load yaml_metadata
28
+ end
29
+ rescue Exception => e
30
+ raise "Error while reading metadata from #{src}; Are you sure it is a pandoc markdown file?\n#{e.message}"
31
+ end
32
+ end
33
+
34
+ def has_target?
35
+ has_key? 'pandocomatic' and self['pandocomatic'].has_key? 'target'
36
+ end
37
+
38
+ def target
39
+ if has_target? then
40
+ self['pandocomatic']['target']
41
+ else
42
+ ''
43
+ end
44
+ end
45
+
46
+ def has_pandoc_options?
47
+ has_key? 'pandocomatic' and self['pandocomatic'].has_key? 'pandoc'
48
+ end
49
+
50
+ def pandoc_options
51
+ if has_pandoc_options? then
52
+ self['pandocomatic']['pandoc']
53
+ else
54
+ {}
55
+ end
56
+ end
57
+
58
+ def to_configuration parent_config = Configuration.new
59
+ end
60
+
61
+ end
62
+
63
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pandocomatic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Huub de Beer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: paru
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.0.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.0.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: trollop
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 2.0.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '2.0'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 2.0.0
53
+ description: 'Automate the use of pandoc <http://pandoc.org>: use pandocomatic as
54
+ a makefile to convert one file, a whole directory of files, or even as a static
55
+ site generator.'
56
+ email: Huub@heerdebeer.org
57
+ executables:
58
+ - pandocomatic
59
+ - pandoc2yaml
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - bin/pandoc2yaml
64
+ - bin/pandocomatic
65
+ - lib/pandocomatic/configuration.rb
66
+ - lib/pandocomatic/dir_converter.rb
67
+ - lib/pandocomatic/file_converter.rb
68
+ - lib/pandocomatic/pandoc_metadata.rb
69
+ homepage: https://github.com/htdebeer/pandocomatic
70
+ licenses:
71
+ - GPL3
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements:
88
+ - pandoc, a universal document converer <http://pandoc.org>
89
+ rubyforge_project:
90
+ rubygems_version: 2.2.2
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Automate the use of pandoc
94
+ test_files: []