markover 0.6.0
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/LICENSE +20 -0
- data/README.md +102 -0
- data/bin/markover +31 -0
- data/config/style.css +174 -0
- data/ext/github_markup.rb +11 -0
- data/lib/markover.rb +31 -0
- data/lib/markover/config.rb +28 -0
- data/lib/markover/converter.rb +120 -0
- data/lib/markover/markup.rb +28 -0
- data/lib/markover/markup/code.rb +40 -0
- data/lib/markover/markup/code_block.rb +30 -0
- data/lib/markover/markup/renderer.rb +67 -0
- data/lib/markover/markup/yaml_frontmatter_remover.rb +17 -0
- data/lib/markover/markupfile.rb +67 -0
- data/lib/markover/optionparser.rb +93 -0
- data/lib/markover/path.rb +29 -0
- data/lib/markover/version.rb +6 -0
- data/lib/markover/wkhtmltopdf.rb +39 -0
- data/spec/fixtures/autolink_url.md +3 -0
- data/spec/fixtures/code_block.textile +8 -0
- data/spec/fixtures/code_block_with_utf8.textile +7 -0
- data/spec/fixtures/code_with_utf8.textile +6 -0
- data/spec/fixtures/integration/markdown.md +60 -0
- data/spec/fixtures/integration/style.css +3 -0
- data/spec/fixtures/integration/textile.textile +47 -0
- data/spec/fixtures/long_code_block.md +5 -0
- data/spec/fixtures/recursion/level1.textile +1 -0
- data/spec/fixtures/recursion/level2/level2.markdown +1 -0
- data/spec/fixtures/table.md +7 -0
- data/spec/fixtures/yaml_front_matter.textile +7 -0
- data/spec/integration_spec.rb +41 -0
- data/spec/markover/converter_spec.rb +124 -0
- data/spec/markover/markup/code_block_spec.rb +21 -0
- data/spec/markover/markup/code_spec.rb +45 -0
- data/spec/markover/markup/renderer_spec.rb +18 -0
- data/spec/markover/markup/yaml_frontmatter_remover_spec.rb +21 -0
- data/spec/markover/markup_file_spec.rb +45 -0
- data/spec/markover/path_spec.rb +32 -0
- data/spec/markover/wkhtmltopdf_spec.rb +35 -0
- data/spec/spec_helper.rb +11 -0
- metadata +228 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# This file is based on the markup class in gollum - https://github.com/github/gollum
|
4
|
+
# (The MIT License)
|
5
|
+
#
|
6
|
+
# Copyright (c) Tom Preston-Werner, Rick Olson
|
7
|
+
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
10
|
+
# in the Software without restriction, including without limitation the rights
|
11
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
# copies of the Software, and to permit persons to whom the Software is
|
13
|
+
# furnished to do so, subject to the following conditions:
|
14
|
+
|
15
|
+
require 'digest/sha1'
|
16
|
+
|
17
|
+
require 'github/markup'
|
18
|
+
require 'nokogiri'
|
19
|
+
|
20
|
+
require 'markover/markup/yaml_frontmatter_remover'
|
21
|
+
require 'markover/markup/code'
|
22
|
+
require 'markover/markup/code_block'
|
23
|
+
require 'markover/markup/renderer'
|
24
|
+
|
25
|
+
module Markover
|
26
|
+
module Markup
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Markover
|
4
|
+
|
5
|
+
module Markup
|
6
|
+
|
7
|
+
# Class that knows how to extract code blocks and render them with syntax highlightning
|
8
|
+
class Code
|
9
|
+
|
10
|
+
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
|
+
def extract(data)
|
18
|
+
data.gsub!(/^``` ?([^\r\n]+)?\r?\n(.+?)\r?\n```\r?$/m) do
|
19
|
+
id = Digest::SHA1.hexdigest($2)
|
20
|
+
@code_blocks << CodeBlock.new(id, $1, $2)
|
21
|
+
id
|
22
|
+
end
|
23
|
+
data
|
24
|
+
end
|
25
|
+
|
26
|
+
# Process all code from the codemap and replace the placeholders with the
|
27
|
+
# final HTML.
|
28
|
+
#
|
29
|
+
# @return [String] Returns the marked up String data.
|
30
|
+
def process(data)
|
31
|
+
return data if data.nil? || data.size.zero? || @code_blocks.size.zero?
|
32
|
+
@code_blocks.each do |block|
|
33
|
+
data.gsub!(block.id, block.highlighted)
|
34
|
+
end
|
35
|
+
data
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'coderay'
|
4
|
+
|
5
|
+
module Markover
|
6
|
+
|
7
|
+
module Markup
|
8
|
+
|
9
|
+
# Class that contains data for a code block
|
10
|
+
class CodeBlock
|
11
|
+
attr_reader :id, :language, :code
|
12
|
+
|
13
|
+
def initialize(id, language, code)
|
14
|
+
@id, @language, @code = id, language, code
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the code with syntax highlightning
|
18
|
+
# @return [String]
|
19
|
+
def highlighted
|
20
|
+
if @language
|
21
|
+
CodeRay.scan(@code, @language).html(:line_numbers => :table)
|
22
|
+
else
|
23
|
+
CodeRay.scan(@code, :text).div
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Markover
|
4
|
+
|
5
|
+
module Markup
|
6
|
+
|
7
|
+
# Contains functionality to render html from a markup file
|
8
|
+
class Renderer
|
9
|
+
# Initialize a new Markup object.
|
10
|
+
#
|
11
|
+
# @param [Markover::File] file The Markover::File to process
|
12
|
+
# @param [Boolean] do_remove_yaml_front_matter Should we remove the front matter?
|
13
|
+
# @return [Markover::Markup]
|
14
|
+
def initialize(file, do_remove_yaml_front_matter = false)
|
15
|
+
@file = file
|
16
|
+
@do_remove_yaml_front_matter = do_remove_yaml_front_matter
|
17
|
+
|
18
|
+
@data = file.data
|
19
|
+
@code = Code.new
|
20
|
+
@yaml_frontmatter_remover = YamlFrontmatterRemover.new
|
21
|
+
end
|
22
|
+
|
23
|
+
# Render the content with Gollum wiki syntax on top of the file's own
|
24
|
+
# markup language.
|
25
|
+
#
|
26
|
+
# @return [String] The formatted data
|
27
|
+
def render
|
28
|
+
prepare_data
|
29
|
+
render_data
|
30
|
+
post_process_data
|
31
|
+
|
32
|
+
return @data
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Prepare data for rendering
|
38
|
+
def prepare_data
|
39
|
+
@data = @yaml_frontmatter_remover.process(@data) if @do_remove_yaml_front_matter
|
40
|
+
@data = @code.extract(@data)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Do the markup to html rendering
|
44
|
+
def render_data
|
45
|
+
begin
|
46
|
+
@data = @data.force_encoding('utf-8') if @data.respond_to? :force_encoding
|
47
|
+
@data = GitHub::Markup.render(@file.filename, @data)
|
48
|
+
if @data.nil?
|
49
|
+
raise "There was an error converting #{@file.name} to HTML."
|
50
|
+
end
|
51
|
+
rescue Object => e
|
52
|
+
@data = %{<p class="markover-error">#{e.message}</p>}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Do post processing on data
|
57
|
+
def post_process_data
|
58
|
+
@data = @code.process(@data)
|
59
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(@data, 'UTF-8')
|
60
|
+
@data = doc.to_xhtml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XHTML, :encoding => 'UTF-8')
|
61
|
+
@data.gsub!(/<p><\/p>/, '')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Markover
|
4
|
+
|
5
|
+
module Markup
|
6
|
+
|
7
|
+
# Class that knows how to remove yaml front matter
|
8
|
+
class YamlFrontmatterRemover
|
9
|
+
|
10
|
+
# Removes YAML Front Matter
|
11
|
+
# Useful if you want to PDF your Jekyll site.
|
12
|
+
def process(data)
|
13
|
+
data.gsub /^(---\s*\n.*?\n?)^(---\s*$\n?)/m, ''
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Markover
|
4
|
+
|
5
|
+
# Class used to load files and determine if they are valid
|
6
|
+
class MarkupFile
|
7
|
+
attr_reader :filename, :name, :data, :format
|
8
|
+
|
9
|
+
# Accepted formats
|
10
|
+
FORMATS = [:markdown, :textile, :rdoc, :org, :creole, :rest, :asciidoc, :pod, :roff, :mediawiki]
|
11
|
+
|
12
|
+
# Initializes the file object. Only reads contents if it's a valid file
|
13
|
+
def initialize(filename)
|
14
|
+
@filename = filename
|
15
|
+
extension = ::File.extname(@filename)
|
16
|
+
@format = load_format(extension)
|
17
|
+
@name = ::File.basename(@filename, extension)
|
18
|
+
@data = ::File.open(@filename, 'rb') { |f| f.read } if valid? && ::File.exists?(@filename)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Is the file valid
|
22
|
+
# @return [Boolean]
|
23
|
+
def valid?
|
24
|
+
valid_format? @format
|
25
|
+
end
|
26
|
+
|
27
|
+
# Converts the format to a symbol if it's a valid format nil otherwise
|
28
|
+
# @param [String] format
|
29
|
+
# @return [Symbol|nil]
|
30
|
+
def load_format(format)
|
31
|
+
case format.to_s
|
32
|
+
when /(md|mkdn?|mdown|markdown)$/i
|
33
|
+
:markdown
|
34
|
+
when /(textile)$/i
|
35
|
+
:textile
|
36
|
+
when /(rdoc)$/i
|
37
|
+
:rdoc
|
38
|
+
when /(org)$/i
|
39
|
+
:org
|
40
|
+
when /(creole)$/i
|
41
|
+
:creole
|
42
|
+
when /(re?st(\.txt)?)$/i
|
43
|
+
:rest
|
44
|
+
when /(asciidoc)$/i
|
45
|
+
:asciidoc
|
46
|
+
when /(pod)$/i
|
47
|
+
:pod
|
48
|
+
when /(\d)$/i
|
49
|
+
:roff
|
50
|
+
when /(media)?wiki$/i
|
51
|
+
:mediawiki
|
52
|
+
else
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Checks if the format is a valid one
|
58
|
+
# @param [String] format
|
59
|
+
# @return [Boolean]
|
60
|
+
def valid_format?(format)
|
61
|
+
return false if format.nil?
|
62
|
+
|
63
|
+
FORMATS.include? format.to_sym
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'markover/version'
|
3
|
+
|
4
|
+
module Markover
|
5
|
+
class Parser
|
6
|
+
def self.parse!(args)
|
7
|
+
new.parse!(args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse!(args)
|
11
|
+
return {} if args.empty?
|
12
|
+
options = {
|
13
|
+
outputdir: nil,
|
14
|
+
stylesheet: nil,
|
15
|
+
recursive: false,
|
16
|
+
merge: false,
|
17
|
+
filename: nil,
|
18
|
+
debug: false,
|
19
|
+
wkhtmltopdfparameters: '',
|
20
|
+
removefrontmatter: false,
|
21
|
+
table_of_contents: false
|
22
|
+
}
|
23
|
+
parser(options).parse!(args)
|
24
|
+
options
|
25
|
+
end
|
26
|
+
|
27
|
+
def parser(options)
|
28
|
+
OptionParser.new do |parser|
|
29
|
+
parser.banner = 'Usage: markover [options] [files or directories]'
|
30
|
+
parser.separator ''
|
31
|
+
parser.separator 'Options'
|
32
|
+
|
33
|
+
parser.on('-o', '--output-dir', '=OUTDIR',
|
34
|
+
'Save parsed files to OUTDIR. Defaults to working directory.') do |value|
|
35
|
+
|
36
|
+
options[:outputdir] = value
|
37
|
+
end
|
38
|
+
|
39
|
+
parser.on('-s', '--stylesheet', '=SHEET',
|
40
|
+
'Override standard stylesheet with SHEET') do |value|
|
41
|
+
|
42
|
+
options[:stylesheet] = value
|
43
|
+
end
|
44
|
+
|
45
|
+
parser.on('-r', '--recursive',
|
46
|
+
'Recurse current or target directory and convert all valid markup files') do
|
47
|
+
|
48
|
+
options[:recursive] = true
|
49
|
+
end
|
50
|
+
|
51
|
+
parser.on('-m', '--merge', '=FILENAME',
|
52
|
+
'Merge any and all passed markup files into single file of the specified name') do |value|
|
53
|
+
|
54
|
+
options[:merge] = true
|
55
|
+
options[:filename] = value
|
56
|
+
end
|
57
|
+
|
58
|
+
parser.on('-d', '--debug', 'Dumps HTML output to stdout') do |value|
|
59
|
+
options[:debug] = true
|
60
|
+
end
|
61
|
+
|
62
|
+
parser.on('-w', '--wkhtmltopdf-params', '=PARAMS',
|
63
|
+
'Parameters to be passed on to wkhtmltopdf. Use "" if more than one parameter. See wkhtmltopdf usage for possible parameters.') do |value|
|
64
|
+
options[:wkhtmltopdfparameters] = value
|
65
|
+
end
|
66
|
+
|
67
|
+
parser.on('-o', '--remove-front-matter', 'Remove yaml frontmatter from your files.') do
|
68
|
+
options[:removefrontmatter] = true
|
69
|
+
end
|
70
|
+
|
71
|
+
parser.on('-n', '--output-filename', '=FILENAME',
|
72
|
+
'Sets the name of the output file. Only used with single file and in merge mode.') do |value|
|
73
|
+
|
74
|
+
options[:filename] = value
|
75
|
+
end
|
76
|
+
|
77
|
+
parser.on('-t', '--toc', 'Generate a table of contents') do
|
78
|
+
options[:table_of_contents] = true
|
79
|
+
end
|
80
|
+
|
81
|
+
parser.on('-v', '--version', 'Show version information and quit') do
|
82
|
+
puts Markover::Version
|
83
|
+
exit
|
84
|
+
end
|
85
|
+
|
86
|
+
parser.on('-?', '-h', '--help', 'Show this message') do
|
87
|
+
puts parser
|
88
|
+
exit
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Markover
|
4
|
+
|
5
|
+
# Class used to interact with directory structure
|
6
|
+
class Path
|
7
|
+
|
8
|
+
# Return an array of paths to valid markup file matching the passed pattern
|
9
|
+
# @param [String] target
|
10
|
+
# @param [Bool] recursive
|
11
|
+
# @return [Array] an array of valid files
|
12
|
+
def self.list_valid(target, recursive = false)
|
13
|
+
if recursive
|
14
|
+
target ||= Dir.pwd
|
15
|
+
if File.directory?(target)
|
16
|
+
target = File.join(target, '**', '*')
|
17
|
+
end
|
18
|
+
else
|
19
|
+
target ||= Dir.pwd
|
20
|
+
if File.directory?(target)
|
21
|
+
target = File.join(target, '*')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Use select to support ruby 1.8
|
26
|
+
Dir.glob(target).select { |file| MarkupFile.new(file).valid? }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Markover
|
2
|
+
|
3
|
+
# The class that communicates with wkhtmltopdf
|
4
|
+
class Wkhtmltopdf
|
5
|
+
|
6
|
+
# Set up options for wkhtmltopdf
|
7
|
+
# @param [String] parameters
|
8
|
+
def initialize(parameters = nil)
|
9
|
+
@parameters = parameters
|
10
|
+
end
|
11
|
+
|
12
|
+
# Convert the html to pdf and write it to file
|
13
|
+
# @param [String] html the html input
|
14
|
+
# @param [String] filename the name of the output file
|
15
|
+
def output_pdf(html, filename)
|
16
|
+
args = command(filename)
|
17
|
+
invoke = args.join(' ')
|
18
|
+
|
19
|
+
IO.popen(invoke, "wb+") do |pdf|
|
20
|
+
pdf.puts(html)
|
21
|
+
pdf.close_write
|
22
|
+
pdf.gets(nil)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Assemble the command to run
|
27
|
+
# @param [String] filename the outputed pdf's filename
|
28
|
+
# @return [Array] a list of strings that make out the call to wkhtmltopdf
|
29
|
+
def command(filename)
|
30
|
+
[bin, @parameters, '--quiet', '-', "\"#{filename}\""].compact
|
31
|
+
end
|
32
|
+
|
33
|
+
# Find the wkhtmltopdf binary
|
34
|
+
# @return [String] the path to the binary
|
35
|
+
def bin
|
36
|
+
@bin ||= "\"#{(`which wkhtmltopdf`).chomp}\""
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|