burr 0.0.2

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.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.md +30 -0
  6. data/README.md +180 -0
  7. data/Rakefile +118 -0
  8. data/bin/burr +9 -0
  9. data/burr.gemspec +36 -0
  10. data/generators/Gemfile.txt +3 -0
  11. data/generators/config.yml +55 -0
  12. data/generators/contents/chapter1.md +7 -0
  13. data/generators/contents/chapter2.md +7 -0
  14. data/generators/stylesheets/pdf.css +569 -0
  15. data/generators/stylesheets/site.css +1 -0
  16. data/lib/burr.rb +56 -0
  17. data/lib/burr/book.rb +289 -0
  18. data/lib/burr/cli.rb +64 -0
  19. data/lib/burr/converter.rb +19 -0
  20. data/lib/burr/core_ext/blank.rb +107 -0
  21. data/lib/burr/dependency.rb +28 -0
  22. data/lib/burr/eeepub_ext/maker.rb +131 -0
  23. data/lib/burr/exporter.rb +137 -0
  24. data/lib/burr/exporters/epub.rb +163 -0
  25. data/lib/burr/exporters/pdf.rb +95 -0
  26. data/lib/burr/exporters/site.rb +101 -0
  27. data/lib/burr/generator.rb +41 -0
  28. data/lib/burr/kramdown_ext/converter.rb +145 -0
  29. data/lib/burr/kramdown_ext/options.rb +38 -0
  30. data/lib/burr/kramdown_ext/parser.rb +65 -0
  31. data/lib/burr/liquid_ext/block.rb +58 -0
  32. data/lib/burr/liquid_ext/extends.rb +114 -0
  33. data/lib/burr/plugin.rb +70 -0
  34. data/lib/burr/plugins/aside.rb +44 -0
  35. data/lib/burr/plugins/codeblock.rb +42 -0
  36. data/lib/burr/plugins/figure.rb +62 -0
  37. data/lib/burr/plugins/link.rb +47 -0
  38. data/lib/burr/plugins/parser_plugin.rb +18 -0
  39. data/lib/burr/plugins/table.rb +42 -0
  40. data/lib/burr/plugins/toc.rb +105 -0
  41. data/lib/burr/ruby_version_check.rb +4 -0
  42. data/lib/burr/server.rb +27 -0
  43. data/lib/burr/ui.rb +46 -0
  44. data/lib/burr/version.rb +8 -0
  45. data/resources/locales/labels/en.yml +45 -0
  46. data/resources/locales/labels/zh_CN.yml +46 -0
  47. data/resources/locales/titles/en.yml +21 -0
  48. data/resources/locales/titles/zh_CN.yml +21 -0
  49. data/resources/templates/epub/_layout.liquid +17 -0
  50. data/resources/templates/epub/acknowledgement.liquid +10 -0
  51. data/resources/templates/epub/afterword.liquid +10 -0
  52. data/resources/templates/epub/appendix.liquid +10 -0
  53. data/resources/templates/epub/author.liquid +10 -0
  54. data/resources/templates/epub/chapter.liquid +10 -0
  55. data/resources/templates/epub/conclusion.liquid +10 -0
  56. data/resources/templates/epub/cover.liquid +9 -0
  57. data/resources/templates/epub/dedication.liquid +10 -0
  58. data/resources/templates/epub/edition.liquid +1 -0
  59. data/resources/templates/epub/epilogue.liquid +1 -0
  60. data/resources/templates/epub/foreword.liquid +10 -0
  61. data/resources/templates/epub/glossary.liquid +1 -0
  62. data/resources/templates/epub/introduction.liquid +1 -0
  63. data/resources/templates/epub/license.liquid +1 -0
  64. data/resources/templates/epub/lof.liquid +24 -0
  65. data/resources/templates/epub/lot.liquid +24 -0
  66. data/resources/templates/epub/part.liquid +4 -0
  67. data/resources/templates/epub/preface.liquid +10 -0
  68. data/resources/templates/epub/prologue.liquid +1 -0
  69. data/resources/templates/epub/table.liquid +7 -0
  70. data/resources/templates/epub/title.liquid +3 -0
  71. data/resources/templates/epub/toc.liquid +10 -0
  72. data/resources/templates/pdf/_item.liquid +6 -0
  73. data/resources/templates/pdf/acknowledgement.liquid +1 -0
  74. data/resources/templates/pdf/afterword.liquid +1 -0
  75. data/resources/templates/pdf/appendix.liquid +4 -0
  76. data/resources/templates/pdf/author.liquid +1 -0
  77. data/resources/templates/pdf/blank.liquid +3 -0
  78. data/resources/templates/pdf/book.liquid +42 -0
  79. data/resources/templates/pdf/chapter.liquid +4 -0
  80. data/resources/templates/pdf/code.liquid +3 -0
  81. data/resources/templates/pdf/conclusion.liquid +1 -0
  82. data/resources/templates/pdf/cover.liquid +6 -0
  83. data/resources/templates/pdf/dedication.liquid +3 -0
  84. data/resources/templates/pdf/edition.liquid +1 -0
  85. data/resources/templates/pdf/epilogue.liquid +1 -0
  86. data/resources/templates/pdf/foreword.liquid +1 -0
  87. data/resources/templates/pdf/glossary.liquid +1 -0
  88. data/resources/templates/pdf/introduction.liquid +1 -0
  89. data/resources/templates/pdf/license.liquid +1 -0
  90. data/resources/templates/pdf/lof.liquid +24 -0
  91. data/resources/templates/pdf/lot.liquid +24 -0
  92. data/resources/templates/pdf/part.liquid +4 -0
  93. data/resources/templates/pdf/preface.liquid +1 -0
  94. data/resources/templates/pdf/prologue.liquid +1 -0
  95. data/resources/templates/pdf/table.liquid +7 -0
  96. data/resources/templates/pdf/title.liquid +3 -0
  97. data/resources/templates/pdf/toc.liquid +4 -0
  98. data/resources/templates/site/_layout.liquid +27 -0
  99. data/resources/templates/site/author.liquid +13 -0
  100. data/resources/templates/site/chapter.liquid +13 -0
  101. data/resources/templates/site/foreword.liquid +13 -0
  102. data/resources/templates/site/preface.liquid +13 -0
  103. metadata +232 -0
