ebookie 0.3.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8cbd3543662f1c4abeff2153fae912695093d4c0
4
+ data.tar.gz: be917c2395058c019bbf02fabfd3da7c6b8ddc19
5
+ SHA512:
6
+ metadata.gz: 3c5e6c82e1fc905b30cd9aff20300bc98e5d25dfa55b97e6da2ee8d5d4881a25762a3ac5edbddf8e66772568be856be94d0dbc257a3af95f1ad7ede451ee6730
7
+ data.tar.gz: 8c99693dd10cb8ee9c2eefb69f2f14b2ea5869cf2aec369d821a343ba7b81f28b572745983774e155bbaae22ff59f20c29a919f42d5e6d9000f7d4e1f4903e77
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 jordanandree
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,91 @@
1
+ # Ebookie
2
+
3
+ Generate PDF, ePub, and Mobi eBooks
4
+
5
+ [Example project](./example)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'ebookie'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install ebookie
20
+
21
+ ## Usage
22
+
23
+ Create a new document:
24
+
25
+ ```ruby
26
+ document = Ebookie::Document.new "My eBook" # Title
27
+ ```
28
+
29
+ Configure it:
30
+
31
+ ```ruby
32
+ document.configure do |config|
33
+ config.cover = './path/to/cover.png' # Cover image
34
+ config.destination = './ebook/' # Ouput for ePub, Mobi, PDF
35
+ config.subject = "Introductions"
36
+ config.source = "http://google.com"
37
+ end
38
+ ```
39
+
40
+ Add a chapter:
41
+
42
+ ```ruby
43
+ # You can pass a string for the content
44
+ document.chapter 'Getting Started', "All about how to get started"
45
+
46
+ # You can also give it an html file to read
47
+ document.chapter 'Getting Started', Pathname.new("path/to/myfile.html")
48
+ ```
49
+
50
+ Add an image:
51
+
52
+ ```ruby
53
+ # Relative or absolute path for image to be copied
54
+ document.image './path/to/image.png'
55
+
56
+ # Chapters can reference images with html:
57
+ document.chapter "My Cool Image", "<img src='image.png' alt='image' />"
58
+ ```
59
+
60
+ Render the document:
61
+
62
+ ```ruby
63
+ # ePub
64
+ document.render_epub
65
+
66
+ # Mobi
67
+ document.render_mobi
68
+
69
+ # PDF
70
+ document.render_pdf
71
+ ```
72
+
73
+ #### Install templates for customization:
74
+
75
+ ```bash
76
+ $ ebookie install ./path/to/templatees
77
+ ```
78
+
79
+ Then configure the document:
80
+
81
+ ```ruby
82
+ document.config.template = './path/to/templates'
83
+ ```
84
+
85
+ ## Contributing
86
+
87
+ 1. Fork it ( http://github.com/mailchimp/ebookie/fork )
88
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
89
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
90
+ 4. Push to the branch (`git push origin my-new-feature`)
91
+ 5. Create new Pull Request
@@ -0,0 +1,16 @@
1
+ module Ebookie
2
+ require "ebookie/version"
3
+ require "ebookie/document"
4
+ require "ebookie/rendering"
5
+ require "logger"
6
+
7
+ def self.logger
8
+ @logger ||= Logger.new(STDOUT)
9
+ if ENV['LOG_LEVEL'] && log_level = Logger.const_get(ENV['LOG_LEVEL'])
10
+ @logger.level = log_level
11
+ else
12
+ @logger.level = Logger::WARN
13
+ end
14
+ @logger
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require "thor"
2
+ require "pathname"
3
+
4
+ module Ebookie
5
+ class Cli < Thor
6
+ include Thor::Actions
7
+ add_runtime_options!
8
+
9
+ desc "install DIRECTORY", "install template files to DIRECTORY"
10
+ def install(directory)
11
+ exec_dir = Pathname.new(Dir.pwd)
12
+ templates_dir = Pathname.new(File.expand_path('../templates', __FILE__))
13
+
14
+ Ebookie::Cli.source_root templates_dir
15
+
16
+ directory templates_dir, exec_dir.join(directory)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ require "ebookie/document/config"
2
+ require "ebookie/document/base"
3
+ require "ebookie/document/chapter"
4
+ require "ebookie/document/image"
5
+
6
+ module Ebookie
7
+ module Document
8
+ class << self
9
+
10
+ def new(*args)
11
+ Base.new(*args)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,49 @@
1
+ module Ebookie
2
+ module Document
3
+ class Base
4
+
5
+ attr_reader :chapters, :images, :config
6
+
7
+ def initialize(title)
8
+ @chapters = []
9
+ @images = []
10
+
11
+ @config = Config.new
12
+ @config.title = title
13
+ end
14
+
15
+ def configure(&block)
16
+ yield @config
17
+ end
18
+
19
+ def chapter(title, content)
20
+ @chapters << Chapter.new(title, content)
21
+ end
22
+
23
+ def image(file)
24
+ @images << Image.new(file)
25
+ end
26
+
27
+ def render_pdf
28
+ Rendering::Pdf.new(self).render
29
+ end
30
+
31
+ def render_epub
32
+ Rendering::Epub.new(self).render
33
+ end
34
+
35
+ def render_mobi
36
+ Rendering::Mobi.new(self).render
37
+ end
38
+
39
+ def method_missing(meth, *args)
40
+ if @config.respond_to?(meth)
41
+ @config.send(meth, *args)
42
+ else
43
+ super
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,26 @@
1
+ module Ebookie
2
+ module Document
3
+ class Chapter
4
+
5
+ attr_accessor :title, :content
6
+
7
+ def initialize(title, content)
8
+ @title = title
9
+ @content = content
10
+ end
11
+
12
+ def content
13
+ if @content.is_a? Pathname
14
+ @content.read
15
+ else
16
+ @content
17
+ end
18
+ end
19
+
20
+ def slug
21
+ title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ module Ebookie
2
+ module Document
3
+ class Config
4
+
5
+ attr_accessor :title
6
+ attr_accessor :creator
7
+ attr_accessor :publisher
8
+ attr_accessor :rights
9
+ attr_accessor :subject
10
+ attr_accessor :language
11
+ attr_accessor :source
12
+ attr_accessor :date
13
+ attr_accessor :destination
14
+ attr_accessor :cover
15
+ attr_accessor :template
16
+
17
+ def date
18
+ @date || Time.now.strftime("%F")
19
+ end
20
+
21
+ def language
22
+ @language || "en-US"
23
+ end
24
+
25
+ def cover=(path)
26
+ if File.exists?(path) || path.match(/http[s]?:\/\//)
27
+ if %w(.png .pdf).include? File.extname(path)
28
+ @cover = Pathname.new(path)
29
+ else
30
+ Ebookie.logger.warn "Cover file is not a valid"
31
+ end
32
+ else
33
+ Ebookie.logger.warn "Cover file does not exist"
34
+ end
35
+ end
36
+
37
+ def slug
38
+ title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ module Ebookie
2
+ module Document
3
+ class Image
4
+
5
+ attr_reader :file
6
+
7
+ def initialize(filepath)
8
+ self.file = filepath
9
+ end
10
+
11
+ def file=(path)
12
+ if File.exists?(path) || path.match(/http[s]?:\/\//)
13
+ if File.extname(path) == '.png'
14
+ @file = Pathname.new(path)
15
+ else
16
+ Ebookie.logger.warn "Image file is not a valid png for '#{path}'"
17
+ end
18
+ else
19
+ Ebookie.logger.warn "Image file does not exist for '#{path}'"
20
+ end
21
+ end
22
+
23
+ def basename
24
+ File.basename(file) if file
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ require "ebookie/rendering/base"
2
+ require "ebookie/rendering/epub"
3
+ require "ebookie/rendering/mobi"
4
+ require "ebookie/rendering/pdf"
5
+
6
+ module Ebookie
7
+ module Rendering
8
+
9
+ end
10
+ end
@@ -0,0 +1,156 @@
1
+ require "ostruct"
2
+ require "borrower"
3
+ require "erb"
4
+
5
+ module Ebookie
6
+ module Rendering
7
+ class Base
8
+ IMAGE_SRC_REGEX = /src=['|"]((\/?.+\/)*)?(.+?[\.]+.+?)['|"]/xi
9
+
10
+ attr_reader :document
11
+
12
+ def initialize(document)
13
+ @document = document
14
+
15
+ after_initialize if respond_to?(:after_initialize)
16
+ end
17
+
18
+ class << self
19
+ def inherited(subclass)
20
+ subclass.class_eval do
21
+ attr_reader :settings
22
+ end
23
+
24
+ subclass.instance_eval do
25
+ define_method :settings do
26
+ @@settings.send(format) || {}
27
+ end
28
+ end
29
+ end
30
+
31
+ def set(key, val)
32
+ @@settings ||= OpenStruct.new
33
+
34
+ format_options = @@settings.send(format) || {}
35
+ @@settings.send "#{format}=", format_options.merge({key => val})
36
+ end
37
+
38
+ def format
39
+ self.name.split("::").last.downcase
40
+ end
41
+ end
42
+
43
+ def render
44
+ throw "Output path required" unless document.destination
45
+
46
+ FileUtils.mkdir_p(tmp_dir) unless File.exists?(tmp_dir)
47
+
48
+ create_paths if settings.keys.include?(:paths) && settings[:paths]
49
+ copy_files if settings.keys.include?(:files) && settings[:files]
50
+ copy_images if document.images.any? && settings[:images_dir]
51
+
52
+ FileUtils.mkdir_p(document.destination) unless File.exists?(document.destination)
53
+
54
+ process!
55
+ return output_path
56
+ end
57
+
58
+ def template_file(path)
59
+ custom_template_dir = Pathname.new(document.template) if document.template
60
+
61
+ if document.template && File.exists?(custom_template_dir.join(format, path))
62
+ custom_template_dir.join(format, path)
63
+ else
64
+ template_dir.join(path)
65
+ end
66
+ end
67
+
68
+ def render_erb_to_file(template, filepath, locals={})
69
+ locals.merge! document: document, renderer: self
70
+
71
+ locals_struct = OpenStruct.new(locals).instance_eval { binding }
72
+ contents = ERB.new(File.read(template)).result(locals_struct)
73
+
74
+ write_contents_to_file(contents, filepath)
75
+ end
76
+
77
+ def tmp_dir
78
+ Pathname.new(File.expand_path("../../../../tmp/#{document.config.slug}/#{format}", __FILE__))
79
+ end
80
+
81
+ def template_dir
82
+ Pathname.new(File.expand_path("../../templates/#{format}", __FILE__))
83
+ end
84
+
85
+ def format
86
+ self.class.format
87
+ end
88
+
89
+ def output_path
90
+ Pathname.new(document.destination).join("#{document.config.slug}.#{format}").to_s
91
+ end
92
+
93
+ def sanitize_html(html)
94
+ {
95
+ /&rsquo;|&lsquo;/ => "'",
96
+ /&rdquo;|&ldquo;|“|”/ => "\"",
97
+ "’" => "'",
98
+ "&#58;" => ":",
99
+ "⌘" => "&#8984;"
100
+ }.each do |k,v|
101
+ html.gsub! k, v
102
+ end
103
+
104
+ html
105
+ end
106
+
107
+ def clean_images(html, new_path)
108
+ html.each_line do |line|
109
+ old_line = line.dup
110
+ matches = line.match(IMAGE_SRC_REGEX).to_a
111
+ next unless matches.any?
112
+
113
+ # remove folder
114
+ line.gsub! matches[2], "" if matches[2]
115
+
116
+ # set our folder
117
+ line.gsub! matches[3], new_path.join(matches[3]).to_s
118
+
119
+ html.gsub! old_line, line
120
+ end
121
+ end
122
+
123
+ private
124
+
125
+ def create_paths
126
+ settings[:paths].each do |path|
127
+ FileUtils.mkdir_p tmp_dir.join(path)
128
+ end
129
+ end
130
+
131
+ def copy_images
132
+ document.images.each do |image|
133
+ borrow image.file.to_s, to: tmp_dir.join(settings[:images_dir], image.basename)
134
+ end
135
+ end
136
+
137
+ def copy_files
138
+ settings[:files].each do |file|
139
+ if File.extname(file) == '.erb' && ext = File.extname(file)
140
+ render_erb_to_file template_file(file), tmp_dir.join(file.gsub(ext, ''))
141
+ else
142
+ FileUtils.cp template_file(file), tmp_dir.join(file)
143
+ end
144
+ end
145
+ end
146
+
147
+ def write_contents_to_file(contents, filepath, mode="w+")
148
+ File.open(filepath, mode) do |handle|
149
+ handle.write(contents)
150
+ handle.close
151
+ end
152
+ end
153
+
154
+ end
155
+ end
156
+ end