karmi-markout 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Karel Minarik
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,23 @@
1
+ = Markout
2
+
3
+ Markout makes it easy to export sexy formatted documents such as specifications from your plain text, Markdown-formatted files.
4
+
5
+ Designed for easy extending, theming and adding output formats.
6
+
7
+ More information soon.
8
+
9
+
10
+ == Usage
11
+
12
+ On the command line:
13
+
14
+ $ sudo gem install karmi-markout --source=http://gems.github.com
15
+
16
+
17
+ == Todo
18
+
19
+ [!] Visualize document history based on Git information
20
+
21
+ == Copyright
22
+
23
+ Copyright (c) 2009 Karel Minarik. Released under MIT license.
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 0
3
+ :patch: 0
4
+ :major: 0
data/bin/markout ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+
6
+ require File.join( File.join(File.dirname(__FILE__), '..', 'lib', 'markout') )
7
+
8
+ opts = {}
9
+
10
+ def die(msg)
11
+ STDERR.puts("\033[41;1mError!\033[0m\n" + msg)
12
+ exit 1
13
+ end
14
+
15
+ OptionParser.new do |o|
16
+ o.banner = "USAGE: #{$0} [options] [path/to/file]"
17
+
18
+ o.on("-f",
19
+ "--format [FORMAT]",
20
+ "Output format (html, pdf)") do |f|
21
+ opts[:format] = f
22
+ end
23
+
24
+ o.on("-t",
25
+ "--template [TEMPLATE]",
26
+ "Output template") do |t|
27
+ opts[:template] = t
28
+ end
29
+
30
+ o.on("-o",
31
+ "--output [path/to/directory]",
32
+ "Output directory (default: same as source file)") do |d|
33
+ die('Output directory does not exist!') unless File.exist?(d)
34
+ opts[:output] = d
35
+ end
36
+
37
+ o.on("-h", "--help", "Show help") do |h|
38
+ puts o
39
+ exit
40
+ end
41
+ end.parse!
42
+
43
+ die("You need to provide path to a Markdown formatted text file!
44
+ USAGE: #{$0} [options] [path/to/file]
45
+ Type #{$0} -h for help") if ARGV.empty?
46
+
47
+ begin
48
+ time = Time.now
49
+ o = Markout::Output.new( ARGV.first, opts )
50
+ puts "\033[0mConverting \033[1m#{ARGV[0]}\033[30;0m to \033[1m#{o.output_path}\033[0m"
51
+ o.export(true)
52
+ puts "\033[42mMarkout finished\033[0m in #{sprintf('%.2f', Time.now-time)} seconds\n"
53
+ rescue Exception => e
54
+ puts "\033[41;1mMarkout Failed!\033[0m\n"
55
+ raise e
56
+ end
data/lib/markout.rb ADDED
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH << File.join( File.dirname(__FILE__), 'markout' )
2
+
3
+ %w{output document formatter}.each { |lib| require lib }
4
+
5
+ module Markout
6
+
7
+ class FileNotFound < Exception; end
8
+
9
+ end
@@ -0,0 +1,20 @@
1
+ require 'pathname'
2
+ require 'mime/types'
3
+
4
+ module Markout
5
+
6
+ class Document
7
+
8
+ attr_reader :path, :base_path, :content
9
+
10
+ def initialize(path)
11
+ @path = File.expand_path(path)
12
+ @base_path = Pathname.new( File.dirname(@path) )
13
+ raise FileNotFound, "File #{@path} not found" unless File.exist?(@path)
14
+ # TODO: Raise error for non-text file
15
+ @content = File.read(path)
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,25 @@
1
+ require 'pathname'
2
+
3
+ module Markout
4
+
5
+ class Formatter
6
+
7
+ def initialize(document, options={})
8
+ @document = document
9
+ @options = options
10
+ @format = self.class.to_s.gsub(/^.*::/, '').downcase
11
+ end
12
+
13
+ def export
14
+ raise NoMethodError, "Return String in `export()` method of your formatter (#{@format})"
15
+ end
16
+
17
+ def filename
18
+ basename = File.basename(@document.path).split('.')
19
+ ext = basename.pop
20
+ "#{basename.join('.')}.#{@format}"
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,59 @@
1
+ require 'rdiscount'
2
+ require 'erb'
3
+ require 'base64'
4
+ require 'mime/types'
5
+
6
+ module Markout
7
+
8
+ class Html < Formatter
9
+
10
+ def export
11
+ suck_in_images!
12
+ ERB.new( File.read(template_path.join('content.rhtml')) ).result(binding)
13
+ end
14
+
15
+ private
16
+
17
+ def template_name
18
+ @options[:template] || 'default'
19
+ end
20
+
21
+ def template_path
22
+ Pathname.new( File.join( File.dirname(__FILE__), 'templates', template_name ) )
23
+ end
24
+
25
+ def content
26
+ @content ||= RDiscount.new( @document.content ).to_html
27
+ end
28
+
29
+ def screen_style
30
+ File.read template_path.join('screen.css')
31
+ end
32
+
33
+ def print_style
34
+ File.read template_path.join('print.css')
35
+ end
36
+
37
+ def title
38
+ h1 = content.match(/<h1\s*.*>(.+)<\/h1>/)[1] rescue nil
39
+ h1 || ''
40
+ end
41
+
42
+ # TODO : Make 'alt' attribute optional
43
+ # TODO : Cleanup?
44
+ def suck_in_images!
45
+ content.to_s.gsub!(/<img src="([^"]+)".*alt="([^"]+)".*\s*\/?>/) do |match|
46
+ begin
47
+ file = File.read( @document.base_path.join($1) )
48
+ mime = MIME::Types.of(File.basename( @document.base_path.join($1) ))
49
+ "<img src=\"data:#{mime};base64,#{Base64.encode64(file)}\" alt=\"#{$2}\" />"
50
+ rescue
51
+ # TODO : Better error handling
52
+ puts "Error: Cannot load image #{$1}"
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,27 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+
8
+ <title><%= title %></title>
9
+
10
+ <style type="text/css" media="screen">
11
+ <%= screen_style %>
12
+ </style>
13
+
14
+ <style type="text/css" media="print">
15
+ <%= print_style %>
16
+ </style>
17
+
18
+ </head>
19
+
20
+ <body>
21
+
22
+ <div id="content">
23
+ <%= content %>
24
+ </div>
25
+
26
+ </body>
27
+ </html>
@@ -0,0 +1,34 @@
1
+ body
2
+ { color: #000;
3
+ background: #fff;
4
+ font-size: 85%;
5
+ font-family: Helvetica, sans-serif;
6
+ margin: 0.5cm; }
7
+
8
+ a
9
+ { color: #000;
10
+ text-decoration: underline; }
11
+
12
+ a img
13
+ { border: none; }
14
+
15
+ h2 {
16
+ font-size: 1.5em;
17
+ letter-spacing: -0.05em;
18
+ padding: 1.15em 0 0 0;
19
+ margin: 1.25em 0 0.25em 0;
20
+ border-top: 1mm solid #999;
21
+ }
22
+
23
+ h3 {
24
+ font-size: 1.1em;
25
+ font-weight:bold;
26
+ margin: 1.8em 0 0.25em 0;
27
+ letter-spacing: -0.05em;
28
+ }
29
+
30
+ pre {
31
+ border: 1pt solid #ccc;
32
+ padding: 0.5em;
33
+ white-space: pre-wrap; white-space: -moz-pre-wrap !important;
34
+ }
@@ -0,0 +1,102 @@
1
+ /*
2
+ = COLORS =
3
+
4
+ Steel blue #d8dde3
5
+ Black blue #172533
6
+ Dark grey #525c66
7
+ Ash grey #dfe2e5
8
+ Live blue #1177DD
9
+ Pale green face #b9cbdd
10
+
11
+ */
12
+
13
+ body {
14
+ color: #222;
15
+ background: #fafafa;
16
+ font-family: Helvetica, sans-serif;
17
+ font-size: 85%;
18
+ line-height: 155%;
19
+ margin: 0;
20
+ padding: 0 5em;
21
+ }
22
+
23
+ .cleaner
24
+ { clear: both; height: 0; line-height: 0; width: 0; border: 0; font-size: 1px; }
25
+
26
+ #content {
27
+ color: #172533;
28
+ font-size: 1.1em;
29
+ max-width: 55em;
30
+ padding-bottom: 4em;
31
+ margin: 7px auto;
32
+ margin-bottom: 4em;
33
+ border-top: 4px solid #172533;
34
+ border-bottom: 4px solid #b9cbdd;
35
+ }
36
+
37
+ h1, h2, h3, h4, h5, h6 {
38
+ color: #222;
39
+ }
40
+ h1, h2 {
41
+ color: #172533;
42
+ font-weight: normal;
43
+ }
44
+ h1 a, h2 a { color: #172533; }
45
+
46
+ h1 {
47
+ font-size: 2.25em;
48
+ letter-spacing: -1px;
49
+ margin-bottom: 0.5em;
50
+ }
51
+
52
+ h2 {
53
+ font-size: 1.5em;
54
+ letter-spacing: -1px;
55
+ padding: 1.15em 0 0 0;
56
+ margin: 1.25em 0 0.25em 0;
57
+ border-top: 4px solid #d8dde3;
58
+ }
59
+
60
+ h3 {
61
+ color: #172533;
62
+ font-size: 1.1em;
63
+ font-weight:bold;
64
+ margin: 1.8em 0 0.25em 0;
65
+ letter-spacing:-1px;
66
+ }
67
+
68
+ h3 a {
69
+ text-decoration:underline;
70
+ }
71
+
72
+ p {
73
+ margin: 0 0 0.8em 0;
74
+ }
75
+
76
+ a {
77
+ color: #172533;
78
+ text-decoration:underline;
79
+ }
80
+ a:hover {
81
+ color: #1177DD;
82
+ text-decoration:underline;
83
+ }
84
+ a img {
85
+ border:none;
86
+ }
87
+
88
+ code, pre, textarea, tt {
89
+ font-family: "Monaco", "lucida console", "bitstream vera sans mono", monospace;
90
+ font-size: 100%;
91
+ }
92
+ pre {
93
+ color: #172533;
94
+ background: #f5f9fc;
95
+ font-size: 100%;
96
+ line-height: 155%;
97
+ border: 4px solid #dfe2e5;
98
+ padding: 0.5em;
99
+ white-space: pre-wrap; white-space: -moz-pre-wrap !important;
100
+ }
101
+
102
+ hr { display: none; }
@@ -0,0 +1,27 @@
1
+ require 'tempfile'
2
+ require File.join(File.dirname(__FILE__), '..', 'html', 'html.rb')
3
+
4
+ # Depends on HTMLDOC utility (http://www.easysw.com/htmldoc/)
5
+ module Markout
6
+
7
+ class Pdf < Formatter
8
+
9
+ def export
10
+ `cat "#{tempfile.path}" | /opt/local/bin/htmldoc -t pdf \
11
+ --bodyfont "Helvetica" --headfootfont "Helvetica" \
12
+ --no-compression --color --embedfonts \
13
+ --header "" --footer .1. --links --no-title \
14
+ --toctitle "" --tocheader "..." --tocfooter "..." \
15
+ -`
16
+ end
17
+
18
+ private
19
+
20
+ def tempfile
21
+ tempfile = Tempfile.new(File.basename(@document.path) + '.html')
22
+ tempfile << Markout::Html.new(@document).export
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,49 @@
1
+ module Markout
2
+
3
+ class Output
4
+
5
+ attr_reader :document, :format, :formatter
6
+
7
+ def initialize(path, options = {})
8
+ @path = path
9
+ @document = Document.new(@path)
10
+ @options = options
11
+ @format = @options[:format] || 'html'
12
+ @formatter = pick_formatter.new( @document, :template => @options[:template] || 'default' )
13
+ @output = ''
14
+ end
15
+
16
+ def export(to_file=false)
17
+ @output = @formatter.export
18
+ write_file if to_file
19
+ return @output
20
+ end
21
+
22
+ def output_path
23
+ if @options[:output]
24
+ File.join( File.expand_path( @options[:output] ), @formatter.filename )
25
+ else
26
+ @document.base_path.join(@formatter.filename)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def write_file
33
+ File.open(output_path, 'w') { |f| f.write @output }
34
+ end
35
+
36
+ def pick_formatter
37
+ unless Markout::const_defined?(@format.to_s.capitalize)
38
+ begin
39
+ require File.join( File.dirname(__FILE__), 'formatters', @format, @format )
40
+ rescue Exception => e
41
+ raise LoadError, "Formatter '#{@format}' not found! (#{e.message})"
42
+ end
43
+ end
44
+ Markout::const_get(@format.to_s.capitalize)
45
+ end
46
+
47
+ end
48
+
49
+ end