pandocomatic 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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: []