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