transmuter 0.0.0.1 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,5 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ *.html
6
+ *.pdf
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ script: "rake spec"
2
+ env: JRUBY_OPTS="--1.9"
3
+ rvm:
4
+ - 1.9.2
5
+ - 1.9.3
6
+ notifications:
7
+ recipients:
8
+ - wael.nasreddine@gmail.com
data/Gemfile CHANGED
@@ -2,3 +2,20 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in transmuter.gemspec
4
4
  gemspec
5
+
6
+ platforms :ruby do
7
+ # Require rbconfig to figure out the target OS
8
+ require 'rbconfig'
9
+
10
+ unless ENV['TRAVIS']
11
+ if RbConfig::CONFIG['target_os'] =~ /darwin/i
12
+ gem 'rb-fsevent', require: false
13
+ gem 'ruby-growl', require: false
14
+ gem 'growl', require: false
15
+ end
16
+ if RbConfig::CONFIG['target_os'] =~ /linux/i
17
+ gem 'rb-inotify', require: false
18
+ gem 'libnotify', require: false
19
+ end
20
+ end
21
+ end
data/Guardfile ADDED
@@ -0,0 +1,13 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'bundler' do
5
+ watch('Gemfile')
6
+ watch(/^.+\.gemspec/)
7
+ end
8
+
9
+ guard 'rspec', :version => 2 do
10
+ watch(%r{^spec/.+_spec\.rb$})
11
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
12
+ watch('spec/spec_helper.rb') { "spec" }
13
+ end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Transmuter
1
+ # Transmuter [![Build Status](http://travis-ci.org/TechnoGate/transmuter.png)](http://travis-ci.org/TechnoGate/transmuter)
2
2
 
3
3
  Transmuter is a command line tool to convert Markdown files into HTML or PDF
4
4
  files, it can also be used to convert HTML files to PDF, it uses in the
