rakali 0.0.8

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: 5a9db33f283b3c0c005337c9f4e278198b72f5a0
4
+ data.tar.gz: dd9193ea8f7ffedff4bf346554ec5901a282f69a
5
+ SHA512:
6
+ metadata.gz: 9a35a109180245835fecac87d95a514483ca9975b2757ed7aa32c92f904135da4eb7298680c86c1445fe465e44490741c3f81b4f5f2577b873477ed434ec6173
7
+ data.tar.gz: ee50a5a11353568443edafdbb5255b753b018e54520f362457790c3b7a98dfa3e845ca45a792647d016c3848382806058bde03bae6485c115d0f52f2bdd5f95c
data/bin/rakali ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path("../../lib/rakali", __FILE__)
4
+
5
+ Rakali::CLI.start
data/lib/rakali.rb ADDED
@@ -0,0 +1,22 @@
1
+ require "thor"
2
+ require 'safe_yaml/load'
3
+ require 'colorator'
4
+ require 'json-schema'
5
+ require 'json'
6
+ require 'open3'
7
+
8
+ require 'rakali/version'
9
+ require 'rakali/cli'
10
+ require 'rakali/converter'
11
+ require 'rakali/document'
12
+ require 'rakali/utils'
13
+ require 'rakali/logger'
14
+
15
+ SafeYAML::OPTIONS[:suppress_warnings] = false
16
+ SafeYAML::OPTIONS[:default_mode] = :safe
17
+
18
+ module Rakali
19
+ def self.logger
20
+ @logger ||= Logger.new
21
+ end
22
+ end
data/lib/rakali/cli.rb ADDED
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+
3
+ module Rakali
4
+ class CLI < Thor
5
+ def self.exit_on_failure?
6
+ true
7
+ end
8
+
9
+ desc "read FILE", "read configuration FILE in yaml format"
10
+
11
+ def convert(file)
12
+ converter = Rakali::Converter.new(file)
13
+
14
+ # don't proceed unless input validates against schema
15
+ unless converter.valid?
16
+ message = "Error: input did not validate with schema #{converter.schema["title"]}\n" + converter.errors.join("\n")
17
+ raise Thor::Error, message
18
+ end
19
+ end
20
+
21
+ default_task :convert
22
+ end
23
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: UTF-8
2
+
3
+ module Rakali
4
+ class Converter
5
+
6
+ # Default options.
7
+ DEFAULTS = {
8
+ 'from' => { 'format' => 'md' },
9
+ 'to' => { 'folder' => nil, 'format' => 'html' },
10
+ 'schema' => 'schemata/default.json',
11
+ 'strict' => false,
12
+ 'templates' => 'rakali/templates',
13
+ 'csl' => 'rakali/csl',
14
+ 'bibliography' => 'rakali/bibliography',
15
+ 'filters' => 'rakali/filters',
16
+ 'writers' => 'rakali/writers'
17
+ }
18
+
19
+ attr_accessor :config, :documents, :errors
20
+
21
+ def initialize(file, options = {})
22
+ begin
23
+ config = read_config_file(file)
24
+
25
+ # deep merge defaults to preserve nested keys
26
+ @config = Utils.deep_merge_hashes(DEFAULTS, config)
27
+
28
+ # print configuration
29
+ Rakali.logger.info "Starting:", "Reading configuration... \n#{to_yaml}"
30
+
31
+ from_folder = @config.fetch('from').fetch('folder')
32
+ from_format = @config.fetch('from').fetch('format')
33
+ documents = Dir.glob("#{from_folder}/*.#{from_format}")
34
+ @documents = documents.map { |document| Rakali::Document.new(document, @config) }
35
+ rescue KeyError => e
36
+ Rakali.logger.abort_with "Fatal:", "Configuration #{e.message}."
37
+ rescue => e
38
+ Rakali.logger.abort_with "Fatal:", "#{e.message}."
39
+ end
40
+ end
41
+
42
+ def read_config_file(file)
43
+ # use an empty hash if the file is empty
44
+ SafeYAML.load_file(file) || {}
45
+ rescue SystemCallError
46
+ Rakali.logger.abort_with "Fatal:", "Configuration file not found: \"#{file}\"."
47
+ end
48
+
49
+ def from_json(string)
50
+ JSON.parse(string)
51
+ rescue JSON::ParserError, TypeError
52
+ nil
53
+ end
54
+
55
+ def to_json
56
+ content.to_json
57
+ end
58
+
59
+ def to_yaml
60
+ config.to_yaml
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,95 @@
1
+ # encoding: UTF-8
2
+
3
+ module Rakali
4
+ class Document
5
+
6
+ attr_accessor :config, :source, :destination, :content, :schema, :errors, :to_folder
7
+
8
+ def initialize(document, config)
9
+ begin
10
+ @config = config
11
+
12
+ @from_folder = @config.fetch('from').fetch('folder')
13
+ @from_format = @config.fetch('from').fetch('format')
14
+ @to_folder = @config.fetch('to').fetch('folder') || @from_folder
15
+ @to_format = @config.fetch('to').fetch('format')
16
+ #config_path = File.expand_path("../config.yml", __FILE__)
17
+
18
+ # for destination filename use source name with new extension
19
+ @source = File.basename(document)
20
+ @destination = @source.sub(/\.#{@from_format}$/, ".#{@to_format}")
21
+
22
+ # convert source document into JSON version of native AST
23
+ @content = convert(nil, "#{@from_folder}/#{@source} -t json")
24
+
25
+ # read in JSON schema
26
+ @schema = IO.read(@config.fetch('schema'))
27
+
28
+ # validate JSON against schema and report errors
29
+ @errors = validate
30
+
31
+ # convert to destination document from JSON version of native AST
32
+ @output = convert(@content, "-f json -o #{@to_folder}/#{@destination}")
33
+ Rakali.logger.abort_with "Fatal:", "Writing file #{@destination} failed" unless created?
34
+
35
+ if @errors.empty?
36
+ Rakali.logger.info "Success:", "Converted file #{@source} to file #{@destination}."
37
+ else
38
+ Rakali.logger.warn "With Errors:", "Converted file #{@source} to file #{@destination}."
39
+ end
40
+ rescue KeyError => e
41
+ Rakali.logger.abort_with "Fatal:", "Configuration #{e.message}."
42
+ rescue => e
43
+ Rakali.logger.abort_with "Fatal:", "#{e.message}."
44
+ end
45
+ end
46
+
47
+ def convert(string = nil, args)
48
+ Open3::popen3("pandoc #{args}") do |stdin, stdout, stderr, wait_thr|
49
+ unless string.nil?
50
+ stdin.puts string
51
+ stdin.close
52
+ end
53
+
54
+ # abort with log message if exit_status of command not 0
55
+ Rakali.logger.abort_with "Fatal:", "#{stderr.read}." if wait_thr.value.exitstatus > 0
56
+
57
+ stdout.read
58
+ end
59
+ end
60
+
61
+ def validate
62
+ errors = JSON::Validator.fully_validate(@schema, @content)
63
+ return [] if errors.empty?
64
+
65
+ if @config.fetch('strict', false)
66
+ errors.each { |error| Rakali.logger.error "Validation Error:", "#{error} for file #{source}" }
67
+ Rakali.logger.abort_with "Fatal:", "Conversion of file #{source} failed."
68
+ else
69
+ errors.each { |error| Rakali.logger.warn "Validation Error:", "#{error} for file #{source}" }
70
+ end
71
+ end
72
+
73
+ def valid?
74
+ errors == []
75
+ end
76
+
77
+ def created?
78
+ # file exists
79
+ return false unless File.exist?("#{@to_folder}/#{@destination}")
80
+
81
+ # file was created in the last 5 seconds
82
+ Time.now - File.mtime("#{@to_folder}/#{@destination}") < 5
83
+ end
84
+
85
+ def from_json(string)
86
+ JSON.parse(string)
87
+ rescue JSON::ParserError, TypeError
88
+ nil
89
+ end
90
+
91
+ def to_json
92
+ content.to_json
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,92 @@
1
+ # This code was taken from Jekyll, available under MIT-LICENSE
2
+ # Copyright (c) 2008-2014 Tom Preston-Werner
3
+
4
+ module Rakali
5
+ class Logger
6
+ attr_accessor :log_level
7
+
8
+ DEBUG = 0
9
+ INFO = 1
10
+ WARN = 2
11
+ ERROR = 3
12
+
13
+ # Public: Create a new logger instance
14
+ #
15
+ # level - (optional, integer) the log level
16
+ #
17
+ # Returns nothing
18
+ def initialize(level = INFO)
19
+ @log_level = level
20
+ end
21
+
22
+ # Public: Print a debug message to stdout
23
+ #
24
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
25
+ # message - the message detail
26
+ #
27
+ # Returns nothing
28
+ def debug(topic, message = nil)
29
+ $stdout.puts(message(topic, message)) if log_level <= DEBUG
30
+ end
31
+
32
+ # Public: Print a message to stdout
33
+ #
34
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
35
+ # message - the message detail
36
+ #
37
+ # Returns nothing
38
+ def info(topic, message = nil)
39
+ $stdout.puts(message(topic, message)) if log_level <= INFO
40
+ end
41
+
42
+ # Public: Print a message to stderr
43
+ #
44
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
45
+ # message - the message detail
46
+ #
47
+ # Returns nothing
48
+ def warn(topic, message = nil)
49
+ $stderr.puts(message(topic, message).yellow) if log_level <= WARN
50
+ end
51
+
52
+ # Public: Print a error message to stderr
53
+ #
54
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
55
+ # message - the message detail
56
+ #
57
+ # Returns nothing
58
+ def error(topic, message = nil)
59
+ $stderr.puts(message(topic, message).red) if log_level <= ERROR
60
+ end
61
+
62
+ # Public: Print a error message to stderr and immediately abort the process
63
+ #
64
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
65
+ # message - the message detail (can be omitted)
66
+ #
67
+ # Returns nothing
68
+ def abort_with(topic, message = nil)
69
+ error(topic, message)
70
+ abort
71
+ end
72
+
73
+ # Public: Build a topic method
74
+ #
75
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
76
+ # message - the message detail
77
+ #
78
+ # Returns the formatted message
79
+ def message(topic, message)
80
+ formatted_topic(topic) + message.to_s.gsub(/---\n/, '')
81
+ end
82
+
83
+ # Public: Format the topic
84
+ #
85
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
86
+ #
87
+ # Returns the formatted topic statement
88
+ def formatted_topic(topic)
89
+ "#{topic} ".rjust(20)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+
3
+ module Rakali
4
+ class Utils
5
+ # This code was taken from Jekyll, available under MIT-LICENSE
6
+ # Copyright (c) 2008-2014 Tom Preston-Werner
7
+ # Merges a master hash with another hash, recursively.
8
+ #
9
+ # master_hash - the "parent" hash whose values will be overridden
10
+ # other_hash - the other hash whose values will be persisted after the merge
11
+ #
12
+ # This code was lovingly stolen from some random gem:
13
+ # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
14
+ def self.deep_merge_hashes(master_hash, other_hash)
15
+ target = master_hash.dup
16
+
17
+ other_hash.keys.each do |key|
18
+ if other_hash[key].is_a? Hash and target[key].is_a? Hash
19
+ target[key] = deep_merge_hashes(target[key], other_hash[key])
20
+ next
21
+ end
22
+
23
+ target[key] = other_hash[key]
24
+ end
25
+
26
+ target
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Rakali
2
+ VERSION = "0.0.8"
3
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rakali
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.8
5
+ platform: ruby
6
+ authors:
7
+ - Martin Fenner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.19'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.19'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json-schema
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: safe_yaml
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: colorator
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.6'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.6'
97
+ - !ruby/object:Gem::Dependency
98
+ name: cucumber
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.3'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.3'
111
+ - !ruby/object:Gem::Dependency
112
+ name: aruba
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: A Pandoc command-line wrapper written in Ruby.
126
+ email: mf@martinfenner.org
127
+ executables:
128
+ - rakali
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - bin/rakali
133
+ - lib/rakali.rb
134
+ - lib/rakali/cli.rb
135
+ - lib/rakali/converter.rb
136
+ - lib/rakali/document.rb
137
+ - lib/rakali/logger.rb
138
+ - lib/rakali/utils.rb
139
+ - lib/rakali/version.rb
140
+ homepage: https://github.com/rakali/rakali.rb
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: 1.3.6
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.2.2
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: A Pandoc command-line wrapper
164
+ test_files: []