burr 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/LICENSE.md +30 -0
- data/README.md +180 -0
- data/Rakefile +118 -0
- data/bin/burr +9 -0
- data/burr.gemspec +36 -0
- data/generators/Gemfile.txt +3 -0
- data/generators/config.yml +55 -0
- data/generators/contents/chapter1.md +7 -0
- data/generators/contents/chapter2.md +7 -0
- data/generators/stylesheets/pdf.css +569 -0
- data/generators/stylesheets/site.css +1 -0
- data/lib/burr.rb +56 -0
- data/lib/burr/book.rb +289 -0
- data/lib/burr/cli.rb +64 -0
- data/lib/burr/converter.rb +19 -0
- data/lib/burr/core_ext/blank.rb +107 -0
- data/lib/burr/dependency.rb +28 -0
- data/lib/burr/eeepub_ext/maker.rb +131 -0
- data/lib/burr/exporter.rb +137 -0
- data/lib/burr/exporters/epub.rb +163 -0
- data/lib/burr/exporters/pdf.rb +95 -0
- data/lib/burr/exporters/site.rb +101 -0
- data/lib/burr/generator.rb +41 -0
- data/lib/burr/kramdown_ext/converter.rb +145 -0
- data/lib/burr/kramdown_ext/options.rb +38 -0
- data/lib/burr/kramdown_ext/parser.rb +65 -0
- data/lib/burr/liquid_ext/block.rb +58 -0
- data/lib/burr/liquid_ext/extends.rb +114 -0
- data/lib/burr/plugin.rb +70 -0
- data/lib/burr/plugins/aside.rb +44 -0
- data/lib/burr/plugins/codeblock.rb +42 -0
- data/lib/burr/plugins/figure.rb +62 -0
- data/lib/burr/plugins/link.rb +47 -0
- data/lib/burr/plugins/parser_plugin.rb +18 -0
- data/lib/burr/plugins/table.rb +42 -0
- data/lib/burr/plugins/toc.rb +105 -0
- data/lib/burr/ruby_version_check.rb +4 -0
- data/lib/burr/server.rb +27 -0
- data/lib/burr/ui.rb +46 -0
- data/lib/burr/version.rb +8 -0
- data/resources/locales/labels/en.yml +45 -0
- data/resources/locales/labels/zh_CN.yml +46 -0
- data/resources/locales/titles/en.yml +21 -0
- data/resources/locales/titles/zh_CN.yml +21 -0
- data/resources/templates/epub/_layout.liquid +17 -0
- data/resources/templates/epub/acknowledgement.liquid +10 -0
- data/resources/templates/epub/afterword.liquid +10 -0
- data/resources/templates/epub/appendix.liquid +10 -0
- data/resources/templates/epub/author.liquid +10 -0
- data/resources/templates/epub/chapter.liquid +10 -0
- data/resources/templates/epub/conclusion.liquid +10 -0
- data/resources/templates/epub/cover.liquid +9 -0
- data/resources/templates/epub/dedication.liquid +10 -0
- data/resources/templates/epub/edition.liquid +1 -0
- data/resources/templates/epub/epilogue.liquid +1 -0
- data/resources/templates/epub/foreword.liquid +10 -0
- data/resources/templates/epub/glossary.liquid +1 -0
- data/resources/templates/epub/introduction.liquid +1 -0
- data/resources/templates/epub/license.liquid +1 -0
- data/resources/templates/epub/lof.liquid +24 -0
- data/resources/templates/epub/lot.liquid +24 -0
- data/resources/templates/epub/part.liquid +4 -0
- data/resources/templates/epub/preface.liquid +10 -0
- data/resources/templates/epub/prologue.liquid +1 -0
- data/resources/templates/epub/table.liquid +7 -0
- data/resources/templates/epub/title.liquid +3 -0
- data/resources/templates/epub/toc.liquid +10 -0
- data/resources/templates/pdf/_item.liquid +6 -0
- data/resources/templates/pdf/acknowledgement.liquid +1 -0
- data/resources/templates/pdf/afterword.liquid +1 -0
- data/resources/templates/pdf/appendix.liquid +4 -0
- data/resources/templates/pdf/author.liquid +1 -0
- data/resources/templates/pdf/blank.liquid +3 -0
- data/resources/templates/pdf/book.liquid +42 -0
- data/resources/templates/pdf/chapter.liquid +4 -0
- data/resources/templates/pdf/code.liquid +3 -0
- data/resources/templates/pdf/conclusion.liquid +1 -0
- data/resources/templates/pdf/cover.liquid +6 -0
- data/resources/templates/pdf/dedication.liquid +3 -0
- data/resources/templates/pdf/edition.liquid +1 -0
- data/resources/templates/pdf/epilogue.liquid +1 -0
- data/resources/templates/pdf/foreword.liquid +1 -0
- data/resources/templates/pdf/glossary.liquid +1 -0
- data/resources/templates/pdf/introduction.liquid +1 -0
- data/resources/templates/pdf/license.liquid +1 -0
- data/resources/templates/pdf/lof.liquid +24 -0
- data/resources/templates/pdf/lot.liquid +24 -0
- data/resources/templates/pdf/part.liquid +4 -0
- data/resources/templates/pdf/preface.liquid +1 -0
- data/resources/templates/pdf/prologue.liquid +1 -0
- data/resources/templates/pdf/table.liquid +7 -0
- data/resources/templates/pdf/title.liquid +3 -0
- data/resources/templates/pdf/toc.liquid +4 -0
- data/resources/templates/site/_layout.liquid +27 -0
- data/resources/templates/site/author.liquid +13 -0
- data/resources/templates/site/chapter.liquid +13 -0
- data/resources/templates/site/foreword.liquid +13 -0
- data/resources/templates/site/preface.liquid +13 -0
- 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
|