@@ -6,6 +6,8 @@ backgound [Redcarper](https://github.com/tanoku/redcarpet),
6
6
  [Albino](https://github.com/github/albino) and
7
7
  [PDFkit](https://github.com/jdpace/PDFKit).
8
8
 
9
+ <a href='http://www.pledgie.com/campaigns/16086'><img alt='Click here to lend your support to: Transmuter and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/16086.png?skin_name=chrome' border='0' /></a>
10
+
9
11
  # Installation
10
12
 
11
13
  To install Transmuter use the command
@@ -35,3 +37,35 @@ $ sudo easy_install pygments
35
37
  2. Try using the wkhtmltopdf-binary gem (mac + linux i386)
36
38
 
37
39
  gem install wkhtmltopdf-binary
40
+
41
+ # Usage
42
+
43
+ You should check the help
44
+
45
+ ```bash
46
+ $ transmute --help
47
+ ```
48
+
49
+ To Generate a PDF from a markdown file with the default CSS:
50
+
51
+ ```bash
52
+ $ transmute file.md
53
+ ```
54
+
55
+ To Generate an HTML from a markdown file with the default CSS:
56
+
57
+ ```bash
58
+ $ transmute file.md -t html
59
+ ```
60
+
61
+ To Generate an HTML from a markdown file with custom CSS:
62
+
63
+ ```bash
64
+ $ transmute file.md -t html -s custom.css
65
+ ```
66
+
67
+ Custom CSS files can be be multiple path separated by a space, for example:
68
+
69
+ ```bash
70
+ $ transmute file.md -t html -s custom1.css custom2.css
71
+ ```
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ # Require RSpec tasks
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ # The default task is tests
8
+ task :default => :spec
data/bin/transmute ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ $:.push File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+
6
+ require 'transmuter'
7
+ Transmuter::CLI::Runner.start
@@ -0,0 +1,99 @@
1
+ require 'thor'
2
+ require 'thor/group'
3
+
4
+ module Transmuter
5
+ module CLI
6
+ module Thor
7
+
8
+ def self.included(base)
9
+ base.send :include, InstanceMethods
10
+ end
11
+
12
+ module InstanceMethods
13
+ def self.included(base)
14
+ base.class_eval <<-END, __FILE__, __LINE__ + 1
15
+ desc "Transmute one file format into another."
16
+
17
+ class_option :input_format,
18
+ type: :string,
19
+ required: false,
20
+ aliases: "-f",
21
+ desc: "The input format."
22
+
23
+ class_option :output_format,
24
+ type: :string,
25
+ required: false,
26
+ aliases: "-t",
27
+ default: "pdf",
28
+ desc: "The output format."
29
+
30
+ class_option :stylesheets,
31
+ type: :array,
32
+ required: false,
33
+ aliases: "-s",
34
+ default: [DEFAULT_THEME],
35
+ desc: "The stylesheets."
36
+
37
+ argument :input,
38
+ type: :string,
39
+ required: true,
40
+ aliases: "-i",
41
+ desc: "The input file name."
42
+
43
+ argument :output,
44
+ type: :string,
45
+ required: false,
46
+ aliases: "-o",
47
+ desc: "The output file name."
48
+
49
+ def set_input_filename
50
+ @input_filename = input
51
+ end
52
+
53
+ def set_input_fileformat
54
+ @input_fileformat = options[:input_format] || input_format
55
+ end
56
+
57
+ def set_output_fileformat
58
+ @output_fileformat = options[:output_format]
59
+ end
60
+
61
+ def set_output_filename
62
+ if output.blank? && options[:output_format].blank?
63
+ raise ArgumentError, "Either output or output_format should be given,"
64
+ end
65
+
66
+ @output_filename = output || output_file
67
+ end
68
+
69
+ def set_stylesheets
70
+ @stylesheets = options[:stylesheets]
71
+ end
72
+
73
+ def transmute_input_to_output
74
+ transmute!
75
+ end
76
+
77
+ protected
78
+
79
+ def input_format
80
+ case @input.split('.').last
81
+ when /^(md|markdown)$/
82
+ "markdown"
83
+ when /^(html|htm)/
84
+ "html"
85
+ else
86
+ raise ArgumentError, "No format was given and format could not be parsed from the file name"
87
+ end
88
+ end
89
+
90
+ def output_file
91
+ output = @input_filename.dup
92
+ output.gsub(/^(.+)\\.[^.]*$/, "\\\\1.\#{@output_fileformat}")
93
+ end
94
+ END
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,67 @@
1
+ module Transmuter
2
+ module CLI
3
+ module Transmute
4
+ def self.included(base)
5
+ base.send :include, InstanceMethods
6
+ end
7
+
8
+ module InstanceMethods
9
+ def transmute!
10
+ set_klasses!
11
+ set_methods
12
+ verify_klasses!
13
+
14
+ source_klass_instance = @source_klass.new(read_input_file, parse_transmute_options)
15
+ output = source_klass_instance.send(@source_transform_method)
16
+
17
+ write_output_file(output)
18
+ end
19
+
20
+ def transmute
21
+ transmute!
22
+ rescue Exception => e
23
+ handle_error(e)
24
+ end
25
+
26
+ protected
27
+ def handle_error(exception)
28
+ # TODO: Handle error properly
29
+ end
30
+
31
+ def set_klasses!
32
+ @source_klass ||= "::Transmuter::Format::#{@input_fileformat.to_s.camelcase}".constantize
33
+ @destination_klass ||= "::Transmuter::Format::#{@output_fileformat.to_s.camelcase}".constantize
34
+ end
35
+
36
+ def set_methods
37
+ @source_transform_method ||= "to_#{@output_fileformat.to_s.downcase}".to_sym
38
+ @destination_process_method ||= :process
39
+ end
40
+
41
+ def verify_klasses!
42
+
43
+ raise NotImplementedError,
44
+ "#{@source_klass} does not respond to #{@source_transform_method}" unless
45
+ @source_klass.public_instance_methods.include?(@source_transform_method)
46
+
47
+ raise NotImplementedError,
48
+ "#{@destination_klass} does not respond to #{@destination_process_method}" unless
49
+ @destination_klass.public_instance_methods.include?(@destination_process_method)
50
+ end
51
+
52
+ def read_input_file
53
+ @input_file_contents ||= File.read(@input_filename)
54
+ end
55
+
56
+ def write_output_file(contents)
57
+ File.open(@output_filename, 'w') { |f| f.write(contents) }
58
+ end
59
+
60
+ def parse_transmute_options
61
+ { stylesheets: @stylesheets }
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,13 @@
1
+ require 'transmuter/cli/thor'
2
+ require 'transmuter/cli/transmute'
3
+
4
+ module Transmuter
5
+ module CLI
6
+ class Runner < ::Thor::Group
7
+ DEFAULT_THEME = File.expand_path(File.join(ROOT_PATH, 'stylesheets', 'default.css'))
8
+
9
+ include Transmute
10
+ include Thor
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ require 'active_support/core_ext'
2
+ require 'active_support/dependencies/autoload'
3
+
4
+ Dir["#{File.dirname(__FILE__)}/core_ext/**/*.rb"].each { |f| require f }
@@ -0,0 +1,81 @@
1
+ require 'albino'
2
+ require 'nokogiri'
3
+
4
+ module Transmuter
5
+ module Format
6
+ class Html
7
+
8
+ def initialize(html, options = {})
9
+ parse_options(options)
10
+ @html = html
11
+ end
12
+
13
+ def to_pdf
14
+ html = process
15
+ pdf = Pdf.new(html, get_options)
16
+ pdf.process
17
+ end
18
+
19
+ def process
20
+ include_inline_stylesheets(syntax_highlighter)
21
+ end
22
+
23
+ protected
24
+ def get_options
25
+ options = @options.dup
26
+ options.delete(:redcarpet_options)
27
+ options
28
+ end
29
+
30
+ def parse_options(options)
31
+ @options = options.dup
32
+ end
33
+
34
+ def read_stylesheet_files
35
+ case @options[:stylesheets]
36
+ when Array
37
+ @options[:stylesheets].collect do |f|
38
+ File.read(f)
39
+ end.join("\n")
40
+ when String
41
+ File.read @options[:stylesheets]
42
+ when NilClass
43
+ # Apparently no stylesheets has been requested
44
+ end
45
+ end
46
+
47
+ def include_inline_stylesheets(html)
48
+ if @options[:stylesheets].present?
49
+ stylesheet_contents = read_stylesheet_files
50
+
51
+ doc = Nokogiri::HTML(html)
52
+ head = doc.xpath('/html/head').first
53
+
54
+ style = Nokogiri::XML::Node.new "style", doc
55
+ style['type'] = "text/css"
56
+ style.content = stylesheet_contents
57
+
58
+ unless head.present?
59
+ head = Nokogiri::XML::Node.new "head", doc
60
+ body = doc.xpath('/html/body').first
61
+ body.add_previous_sibling head
62
+ end
63
+
64
+ style.parent = head
65
+
66
+ html = doc.to_s
67
+ end
68
+
69
+ html
70
+ end
71
+
72
+ def syntax_highlighter
73
+ doc = Nokogiri::HTML(@html)
74
+ doc.search("//pre[@lang]").each do |pre|
75
+ pre.replace Albino.colorize(pre.text.rstrip, pre[:lang].downcase.to_sym)
76
+ end
77
+ doc.to_s
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,45 @@
1
+ require 'redcarpet'
2
+
3
+ module Transmuter
4
+ module Format
5
+ class Markdown
6
+ REDCARPET_OPTIONS = [:autolink, :no_intraemphasis, :fenced_code, :gh_blockcode]
7
+
8
+ def initialize(markdown, options = {})
9
+ parse_options(options)
10
+ @markdown = markdown
11
+ end
12
+
13
+ def to_pdf
14
+ html = to_html
15
+ pdf = Pdf.new(html, get_options)
16
+ pdf.process
17
+ end
18
+
19
+ def to_html
20
+ html = Html.new(parse_markdown, get_options)
21
+ html.process
22
+ end
23
+
24
+ protected
25
+ def get_options
26
+ options = @options.dup
27
+ options.delete(:redcarpet_options)
28
+ options
29
+ end
30
+
31
+ def parse_options(options)
32
+ options = options.dup
33
+ @options = options.merge!(:redcarpet_options => REDCARPET_OPTIONS)
34
+ end
35
+
36
+ def create_markdown
37
+ Redcarpet.new(@markdown, *@options[:redcarpet_options])
38
+ end
39
+
40
+ def parse_markdown
41
+ create_markdown.to_html
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ require 'pdfkit'
2
+
3
+ module Transmuter
4
+ module Format
5
+ class Pdf
6
+
7
+ def initialize(html, options = {})
8
+ parse_options(options)
9
+ @html = html
10
+ end
11
+
12
+ def process
13
+ kit = PDFKit.new(@html, :page_size => @options[:page_size])
14
+
15
+ kit.to_pdf
16
+ end
17
+
18
+ protected
19
+ def parse_options(options)
20
+ options = options.dup
21
+ @options = options.merge!(:page_size => 'Letter')
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ module Transmuter
2
+ module Format
3
+ extend ::ActiveSupport::Autoload
4
+
5
+ autoload :Markdown
6
+ autoload :Html
7
+ autoload :Pdf
8
+ end
9
+ end
@@ -1,8 +1,7 @@
1
1
  module Transmuter
2
2
  MAJOR = 0
3
3
  MINOR = 0
4
- BUILD = 0
5
- REVISION = 1
4
+ PATCH = 1
6
5
 
7
- VERSION = [MAJOR, MINOR, BUILD, REVISION].join('.')
8
- end
6
+ VERSION = [MAJOR, MINOR, PATCH].join('.')
7
+ end
data/lib/transmuter.rb CHANGED
@@ -1,5 +1,6 @@
1
- require "transmuter/version"
1
+ ROOT_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..'))
2
2
 
3
- module Transmuter
4
- # Your code goes here...
5
- end
3
+ require "transmuter/version"
4
+ require "transmuter/core_ext"
5
+ require "transmuter/format"
6
+ require "transmuter/cli"
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ ROOT_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+ $:.push File.expand_path("#{ROOT_PATH}/lib")
4
+
5
+ require 'rubygems'
6
+ require 'rspec'
7
+
8
+ # Require the library
9
+ require 'transmuter'
10
+
11
+ include Transmuter
12
+
13
+ # Require support files
14
+ Dir[ROOT_PATH + "/spec/support/**/*.rb"].each {|f| require f}
15
+
16
+ RSpec.configure do |config|
17
+ # == Mock Framework
18
+ #
19
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
20
+ #
21
+ config.mock_with :mocha
22
+ # config.mock_with :flexmock
23
+ # config.mock_with :rr
24
+ # config.mock_with :rspec
25
+ end