riven 0.0.1
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 +7 -0
- data/.gitignore +34 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +21 -0
- data/LICENSE +20 -0
- data/README.md +130 -0
- data/bin/riven +39 -0
- data/css/style.css +757 -0
- data/lib/riven.rb +3 -0
- data/lib/riven/html_file.rb +17 -0
- data/lib/riven/html_generator.rb +57 -0
- data/lib/riven/markup/code.rb +44 -0
- data/lib/riven/markup/code_block.rb +27 -0
- data/lib/riven/markup_file.rb +40 -0
- data/lib/riven/opt_parser.rb +77 -0
- data/lib/riven/version.rb +3 -0
- data/lib/riven/wkhtmltopdf.rb +27 -0
- data/riven.gemspec +32 -0
- metadata +118 -0
data/lib/riven.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Riven
|
2
|
+
class HTMLFile
|
3
|
+
attr_accessor :file_name
|
4
|
+
|
5
|
+
public def initialize(file_name)
|
6
|
+
@file_name = file_name
|
7
|
+
end
|
8
|
+
|
9
|
+
public def write(content)
|
10
|
+
File.open(@file_name, 'w') { |file| file.write(content) }
|
11
|
+
end
|
12
|
+
|
13
|
+
public def delete!
|
14
|
+
File.delete @file_name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'riven/html_file'
|
3
|
+
require 'riven/markup/code'
|
4
|
+
require 'redcarpet'
|
5
|
+
|
6
|
+
module Riven
|
7
|
+
class HTMLGenerator
|
8
|
+
attr_accessor :html, :html_file
|
9
|
+
|
10
|
+
public def initialize(markup)
|
11
|
+
@html_file = Riven::HTMLFile.new('_riven_tmp_file.html')
|
12
|
+
|
13
|
+
@markup = markup
|
14
|
+
|
15
|
+
@html = generate_html
|
16
|
+
@html_file.write(@html)
|
17
|
+
end
|
18
|
+
|
19
|
+
public def generate_html
|
20
|
+
css = File.read(File.expand_path(File.dirname(__FILE__)) + '/../../css/style.css')
|
21
|
+
|
22
|
+
html = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
|
23
|
+
html << '<style type="text/css">' + css + '</style></head><body>'
|
24
|
+
html << markup_to_html(@markup)
|
25
|
+
html << '</body></html>'
|
26
|
+
end
|
27
|
+
|
28
|
+
public def markup_to_html(markup)
|
29
|
+
code = Riven::Markup::Code.new
|
30
|
+
|
31
|
+
markup = code.extract(markup)
|
32
|
+
|
33
|
+
opts = {
|
34
|
+
no_intra_emphasis: true,
|
35
|
+
tables: true,
|
36
|
+
underline: true,
|
37
|
+
highlight: true,
|
38
|
+
filter_html: true,
|
39
|
+
with_toc_data: true,
|
40
|
+
lax_spacing: true,
|
41
|
+
xhtml: true,
|
42
|
+
fenced_code_blocks: true
|
43
|
+
}
|
44
|
+
|
45
|
+
redcarpet_markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, opts)
|
46
|
+
html = redcarpet_markdown.render(markup)
|
47
|
+
|
48
|
+
html = code.process(html)
|
49
|
+
|
50
|
+
return html
|
51
|
+
end
|
52
|
+
|
53
|
+
public def close!
|
54
|
+
@html_file.delete!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'riven/markup/code_block'
|
3
|
+
|
4
|
+
module Riven
|
5
|
+
module Markup
|
6
|
+
|
7
|
+
# Class that knows how to extract code blocks and render them with syntax highlightning
|
8
|
+
class Code
|
9
|
+
|
10
|
+
public def initialize
|
11
|
+
@code_blocks = []
|
12
|
+
end
|
13
|
+
|
14
|
+
# Extract all code blocks into the codemap and replace with placeholders.
|
15
|
+
#
|
16
|
+
# @return [String] Returns the placeholder'd String data.
|
17
|
+
|
18
|
+
public def extract(data)
|
19
|
+
data.gsub!(/^``` ?([^\r\n]+)?\r?\n(.+?)\r?\n```\r?$/m) do
|
20
|
+
id = Digest::SHA1.hexdigest($2)
|
21
|
+
@code_blocks << CodeBlock.new(id, $1, $2)
|
22
|
+
id
|
23
|
+
end
|
24
|
+
|
25
|
+
return data
|
26
|
+
end
|
27
|
+
|
28
|
+
# Process all code from the codemap and replace the placeholders with the
|
29
|
+
# final HTML.
|
30
|
+
#
|
31
|
+
# @return [String] Returns the marked up String data.
|
32
|
+
|
33
|
+
public def process(data)
|
34
|
+
return data if data.nil? || data.size.zero? || @code_blocks.size.zero?
|
35
|
+
|
36
|
+
@code_blocks.each do |block|
|
37
|
+
data.gsub!(block.id, block.highlighted)
|
38
|
+
end
|
39
|
+
|
40
|
+
data
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'coderay'
|
2
|
+
|
3
|
+
module Riven
|
4
|
+
module Markup
|
5
|
+
|
6
|
+
# Class that contains data for a code block
|
7
|
+
|
8
|
+
class CodeBlock
|
9
|
+
attr_reader :id, :language, :code
|
10
|
+
|
11
|
+
public def initialize(id, language, code)
|
12
|
+
@id, @language, @code = id, language, code
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the code with syntax highlightning
|
16
|
+
# @return [String]
|
17
|
+
|
18
|
+
public def highlighted
|
19
|
+
if @language
|
20
|
+
CodeRay.scan(@code, @language).div(tab_width: 4)
|
21
|
+
else
|
22
|
+
CodeRay.scan(@code, :text).div
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Riven
|
2
|
+
#
|
3
|
+
# Represents a MD File
|
4
|
+
#
|
5
|
+
|
6
|
+
class MarkupFile
|
7
|
+
attr_accessor :path
|
8
|
+
|
9
|
+
|
10
|
+
#
|
11
|
+
# Constructor
|
12
|
+
# Also checks if the file exists. If not, an exception will be thrown.
|
13
|
+
#
|
14
|
+
|
15
|
+
public def initialize(path)
|
16
|
+
@path = File.expand_path(path)
|
17
|
+
|
18
|
+
unless File.exists?(@path)
|
19
|
+
raise "File '#{path}' doesn't exist"
|
20
|
+
end
|
21
|
+
|
22
|
+
if File.directory?(@path)
|
23
|
+
raise "Mixing files and directories is not allowed, sorry"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
class << self
|
29
|
+
public def read_all(markup_files)
|
30
|
+
markup = ''
|
31
|
+
|
32
|
+
markup_files.each do |file|
|
33
|
+
markup << "\n\n" + File.read(file.path)
|
34
|
+
end
|
35
|
+
|
36
|
+
return markup
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'riven'
|
3
|
+
require 'riven/markup_file'
|
4
|
+
|
5
|
+
module Riven
|
6
|
+
#
|
7
|
+
# Utility class to parse the options and files passed to the riven command
|
8
|
+
#
|
9
|
+
|
10
|
+
class OptParser
|
11
|
+
class << self
|
12
|
+
#
|
13
|
+
# Returns an array of Riven::MarkupFile for each given markdown file
|
14
|
+
#
|
15
|
+
|
16
|
+
public def files
|
17
|
+
file_names = ARGV
|
18
|
+
|
19
|
+
if file_names.size === 1 && File.directory?(file_names[0])
|
20
|
+
file_names = Dir["#{file_names[0]}/*.md"].sort
|
21
|
+
end
|
22
|
+
|
23
|
+
file_names.map { |file| Riven::MarkupFile.new(file) }
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
#
|
28
|
+
# Parses the options and returns a map with the options and their values.
|
29
|
+
#
|
30
|
+
|
31
|
+
public def options
|
32
|
+
options = {
|
33
|
+
output_file: '',
|
34
|
+
cover_file: '',
|
35
|
+
css_file: '',
|
36
|
+
toc: false,
|
37
|
+
dump_html: false
|
38
|
+
}
|
39
|
+
|
40
|
+
opt_parser = OptionParser.new do |opts|
|
41
|
+
opts.banner = 'Usage: riven [OPTIONS] Markdown Files'
|
42
|
+
opts.separator ''
|
43
|
+
opts.separator 'Options'
|
44
|
+
|
45
|
+
opts.on("-o FILE", "--output=FILE", "File name of the output PDF file") do |output_file|
|
46
|
+
options[:output_file] = output_file
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on("-s FILE", "--css=FILE", "Path to the custom CSS file") do |css_file|
|
50
|
+
options[:css_file] = css_file
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on("-c FILE", "--cover=FILE", "Path to the cover MD file") do |cover_file|
|
54
|
+
options[:cover_file] = cover_file
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.on("-t", "--toc", "Enabled the table of contents auto generation") do
|
58
|
+
options[:toc] = true
|
59
|
+
end
|
60
|
+
|
61
|
+
opts.on("-d", "--dump-html", "Dumps the HTML file to STDOUT") do
|
62
|
+
options[:dump_html] = true
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on('-V', '--version', 'Displays the version') do
|
66
|
+
puts Riven::VERSION.to_s
|
67
|
+
exit
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
opt_parser.parse!
|
72
|
+
|
73
|
+
return options
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Riven
|
2
|
+
class Wkhtmltopdf
|
3
|
+
class << self
|
4
|
+
public def check_installation
|
5
|
+
`wkhtmltopdf -V > /dev/null 2>&1`
|
6
|
+
|
7
|
+
unless $?.exitstatus == 0
|
8
|
+
puts "Seems like wkhtmltopdf is not correctly installed or set up"
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
public def generate_pdf(html_file, output_file)
|
14
|
+
params = [
|
15
|
+
'--disable-smart-shrinking',
|
16
|
+
'--page-size A4',
|
17
|
+
'--margin-bottom 10mm',
|
18
|
+
'--margin-top 10mm',
|
19
|
+
'--margin-left 8mm',
|
20
|
+
'--margin-right 8mm'
|
21
|
+
]
|
22
|
+
|
23
|
+
output = `wkhtmltopdf #{params.join(' ')} #{html_file.file_name} #{output_file} 2>&1`
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/riven.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'riven/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'riven'
|
7
|
+
|
8
|
+
spec.version = Riven::VERSION
|
9
|
+
spec.date = Time.now.strftime('%Y-%m-%d')
|
10
|
+
|
11
|
+
spec.summary = 'Converts Markdown to PDF'
|
12
|
+
spec.description = 'Converts GitHub Flavored Markdown to awesome looking PDFs! Featuring: ' +
|
13
|
+
'Syntax Highlighting, Custom CSS, Covers, Table of Contents and more'
|
14
|
+
|
15
|
+
spec.authors = ['Benjamin Kammerl']
|
16
|
+
spec.email = 'benny@itws.de'
|
17
|
+
spec.homepage = 'https://github.com/phortx/riven'
|
18
|
+
spec.license = 'MIT'
|
19
|
+
|
20
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.8'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10.4'
|
28
|
+
|
29
|
+
|
30
|
+
spec.add_dependency 'redcarpet', '~> 3.2'
|
31
|
+
spec.add_dependency 'coderay', '~> 1.1'
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: riven
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Benjamin Kammerl
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.4'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: redcarpet
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coderay
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
description: 'Converts GitHub Flavored Markdown to awesome looking PDFs! Featuring:
|
70
|
+
Syntax Highlighting, Custom CSS, Covers, Table of Contents and more'
|
71
|
+
email: benny@itws.de
|
72
|
+
executables:
|
73
|
+
- riven
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- Gemfile
|
79
|
+
- Gemfile.lock
|
80
|
+
- LICENSE
|
81
|
+
- README.md
|
82
|
+
- bin/riven
|
83
|
+
- css/style.css
|
84
|
+
- lib/riven.rb
|
85
|
+
- lib/riven/html_file.rb
|
86
|
+
- lib/riven/html_generator.rb
|
87
|
+
- lib/riven/markup/code.rb
|
88
|
+
- lib/riven/markup/code_block.rb
|
89
|
+
- lib/riven/markup_file.rb
|
90
|
+
- lib/riven/opt_parser.rb
|
91
|
+
- lib/riven/version.rb
|
92
|
+
- lib/riven/wkhtmltopdf.rb
|
93
|
+
- riven.gemspec
|
94
|
+
homepage: https://github.com/phortx/riven
|
95
|
+
licenses:
|
96
|
+
- MIT
|
97
|
+
metadata: {}
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 2.4.5
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Converts Markdown to PDF
|
118
|
+
test_files: []
|