@@ -0,0 +1 @@
1
+ @charset 'utf-8';
data/lib/burr.rb ADDED
@@ -0,0 +1,56 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ # Require all of the Ruby files in the given directory.
4
+ #
5
+ # path - The String relative path from here to the directory.
6
+ #
7
+ # Returns nothing.
8
+ def require_all(path)
9
+ glob = File.join(File.dirname(__FILE__), path, '*.rb')
10
+ Dir[glob].each do |f|
11
+ require f
12
+ end
13
+ end
14
+
15
+ require 'nokogiri'
16
+ require 'kramdown'
17
+ require 'liquid'
18
+ require 'thor'
19
+ require 'thor/group'
20
+ require 'eeepub'
21
+
22
+ require 'yaml'
23
+
24
+ require_all 'burr/core_ext'
25
+ require_all 'burr/kramdown_ext'
26
+ require 'burr/cli'
27
+ require 'burr/dependency'
28
+ require 'burr/generator'
29
+ require 'burr/version'
30
+ require 'burr/ui'
31
+ require 'burr/converter'
32
+ require 'burr/exporter'
33
+ require_all 'burr/exporters'
34
+ require 'burr/plugin'
35
+ require_all 'burr/plugins'
36
+ require_all 'burr/liquid_ext'
37
+ require_all 'burr/eeepub_ext'
38
+ require 'burr/book'
39
+ require 'burr/server'
40
+
41
+ Encoding.default_internal = 'utf-8'
42
+ Encoding.default_external = 'utf-8'
43
+
44
+ module Burr
45
+
46
+ def self.configuration
47
+ path = "#{Dir.pwd}/config.yml"
48
+
49
+ begin
50
+ YAML.load_file path
51
+ rescue => e
52
+ puts "#{e.message}"
53
+ end
54
+ end
55
+
56
+ end
data/lib/burr/book.rb ADDED
@@ -0,0 +1,289 @@
1
+ module Burr
2
+ class Book
3
+
4
+ attr_accessor :config, :format, :ui
5
+ attr_accessor :gem_dir, :root_dir, :outputs_dir, :caches_dir, :contents_dir, :plugins_dir, :templates_dir
6
+ attr_accessor :items, :toc, :images, :tables, :current_item
7
+ attr_accessor :labels, :titles, :ids
8
+ attr_accessor :uid, :slug
9
+
10
+ def initialize(config, format)
11
+ @config = config
12
+ @format = format
13
+ @ui = Burr::UI.new
14
+
15
+ # directory location
16
+ @gem_dir = File.expand_path('../../../' ,__FILE__)
17
+ @root_dir = Dir.pwd
18
+ @outputs_dir = "#{@root_dir}/outputs"
19
+ @caches_dir = "#{@root_dir}/caches"
20
+ @contents_dir = "#{@root_dir}/contents"
21
+ @plugins_dir = "#{@root_dir}/plugins"
22
+ @templates_dir = "#{@root_dir}/templates"
23
+
24
+ # publishing process variables
25
+ @items = []
26
+ @toc = ''
27
+ @images = []
28
+ @tables = []
29
+ @current_item = []
30
+
31
+ # labels and titles
32
+ book_labels # @labels = {}, @ids = []
33
+ book_titles # @titles = {}
34
+
35
+ # book information
36
+ book_uid # @uid = ''
37
+ book_slug # @slug = ''
38
+ end
39
+
40
+ # Export site files in outputs/site
41
+ #
42
+ def export_site
43
+ exporter = Burr::Site.new(self)
44
+ self.ui.confirm "Start exporting site files...."
45
+ exporter.run
46
+ self.ui.confirm "Exported site!"
47
+ end
48
+
49
+ # Export PDF files in outputs/pdf
50
+ #
51
+ def export_pdf
52
+ exporter = Burr::PDF.new(self)
53
+ self.ui.confirm "Start exporting pdf file...."
54
+ exporter.run
55
+ self.ui.confirm "Exported PDF!"
56
+ end
57
+
58
+ # Export Epub files in outputs/epub
59
+ #
60
+ def export_epub
61
+ exporter = Burr::Epub.new(self)
62
+ self.ui.confirm "Start exporting epub file...."
63
+ exporter.run
64
+ self.ui.confirm "Exported Epub!"
65
+ end
66
+
67
+ # Export Mobi files in outputs/mobi
68
+ #
69
+ def export_mobi
70
+ dest = File.join(self.outputs_dir, 'mobi')
71
+ FileUtils.mkdir_p(dest) unless File.exist?(dest)
72
+
73
+ self.ui.confirm "Start exporting mobi file...."
74
+
75
+ FileUtils.cd(File.join(self.outputs_dir, 'epub')) do
76
+ base = "#{self.config['slug']}-#{Time.new.strftime('%Y%m%d')}"
77
+ epub = "#{base}.epub"
78
+ mobi = "#{base}.mobi"
79
+ unless File.exist?(epub)
80
+ self.ui.error('Please export Epub first!')
81
+ exit 1
82
+ end
83
+
84
+ system "kindlegen #{epub} -c2"
85
+ FileUtils.cp(mobi, dest)
86
+ FileUtils.rm(mobi)
87
+ end
88
+
89
+ self.ui.confirm "Exported Mobi!"
90
+ end
91
+
92
+ # Export all formats
93
+ #
94
+ def export_all
95
+ self.export_pdf
96
+ self.export_epub
97
+ self.export_mobi
98
+ end
99
+
100
+ # Gets the template file for an element.
101
+ #
102
+ # - element The element name, such as 'chapter', 'appendix'
103
+ #
104
+ # Returns The absolute path of this element's template file.
105
+ #
106
+ def template_for(element)
107
+ base = File.join('templates', self.format, "#{element}.liquid")
108
+ default = File.join(self.gem_dir, 'resources', base)
109
+ custom = File.join(self.root_dir, base)
110
+
111
+ if File.exist?(custom)
112
+ custom
113
+ elsif !File.exist?(custom) && File.exist?(default)
114
+ default
115
+ else
116
+ self.ui.error("ERROR: Template #{self.format}/#{element}.liquid not found!")
117
+ exit 1
118
+ end
119
+ end
120
+
121
+ # Get the stylesheet file for a format.
122
+ #
123
+ # @param [String] format The format name, could be 'pdf', 'epub', 'site' and 'mobi'
124
+ # @return [String] The absolute path to this format's stylesheet
125
+ def stylesheet_for(format)
126
+ if %w(pdf epub site mobi).include?(format)
127
+ css = File.join(self.outputs_dir, format, "style.css")
128
+
129
+ if File.exist?(css)
130
+ css
131
+ else
132
+ self.ui.error("ERROR: Not found stylesheet for format #{format}.")
133
+ exit 1
134
+ end
135
+ else
136
+ self.ui.error("ERROR: #{format} is not support!")
137
+ exit 1
138
+ end
139
+ end
140
+
141
+ # Shortcut method to get the label of any element type.
142
+ #
143
+ # element - The element type (`chapter', `foreword', ...) in String format.
144
+ # variables - A variables Hash used to render the label.
145
+ #
146
+ # Returns the label String of the element or an empty String.
147
+ def render_label(element, variables = {})
148
+ c_labels = self.labels.include?(element) ? self.labels[element] : ''
149
+ # some elements (mostly chapters and appendices) have a different label for each level (h1, ..., h6)
150
+ if c_labels.is_a? Array
151
+ index = variables['item']['level'] - 1
152
+ if index == 0
153
+ label = c_labels[0]
154
+ else
155
+ label = c_labels[1]
156
+ end
157
+ else
158
+ label = c_labels
159
+ end
160
+
161
+ self.render_string(label, variables)
162
+ end
163
+
164
+ # Shortcut method to get the id of headings.
165
+ #
166
+ # variables - A variables Hash used to render the id.
167
+ #
168
+ # Returns the id String of the heading.
169
+ def render_id(variables = {})
170
+ index = variables['item']['level'] - 1
171
+ if index == 0
172
+ id = self.ids[0]
173
+ else
174
+ id = self.ids[1]
175
+ end
176
+
177
+ self.render_string(id, variables)
178
+ end
179
+
180
+ # Renders any string as a Liquid template.
181
+ #
182
+ # @param [String] text The original content to render
183
+ # @param [Array] variables Optional variables passed to the template
184
+ def render_string(text, variables = {})
185
+ registers = { :registers => { :book => self } }
186
+ Liquid::Template.parse(text).render(variables, registers)
187
+ end
188
+
189
+
190
+ # Renders any template (currently only supports Liquid templates).
191
+ #
192
+ # @param [String] template The template name, without the extension
193
+ # @param [Hash] parameters Optional variables passed to the template
194
+ # @param [String] target Optional output file path. If set, the rendered template is saved in this file.
195
+ # @return [String] The rendered content
196
+ def render(template, parameters = {}, target = nil)
197
+ defaults = {
198
+ 'config' => self.config,
199
+ 'format' => self.format,
200
+ 'generator' => { 'name' => 'Burr', 'version' => Burr::Version::STRING }
201
+ }
202
+ text = File.read(template)
203
+ registers = { :registers => { :book => self } }
204
+ content = Liquid::Template.parse(text).render(defaults.merge(parameters), registers)
205
+
206
+ if target
207
+ File.open(target, 'wb') { |f| f.puts content }
208
+ end
209
+
210
+ content
211
+ end
212
+
213
+ # Makes the liquid tags live.
214
+ #
215
+ # Returns Hash.
216
+ def to_liquid
217
+ #{ 'book' => self }
218
+ end
219
+
220
+ private
221
+
222
+ # Generates `@labels' for chapters, appendixes, etc.
223
+ #
224
+ # Returns nil.
225
+ def book_labels
226
+ base = File.join('locales', 'labels', "#{self.config['language']}.yml")
227
+ default = File.join(self.gem_dir, 'resources', base)
228
+ custom = File.join(self.root_dir, base)
229
+
230
+ labels = YAML::load_file(default)
231
+
232
+ #books can define their own labels files
233
+ if File.exist? custom
234
+ custom_labels = YAML::load_file(custom)
235
+ labels.merge!(custom_labels)
236
+ end
237
+
238
+ self.labels = labels
239
+ self.ids = labels['id']
240
+ nil
241
+ end
242
+
243
+ # Generates `@titles' for chapters, appendixes, etc.
244
+ #
245
+ # Returns nil.
246
+ def book_titles
247
+ base = File.join('locales', 'titles', "#{self.config['language']}.yml")
248
+ default = File.join(self.gem_dir, 'resources', base)
249
+ custom = File.join(self.root_dir, base)
250
+
251
+ titles = YAML::load_file(default)
252
+
253
+ #books can define their own titles files
254
+ if File.exist? custom
255
+ custom_titles = YAML::load_file(custom)
256
+ return titles.merge(custom_titles)
257
+ end
258
+
259
+ self.titles = titles
260
+ nil
261
+ end
262
+
263
+ # Generates a unique `@uid' for the book.
264
+ #
265
+ # Returns nil.
266
+ def book_uid
267
+ if @config['isbn']
268
+ @uid = @config['isbn']
269
+ else
270
+ @uid = Digest::MD5.hexdigest("#{Time.now}--#{rand}")
271
+ end
272
+ end
273
+
274
+ # Generates a `@slug' for the book.
275
+ #
276
+ # Uses the current directory name as slug, if no `slug' in `config.yml' provided.
277
+ #
278
+ # Returns String of the book's slug.
279
+ def book_slug
280
+ if @config['slug']
281
+ @slug = @config['slug']
282
+ else
283
+ dir = File.basename(self.root_dir)
284
+ @slug = CGI.escape(dir)
285
+ end
286
+ end
287
+
288
+ end
289
+ end
data/lib/burr/cli.rb ADDED
@@ -0,0 +1,64 @@
1
+ module Burr
2
+ class Cli < Thor
3
+
4
+ desc 'new [PATH]', 'Create a new book'
5
+ def new(path)
6
+ generator = Burr::Generator.new
7
+ generator.destination_root = path
8
+ generator.invoke_all
9
+ end
10
+
11
+ desc 'export [FORMAT]', 'Export a book format, or all formats'
12
+ def export(format)
13
+ valid = %w(site pdf epub mobi all)
14
+
15
+ if valid.include?(format)
16
+ book = Burr::Book.new(config, format)
17
+ case format
18
+ when 'site'
19
+ book.export_site
20
+ when 'pdf'
21
+ unless Dependency.prince_installed?
22
+ book.ui.warn "Please install PrinceXML first."
23
+ exit 1
24
+ end
25
+ book.export_pdf
26
+ when 'epub'
27
+ book.export_epub
28
+ when 'mobi'
29
+ unless Dependency.kindlegen_installed?
30
+ book.ui.warn "Please install kindelgen first."
31
+ exit 1
32
+ end
33
+ book.export_mobi
34
+ when 'all'
35
+ puts 'pending'
36
+ # book.export_all
37
+ end
38
+ else
39
+ raise "ERROR: invalid format. Formats: #{valid.join(', ')}."
40
+ end
41
+ end
42
+
43
+ desc 'server', 'Site preview'
44
+ def server
45
+ Burr::Server.start!
46
+ end
47
+
48
+ desc 'version', 'Show the burr version'
49
+ def version
50
+ puts Burr::Version::STRING
51
+ end
52
+
53
+ private
54
+
55
+ def config
56
+ @config ||= Burr.configuration
57
+ end
58
+
59
+ def book_root
60
+ @root ||= Dir.pwd
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,19 @@
1
+ module Burr
2
+ class Converter
3
+
4
+ attr_accessor :book
5
+
6
+ def initialize(book)
7
+ @book = book
8
+ end
9
+
10
+ def convert(text)
11
+ ::Kramdown::Document.new(text,
12
+ :input => 'Bsmarkdown',
13
+ :auto_ids => false,
14
+ :register => self.book
15
+ ).to_bshtml
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+
3
+ # This file is steal from Rails
4
+
5
+ class Object
6
+ # An object is blank if it's false, empty, or a whitespace string.
7
+ # For example, '', ' ', +nil+, [], and {} are all blank.
8
+ #
9
+ # This simplifies:
10
+ #
11
+ # if address.nil? || address.empty?
12
+ #
13
+ # ...to:
14
+ #
15
+ # if address.blank?
16
+ def blank?
17
+ respond_to?(:empty?) ? empty? : !self
18
+ end
19
+
20
+ # An object is present if it's not <tt>blank?</tt>.
21
+ def present?
22
+ !blank?
23
+ end
24
+
25
+ # Returns object if it's <tt>present?</tt> otherwise returns +nil+.
26
+ # <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
27
+ #
28
+ # This is handy for any representation of objects where blank is the same
29
+ # as not present at all. For example, this simplifies a common check for
30
+ # HTTP POST/query parameters:
31
+ #
32
+ # state = params[:state] if params[:state].present?
33
+ # country = params[:country] if params[:country].present?
34
+ # region = state || country || 'US'
35
+ #
36
+ # ...becomes:
37
+ #
38
+ # region = params[:state].presence || params[:country].presence || 'US'
39
+ def presence
40
+ self if present?
41
+ end
42
+ end
43
+
44
+ class NilClass
45
+ # +nil+ is blank:
46
+ #
47
+ # nil.blank? # => true
48
+ def blank?
49
+ true
50
+ end
51
+ end
52
+
53
+ class FalseClass
54
+ # +false+ is blank:
55
+ #
56
+ # false.blank? # => true
57
+ def blank?
58
+ true
59
+ end
60
+ end
61
+
62
+ class TrueClass
63
+ # +true+ is not blank:
64
+ #
65
+ # true.blank? # => false
66
+ def blank?
67
+ false
68
+ end
69
+ end
70
+
71
+ class Array
72
+ # An array is blank if it's empty:
73
+ #
74
+ # [].blank? # => true
75
+ # [1,2,3].blank? # => false
76
+ alias_method :blank?, :empty?
77
+ end
78
+
79
+ class Hash
80
+ # A hash is blank if it's empty:
81
+ #
82
+ # {}.blank? # => true
83
+ # { key: 'value' }.blank? # => false
84
+ alias_method :blank?, :empty?
85
+ end
86
+
87
+ class String
88
+ # A string is blank if it's empty or contains whitespaces only:
89
+ #
90
+ # ''.blank? # => true
91
+ # ' '.blank? # => true
92
+ # ' '.blank? # => true
93
+ # ' something here '.blank? # => false
94
+ def blank?
95
+ self !~ /[^[:space:]]/
96
+ end
97
+ end
98
+
99
+ class Numeric #:nodoc:
100
+ # No number is blank:
101
+ #
102
+ # 1.blank? # => false
103
+ # 0.blank? # => false
104
+ def blank?
105
+ false
106
+ end
107
+ end