epuber 0.7.4 → 0.8.0
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -2
- data/README.md +2 -1
- data/epuber.gemspec +10 -12
- data/lib/epuber/book/contributor.rb +0 -1
- data/lib/epuber/book/file_request.rb +1 -1
- data/lib/epuber/book/target.rb +20 -23
- data/lib/epuber/book/toc_item.rb +2 -4
- data/lib/epuber/book.rb +19 -19
- data/lib/epuber/checker/bookspec_checker.rb +26 -0
- data/lib/epuber/checker/text_checker.rb +2 -1
- data/lib/epuber/checker.rb +16 -2
- data/lib/epuber/checker_transformer_base.rb +2 -5
- data/lib/epuber/command/build.rb +34 -24
- data/lib/epuber/command/init.rb +23 -23
- data/lib/epuber/command/server.rb +2 -2
- data/lib/epuber/command.rb +17 -20
- data/lib/epuber/compiler/compilation_context.rb +10 -8
- data/lib/epuber/compiler/file_database.rb +0 -2
- data/lib/epuber/compiler/file_finders/abstract.rb +33 -23
- data/lib/epuber/compiler/file_finders/imaginary.rb +40 -35
- data/lib/epuber/compiler/file_resolver.rb +77 -88
- data/lib/epuber/compiler/file_stat.rb +4 -4
- data/lib/epuber/compiler/file_types/abstract_file.rb +3 -4
- data/lib/epuber/compiler/file_types/bade_file.rb +12 -7
- data/lib/epuber/compiler/file_types/coffee_script_file.rb +1 -1
- data/lib/epuber/compiler/file_types/generated_file.rb +1 -1
- data/lib/epuber/compiler/file_types/image_file.rb +4 -2
- data/lib/epuber/compiler/file_types/nav_file.rb +0 -1
- data/lib/epuber/compiler/file_types/opf_file.rb +0 -1
- data/lib/epuber/compiler/file_types/source_file.rb +8 -3
- data/lib/epuber/compiler/file_types/xhtml_file.rb +67 -13
- data/lib/epuber/compiler/generator.rb +1 -2
- data/lib/epuber/compiler/meta_inf_generator.rb +1 -1
- data/lib/epuber/compiler/nav_generator.rb +5 -6
- data/lib/epuber/compiler/opf_generator.rb +22 -23
- data/lib/epuber/compiler/problem.rb +12 -21
- data/lib/epuber/compiler/xhtml_processor.rb +61 -31
- data/lib/epuber/compiler.rb +66 -19
- data/lib/epuber/config.rb +13 -7
- data/lib/epuber/dsl/attribute.rb +16 -17
- data/lib/epuber/dsl/attribute_support.rb +3 -3
- data/lib/epuber/dsl/object.rb +17 -15
- data/lib/epuber/dsl/tree_object.rb +2 -3
- data/lib/epuber/epubcheck.rb +15 -0
- data/lib/epuber/helper.rb +0 -1
- data/lib/epuber/lockfile.rb +7 -9
- data/lib/epuber/plugin.rb +1 -2
- data/lib/epuber/ruby_extensions/match_data.rb +1 -1
- data/lib/epuber/ruby_extensions/thread.rb +1 -0
- data/lib/epuber/server/base.styl +0 -1
- data/lib/epuber/server/basic.styl +1 -30
- data/lib/epuber/server/handlers.rb +1 -1
- data/lib/epuber/server.rb +67 -66
- data/lib/epuber/third_party/bower.rb +5 -5
- data/lib/epuber/transformer/text_transformer.rb +4 -2
- data/lib/epuber/transformer.rb +2 -2
- data/lib/epuber/user_interface.rb +49 -38
- data/lib/epuber/vendor/hash_binding.rb +9 -2
- data/lib/epuber/vendor/ruby_templater.rb +1 -5
- data/lib/epuber/vendor/version.rb +10 -10
- data/lib/epuber/version.rb +1 -1
- metadata +67 -69
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Bold.ttf +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-BoldItalic.ttf +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Italic.ttf +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Regular.ttf +0 -0
@@ -11,20 +11,19 @@ require_relative '../book/toc_item'
|
|
11
11
|
module Epuber
|
12
12
|
class Compiler
|
13
13
|
class OPFGenerator < Generator
|
14
|
-
|
15
14
|
EPUB2_NAMESPACES = {
|
16
|
-
'xmlns'
|
17
|
-
'xmlns:dc'
|
15
|
+
'xmlns' => 'http://www.idpf.org/2007/opf',
|
16
|
+
'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
|
18
17
|
'xmlns:opf' => 'http://www.idpf.org/2007/opf',
|
19
18
|
}.freeze
|
20
19
|
|
21
20
|
EPUB3_NAMESPACES = {
|
22
|
-
'prefix'
|
21
|
+
'prefix' => 'rendition: http://www.idpf.org/vocab/rendition/',
|
23
22
|
'xmlns:epub' => 'http://www.idpf.org/2007/ops',
|
24
23
|
}.freeze
|
25
24
|
|
26
25
|
IBOOKS_NAMESPACES = {
|
27
|
-
'prefix'
|
26
|
+
'prefix' => 'rendition: http://www.idpf.org/vocab/rendition/# ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/',
|
28
27
|
'xmlns:ibooks' => 'http://apple.com/ibooks/html-extensions',
|
29
28
|
}.freeze
|
30
29
|
|
@@ -32,32 +31,32 @@ module Epuber
|
|
32
31
|
LANDMARKS_MAP = {
|
33
32
|
|
34
33
|
# my favorite
|
35
|
-
landmark_cover:
|
34
|
+
landmark_cover: 'cover',
|
36
35
|
landmark_start_page: 'text',
|
37
|
-
landmark_copyright:
|
38
|
-
landmark_toc:
|
36
|
+
landmark_copyright: 'copyright-page',
|
37
|
+
landmark_toc: 'toc',
|
39
38
|
|
40
39
|
# others
|
41
|
-
landmark_title:
|
42
|
-
landmark_index:
|
43
|
-
landmark_glossary:
|
44
|
-
landmark_acknowledgements:
|
45
|
-
landmark_bibliography:
|
46
|
-
landmark_colophon:
|
47
|
-
landmark_dedication:
|
48
|
-
landmark_epigraph:
|
49
|
-
landmark_foreword:
|
40
|
+
landmark_title: 'title-page',
|
41
|
+
landmark_index: 'index',
|
42
|
+
landmark_glossary: 'glossary',
|
43
|
+
landmark_acknowledgements: 'acknowledgements',
|
44
|
+
landmark_bibliography: 'bibliography',
|
45
|
+
landmark_colophon: 'colophon',
|
46
|
+
landmark_dedication: 'dedication',
|
47
|
+
landmark_epigraph: 'epigraph',
|
48
|
+
landmark_foreword: 'foreword',
|
50
49
|
landmark_list_of_illustrations: 'loi',
|
51
|
-
landmark_list_of_tables:
|
52
|
-
landmark_notes:
|
53
|
-
landmark_preface:
|
50
|
+
landmark_list_of_tables: 'lot',
|
51
|
+
landmark_notes: 'notes',
|
52
|
+
landmark_preface: 'preface',
|
54
53
|
|
55
54
|
}.freeze
|
56
55
|
|
57
56
|
PROPERTIES_MAP = {
|
58
57
|
cover_image: 'cover-image',
|
59
|
-
navigation:
|
60
|
-
scripted:
|
58
|
+
navigation: 'nav',
|
59
|
+
scripted: 'scripted',
|
61
60
|
remote_resources: 'remote-resources',
|
62
61
|
mathml: 'mathml',
|
63
62
|
}.freeze
|
@@ -164,7 +163,7 @@ module Epuber
|
|
164
163
|
attrs['media-type'] = mime_type_for(file)
|
165
164
|
|
166
165
|
properties = file.properties
|
167
|
-
if properties.length
|
166
|
+
if properties.length.positive? && @target.epub_version >= 3
|
168
167
|
pretty_properties = properties.to_a.map { |property| PROPERTIES_MAP[property] }.join(' ')
|
169
168
|
attrs['properties'] = pretty_properties
|
170
169
|
end
|
@@ -4,9 +4,7 @@ module Epuber
|
|
4
4
|
class Compiler
|
5
5
|
class Problem
|
6
6
|
class Location
|
7
|
-
attr_reader :line
|
8
|
-
attr_reader :column
|
9
|
-
attr_reader :length
|
7
|
+
attr_reader :line, :column, :length
|
10
8
|
|
11
9
|
def initialize(line, column, length = nil)
|
12
10
|
@line = line
|
@@ -15,20 +13,14 @@ module Epuber
|
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
18
|
-
attr_reader :level
|
19
|
-
attr_reader :message
|
20
|
-
attr_reader :source
|
21
|
-
attr_reader :location
|
22
|
-
attr_reader :file_path
|
16
|
+
attr_reader :level, :message, :source, :location, :file_path
|
23
17
|
|
24
18
|
def initialize(level, message, source, location: nil, line: nil, column: nil, length: nil, file_path: nil)
|
25
19
|
@level = level
|
26
20
|
@message = message
|
27
21
|
@source = source
|
28
22
|
@location = location
|
29
|
-
if @location.nil? && line && column
|
30
|
-
@location = Location.new(line, column, length)
|
31
|
-
end
|
23
|
+
@location = Location.new(line, column, length) if @location.nil? && line && column
|
32
24
|
|
33
25
|
@file_path = file_path
|
34
26
|
end
|
@@ -40,7 +32,7 @@ module Epuber
|
|
40
32
|
# @return [String]
|
41
33
|
#
|
42
34
|
def self.caret_symbol(indent)
|
43
|
-
' ' * indent
|
35
|
+
"#{' ' * indent}^"
|
44
36
|
end
|
45
37
|
|
46
38
|
# Formats caret symbols for indent and length
|
@@ -53,7 +45,7 @@ module Epuber
|
|
53
45
|
def self.caret_symbols(indent, length)
|
54
46
|
start_sign = caret_symbol(indent)
|
55
47
|
end_sign = if length > 1
|
56
|
-
caret_symbol(length-2)
|
48
|
+
caret_symbol(length - 2)
|
57
49
|
else
|
58
50
|
''
|
59
51
|
end
|
@@ -74,10 +66,11 @@ module Epuber
|
|
74
66
|
lines = text.split("\n")
|
75
67
|
|
76
68
|
line = lines[line_index] || ''
|
77
|
-
matched_text = line[column_index
|
69
|
+
matched_text = line[column_index...column_index + location.length] || ''
|
78
70
|
|
79
|
-
pre = (lines[0
|
80
|
-
post = ([line[column_index + location.length
|
71
|
+
pre = (lines[0...line_index] + [line[0...column_index]]).join("\n")
|
72
|
+
post = ([line[column_index + location.length..line.length]] + (lines[location.line..lines.count] || []))
|
73
|
+
.join("\n")
|
81
74
|
|
82
75
|
[pre, matched_text, post]
|
83
76
|
end
|
@@ -89,9 +82,7 @@ module Epuber
|
|
89
82
|
post_line = post.split("\n").first || ''
|
90
83
|
|
91
84
|
pre = match_pre_line = pre_line
|
92
|
-
if remove_tabs(match_pre_line).length > 100
|
93
|
-
pre = "#{match_pre_line.first(20)}...#{match_pre_line.last(30)}"
|
94
|
-
end
|
85
|
+
pre = "#{match_pre_line.first(20)}...#{match_pre_line.last(30)}" if remove_tabs(match_pre_line).length > 100
|
95
86
|
|
96
87
|
pre = remove_tabs(pre)
|
97
88
|
|
@@ -114,8 +105,8 @@ module Epuber
|
|
114
105
|
|
115
106
|
[
|
116
107
|
"#{@file_path}:#{line} column: #{column} --- #{@message}",
|
117
|
-
|
118
|
-
|
108
|
+
" #{pre}#{colored_match_text}#{post}",
|
109
|
+
" #{pointers}",
|
119
110
|
].join("\n")
|
120
111
|
end
|
121
112
|
end
|
@@ -13,7 +13,8 @@ module Epuber
|
|
13
13
|
|
14
14
|
# Method for parsing incomplete XML, supports multiple root elements
|
15
15
|
#
|
16
|
-
# @warning Because of nature of XML, when input string don't contain root element, it will create own called
|
16
|
+
# @warning Because of nature of XML, when input string don't contain root element, it will create own called
|
17
|
+
# `body`, since it will be used in next steps.
|
17
18
|
#
|
18
19
|
# @param [String] text input XHTML text
|
19
20
|
#
|
@@ -23,7 +24,8 @@ module Epuber
|
|
23
24
|
text = text.dup
|
24
25
|
|
25
26
|
if /\A[\n\r ]+(<\?xml)/ =~ text
|
26
|
-
UI.warning('XML header must be at the beginning of document',
|
27
|
+
UI.warning('XML header must be at the beginning of document',
|
28
|
+
location: UI::Location.new(path: file_path, lineno: 1))
|
27
29
|
|
28
30
|
text = text.lstrip
|
29
31
|
end
|
@@ -37,16 +39,14 @@ module Epuber
|
|
37
39
|
|
38
40
|
doctypes = []
|
39
41
|
while /(\n|\?>|\A)?(<!DOCTYPE [^>]*>\n*)/ =~ text
|
40
|
-
doctypes <<
|
42
|
+
doctypes << ::Regexp.last_match(2).strip
|
41
43
|
|
42
44
|
match = Regexp.last_match
|
43
45
|
text[match.begin(2)...match.end(2)] = ''
|
44
46
|
end
|
45
47
|
|
46
48
|
before = ([xml_header] + doctypes).compact.join("\n")
|
47
|
-
unless before.empty?
|
48
|
-
before = before + "\n"
|
49
|
-
end
|
49
|
+
before += "\n" unless before.empty?
|
50
50
|
|
51
51
|
parse_options = Nokogiri::XML::ParseOptions::DEFAULT_XML |
|
52
52
|
Nokogiri::XML::ParseOptions::NOERROR | # to silence any errors or warnings printing into console
|
@@ -82,11 +82,10 @@ module Epuber
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def self.xml_document_from_string(text, file_path = nil)
|
85
|
-
xml,
|
85
|
+
xml, = xml_doc_from_str_with_errors(text, file_path)
|
86
86
|
xml
|
87
87
|
end
|
88
88
|
|
89
|
-
|
90
89
|
# Method to add all missing items in XML root
|
91
90
|
#
|
92
91
|
# Required items:
|
@@ -137,10 +136,10 @@ module Epuber
|
|
137
136
|
end
|
138
137
|
|
139
138
|
# https://github.com/IDPF/epubcheck/issues/631
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
139
|
+
return unless epub_version < 3.0
|
140
|
+
|
141
|
+
xhtml_doc.internal_subset&.remove
|
142
|
+
xhtml_doc.create_internal_subset('html', '-//W3C//DTD XHTML 1.1//EN', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd')
|
144
143
|
end
|
145
144
|
|
146
145
|
# Method for adding style sheets with links, method will not add duplicate items
|
@@ -151,7 +150,7 @@ module Epuber
|
|
151
150
|
# @return nil
|
152
151
|
#
|
153
152
|
def self.add_styles(xhtml_doc, styles)
|
154
|
-
head
|
153
|
+
head = xhtml_doc.at_css('html > head')
|
155
154
|
old_links = head.css('link[rel="stylesheet"]').map { |node| node['href'] }
|
156
155
|
|
157
156
|
links_to_add = styles - old_links
|
@@ -169,7 +168,7 @@ module Epuber
|
|
169
168
|
# @return nil
|
170
169
|
#
|
171
170
|
def self.add_scripts(xhtml_doc, scripts)
|
172
|
-
head
|
171
|
+
head = xhtml_doc.at_css('html > head')
|
173
172
|
old_links = head.css('script').map { |node| node['src'] }
|
174
173
|
|
175
174
|
links_to_add = scripts - old_links
|
@@ -195,7 +194,8 @@ module Epuber
|
|
195
194
|
# Method which will resolve path to file from pattern
|
196
195
|
#
|
197
196
|
# @param [String] path pattern or path of the file
|
198
|
-
# @param [Symbol | Array<Symbol>] groups groups of the searching file, could be for example :image when searching
|
197
|
+
# @param [Symbol | Array<Symbol>] groups groups of the searching file, could be for example :image when searching
|
198
|
+
# for file from tag <img>
|
199
199
|
# @param [String] file_path path to file from which is searching for other file
|
200
200
|
# @param [Epuber::Compiler::FileFinder] file_finder finder for searching for files
|
201
201
|
#
|
@@ -233,7 +233,8 @@ module Epuber
|
|
233
233
|
# @param [Nokogiri::XML::Document] xhtml_doc input XML document to work with
|
234
234
|
# @param [String] tag_name CSS selector for tag
|
235
235
|
# @param [String] attribute_name name of attribute
|
236
|
-
# @param [Symbol | Array<Symbol>] groups groups of the searching file, could be for example :image when searching
|
236
|
+
# @param [Symbol | Array<Symbol>] groups groups of the searching file, could be for example :image when searching
|
237
|
+
# for file from tag <img>
|
237
238
|
# @param [String] file_path path to file from which is searching for other file
|
238
239
|
# @param [Epuber::Compiler::FileFinder] file_finder finder for searching for files
|
239
240
|
#
|
@@ -243,22 +244,21 @@ module Epuber
|
|
243
244
|
founded_links = []
|
244
245
|
|
245
246
|
xhtml_doc.css("#{tag_name}[#{attribute_name}]").each do |node|
|
246
|
-
|
247
|
-
|
248
|
-
# @type [String] src
|
247
|
+
src = node[attribute_name]
|
248
|
+
# @type [String] src
|
249
249
|
|
250
|
-
|
250
|
+
next if src.nil?
|
251
|
+
next if src.start_with?('$')
|
251
252
|
|
252
|
-
|
253
|
-
|
253
|
+
target_file = resolved_link_to_file(src, groups, file_path, file_finder)
|
254
|
+
founded_links << target_file
|
254
255
|
|
255
|
-
|
256
|
-
|
257
|
-
|
256
|
+
node[attribute_name] = target_file.to_s
|
257
|
+
rescue UnparseableLinkError, FileFinders::FileNotFoundError, FileFinders::MultipleFilesFoundError => e
|
258
|
+
UI.warning(e.to_s, location: node)
|
258
259
|
|
259
|
-
|
260
|
-
|
261
|
-
end
|
260
|
+
# skip not found files
|
261
|
+
next
|
262
262
|
end
|
263
263
|
|
264
264
|
founded_links
|
@@ -349,7 +349,6 @@ module Epuber
|
|
349
349
|
|
350
350
|
begin
|
351
351
|
new_path = file_resolver.dest_finder.find_file(path, groups: resource_group, context_path: dirname)
|
352
|
-
|
353
352
|
rescue UnparseableLinkError, FileFinders::FileNotFoundError, FileFinders::MultipleFilesFoundError
|
354
353
|
begin
|
355
354
|
new_path = resolved_link_to_file(path, resource_group, dirname, file_resolver.source_finder).to_s
|
@@ -361,8 +360,7 @@ module Epuber
|
|
361
360
|
file.path_type = :manifest
|
362
361
|
file_resolver.add_file(file)
|
363
362
|
|
364
|
-
new_path = FileResolver
|
365
|
-
|
363
|
+
new_path = FileResolver.renamed_file_with_path(new_path)
|
366
364
|
rescue UnparseableLinkError, FileFinders::FileNotFoundError, FileFinders::MultipleFilesFoundError => e
|
367
365
|
UI.warning(e.to_s, location: img)
|
368
366
|
|
@@ -373,6 +371,38 @@ module Epuber
|
|
373
371
|
img[attribute_name] = new_path
|
374
372
|
end
|
375
373
|
end
|
374
|
+
|
375
|
+
# @param [Nokogiri::XML::Document] xhtml_doc input XML document to work with
|
376
|
+
# @return [Array<Nokogiri::XML::Node>] list of nodes with global ids
|
377
|
+
#
|
378
|
+
def self.find_global_ids_nodes(xhtml_doc)
|
379
|
+
xhtml_doc
|
380
|
+
.css('[id^="$"]')
|
381
|
+
end
|
382
|
+
|
383
|
+
# @param [Nokogiri::XML::Document] xhtml_doc input XML document to work with
|
384
|
+
# @return [Array<string>] list of global ids (without dollar signs)
|
385
|
+
#
|
386
|
+
def self.find_global_ids(xhtml_doc)
|
387
|
+
find_global_ids_nodes(xhtml_doc)
|
388
|
+
.map { |node| node['id'][1..-1] }
|
389
|
+
end
|
390
|
+
|
391
|
+
# @param [Nokogiri::XML::Document] xhtml_doc input XML document to work with
|
392
|
+
# @return [Array<Nokogiri::XML::Node>] list of nodes with global links
|
393
|
+
#
|
394
|
+
def self.find_global_links_nodes(xhtml_doc)
|
395
|
+
xhtml_doc
|
396
|
+
.css('[href^="$"]')
|
397
|
+
end
|
398
|
+
|
399
|
+
# @param [Nokogiri::XML::Document] xhtml_doc input XML document to work with
|
400
|
+
# @return [Array<string>] list of global ids (without dollar signs)
|
401
|
+
#
|
402
|
+
def self.find_global_links(xhtml_doc)
|
403
|
+
find_global_links_nodes(xhtml_doc)
|
404
|
+
.map { |node| node['href'][1..-1] }
|
405
|
+
end
|
376
406
|
end
|
377
407
|
end
|
378
408
|
end
|
data/lib/epuber/compiler.rb
CHANGED
@@ -71,22 +71,30 @@ module Epuber
|
|
71
71
|
|
72
72
|
FileUtils.mkdir_p(build_folder)
|
73
73
|
|
74
|
-
puts "
|
74
|
+
UI.puts " #{<<~MSG}"
|
75
|
+
building target #{@target.name.inspect} (build dir: #{Config.instance.pretty_path_from_project(build_folder)})
|
76
|
+
MSG
|
75
77
|
|
76
|
-
file_resolver.add_file(FileTypes::SourceFile.new(Config.instance.pretty_path_from_project(@book.file_path)
|
78
|
+
file_resolver.add_file(FileTypes::SourceFile.new(Config.instance.pretty_path_from_project(@book.file_path)))
|
77
79
|
compilation_context.plugins
|
78
80
|
|
81
|
+
# validate bookspec
|
82
|
+
compilation_context.perform_plugin_things(Checker, :bookspec) do |checker|
|
83
|
+
checker.call(@book, compilation_context)
|
84
|
+
end
|
85
|
+
|
79
86
|
parse_toc_item(@target.root_toc)
|
80
87
|
parse_target_file_requests
|
81
88
|
|
82
89
|
process_all_target_files
|
83
90
|
generate_other_files
|
91
|
+
process_global_ids
|
84
92
|
|
85
93
|
# build folder cleanup
|
86
94
|
remove_unnecessary_files
|
87
95
|
remove_empty_folders
|
88
96
|
|
89
|
-
source_paths = file_resolver.files.select { |a| a.is_a?(FileTypes::SourceFile) }.map
|
97
|
+
source_paths = file_resolver.files.select { |a| a.is_a?(FileTypes::SourceFile) }.map(&:source_path)
|
90
98
|
compilation_context.source_file_database.cleanup(source_paths)
|
91
99
|
compilation_context.source_file_database.update_all_metadata
|
92
100
|
compilation_context.source_file_database.save_to_file
|
@@ -118,7 +126,7 @@ module Epuber
|
|
118
126
|
old_paths = zip_file.instance_eval { @entry_set.entries.map(&:name) }
|
119
127
|
diff = old_paths - new_paths
|
120
128
|
diff.each do |file_to_remove|
|
121
|
-
puts "DEBUG: removing file from result EPUB: #{file_to_remove}" if compilation_context.verbose?
|
129
|
+
UI.puts "DEBUG: removing file from result EPUB: #{file_to_remove}" if compilation_context.verbose?
|
122
130
|
zip_file.remove(file_to_remove)
|
123
131
|
end
|
124
132
|
end
|
@@ -147,7 +155,7 @@ module Epuber
|
|
147
155
|
epub_name += @book.build_version.to_s unless @book.build_version.nil?
|
148
156
|
epub_name += "-#{@target.name}" if @target != @book.default_target
|
149
157
|
epub_name += "-#{configuration_suffix}" unless configuration_suffix.nil?
|
150
|
-
epub_name
|
158
|
+
"#{epub_name}.epub"
|
151
159
|
end
|
152
160
|
|
153
161
|
|
@@ -158,21 +166,25 @@ module Epuber
|
|
158
166
|
def remove_empty_folders
|
159
167
|
Dir.chdir(@file_resolver.destination_path) do
|
160
168
|
Dir.glob('**/*')
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
169
|
+
.select { |d| File.directory?(d) }
|
170
|
+
.select { |d| (Dir.entries(d) - %w[. ..]).empty? }
|
171
|
+
.each do |d|
|
172
|
+
UI.puts "DEBUG: removing empty folder `#{d}`" if compilation_context.verbose?
|
173
|
+
Dir.rmdir(d)
|
174
|
+
end
|
167
175
|
end
|
168
176
|
end
|
169
177
|
|
170
178
|
# @return nil
|
171
179
|
#
|
172
180
|
def remove_unnecessary_files
|
173
|
-
unnecessary_paths = @file_resolver.unneeded_files_in_destination.map
|
181
|
+
unnecessary_paths = @file_resolver.unneeded_files_in_destination.map do |path|
|
182
|
+
File.join(@file_resolver.destination_path, path)
|
183
|
+
end
|
174
184
|
unnecessary_paths.each do |path|
|
175
|
-
|
185
|
+
if compilation_context.verbose?
|
186
|
+
UI.puts "DEBUG: removing unnecessary file: `#{Config.instance.pretty_path_from_project(path)}`"
|
187
|
+
end
|
176
188
|
|
177
189
|
File.delete(path)
|
178
190
|
end
|
@@ -201,11 +213,11 @@ module Epuber
|
|
201
213
|
@file_resolver.add_file(container_xml)
|
202
214
|
process_file(container_xml)
|
203
215
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
216
|
+
return unless @target.epub_version >= 2.0 && @target.epub_version < 3.0
|
217
|
+
|
218
|
+
ibooks_options = FileTypes::IBooksDisplayOptionsFile.new
|
219
|
+
@file_resolver.add_file(ibooks_options)
|
220
|
+
process_file(ibooks_options)
|
209
221
|
end
|
210
222
|
|
211
223
|
# @return nil
|
@@ -239,6 +251,7 @@ module Epuber
|
|
239
251
|
# add missing files to file_resolver
|
240
252
|
paths.each do |path|
|
241
253
|
next if file_resolver.file_with_source_path(path)
|
254
|
+
|
242
255
|
file_resolver.add_file(FileTypes::SourceFile.new(path))
|
243
256
|
end
|
244
257
|
|
@@ -247,7 +260,7 @@ module Epuber
|
|
247
260
|
|
248
261
|
# add all activated plugin files
|
249
262
|
paths += compilation_context.plugins.map do |plugin|
|
250
|
-
plugin.files.map
|
263
|
+
plugin.files.map(&:source_path)
|
251
264
|
end.flatten
|
252
265
|
|
253
266
|
# add dependencies to databases
|
@@ -286,6 +299,40 @@ module Epuber
|
|
286
299
|
end
|
287
300
|
end
|
288
301
|
|
302
|
+
def process_global_ids
|
303
|
+
xhtml_files = @file_resolver.files.select { |file| file.is_a?(FileTypes::XHTMLFile) }
|
304
|
+
global_ids = validate_global_ids(xhtml_files)
|
305
|
+
|
306
|
+
xhtml_files.each do |file|
|
307
|
+
file.process_global_ids(compilation_context, global_ids)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
# Validates duplicity of global ids in all files + returns map of global ids to files
|
312
|
+
#
|
313
|
+
# @param xhtml_files [Array<FileTypes::XHTMLFile>]
|
314
|
+
# @return [Hash<String, FileTypes::XHTMLFile>]
|
315
|
+
#
|
316
|
+
def validate_global_ids(xhtml_files)
|
317
|
+
map = {}
|
318
|
+
xhtml_files.each do |file|
|
319
|
+
file.global_ids.each do |id|
|
320
|
+
if map.key?(id)
|
321
|
+
message = "Duplicate global id `#{id}` in file `#{file.source_path}`."
|
322
|
+
if compilation_context.release_build?
|
323
|
+
UI.error!(message)
|
324
|
+
else
|
325
|
+
UI.warning("#{message} Will fail during release build.")
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
map[id] = file
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
map
|
334
|
+
end
|
335
|
+
|
289
336
|
# @param cmd [String]
|
290
337
|
#
|
291
338
|
# @return [void]
|
data/lib/epuber/config.rb
CHANGED
@@ -60,9 +60,11 @@ module Epuber
|
|
60
60
|
#
|
61
61
|
# @return [Epuber::Book]
|
62
62
|
#
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
attr_writer :bookspec
|
64
|
+
|
65
|
+
# @return [Boolean]
|
66
|
+
#
|
67
|
+
attr_accessor :release_build
|
66
68
|
|
67
69
|
# @return [Epuber::Lockfile]
|
68
70
|
#
|
@@ -122,12 +124,16 @@ module Epuber
|
|
122
124
|
|
123
125
|
def warn_for_outdated_versions!
|
124
126
|
if bookspec_lockfile.epuber_version > Epuber::VERSION
|
125
|
-
UI.warning(
|
127
|
+
UI.warning(<<~MSG.rstrip)
|
128
|
+
Warning: the running version of Epuber is older than the version that created the lockfile. We suggest you upgrade to the latest version of Epuber by running `gem install epuber`.
|
129
|
+
MSG
|
126
130
|
end
|
127
131
|
|
128
|
-
|
129
|
-
|
130
|
-
|
132
|
+
return unless bookspec_lockfile.bade_version && bookspec_lockfile.bade_version > Bade::VERSION
|
133
|
+
|
134
|
+
UI.warning(<<~MSG.rstrip)
|
135
|
+
Warning: the running version of Bade is older than the version that created the lockfile. We suggest you upgrade to the latest version of Bade by running `gem install bade`.
|
136
|
+
MSG
|
131
137
|
end
|
132
138
|
|
133
139
|
def same_version_as_last_run?
|
data/lib/epuber/dsl/attribute.rb
CHANGED
@@ -109,25 +109,25 @@ module Epuber
|
|
109
109
|
# is not specified.
|
110
110
|
#
|
111
111
|
attr_reader :required
|
112
|
-
|
112
|
+
alias required? required
|
113
113
|
|
114
114
|
# @return [Bool] whether the attribute should be specified only on the root specification.
|
115
115
|
#
|
116
116
|
attr_reader :root_only
|
117
|
-
|
117
|
+
alias root_only? root_only
|
118
118
|
|
119
119
|
|
120
120
|
# @return [Bool] whether there should be a singular alias for the attribute writer.
|
121
121
|
#
|
122
122
|
attr_reader :singularize
|
123
|
-
|
123
|
+
alias singularize? singularize
|
124
124
|
|
125
125
|
# @return [Bool] whether the attribute describes file patterns.
|
126
126
|
#
|
127
127
|
# @note This is mostly used by the linter.
|
128
128
|
#
|
129
129
|
attr_reader :file_patterns
|
130
|
-
|
130
|
+
alias file_patterns? file_patterns
|
131
131
|
|
132
132
|
# @return [Bool] defines whether the attribute reader should join the values with the parent.
|
133
133
|
#
|
@@ -184,25 +184,24 @@ module Epuber
|
|
184
184
|
raise StandardError, "Can't set `#{name}` attribute for subspecs (in `#{spec.name}`)."
|
185
185
|
end
|
186
186
|
|
187
|
-
|
188
|
-
value.keys.each do |key|
|
189
|
-
unless allowed_keys.include?(key)
|
190
|
-
raise StandardError, "Unknown key `#{key}` for #{self}. Allowed keys: `#{allowed_keys.inspect}`"
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
187
|
+
return unless keys
|
194
188
|
|
195
189
|
# @return [Array] the flattened list of the allowed keys for the hash of a given specification.
|
196
190
|
#
|
197
|
-
|
191
|
+
allowed_keys = lambda do
|
198
192
|
if keys.is_a?(Hash)
|
199
193
|
keys.keys.concat(keys.values.flatten.compact)
|
200
194
|
else
|
201
195
|
keys
|
202
196
|
end
|
203
197
|
end
|
204
|
-
end
|
205
198
|
|
199
|
+
value.each_key do |key|
|
200
|
+
unless allowed_keys.include?(key)
|
201
|
+
raise StandardError, "Unknown key `#{key}` for #{self}. Allowed keys: `#{allowed_keys.inspect}`"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
206
205
|
|
207
206
|
#---------------------------------------------------------------------#
|
208
207
|
|
@@ -221,15 +220,14 @@ module Epuber
|
|
221
220
|
validate_type(value)
|
222
221
|
rescue StandardError
|
223
222
|
raise if @auto_convert.nil?
|
223
|
+
|
224
224
|
dest_class = @auto_convert[value.class]
|
225
225
|
|
226
226
|
if dest_class.nil?
|
227
227
|
array_keys = @auto_convert.select { |k, _v| k.is_a?(Array) }
|
228
228
|
array_keys_with_type = array_keys.select { |k, _v| k.any? { |klass| value.class <= klass } }
|
229
229
|
|
230
|
-
if array_keys_with_type.count
|
231
|
-
dest_class = array_keys_with_type.values.first
|
232
|
-
end
|
230
|
+
dest_class = array_keys_with_type.values.first if array_keys_with_type.count.positive?
|
233
231
|
end
|
234
232
|
|
235
233
|
if dest_class.respond_to?(:call)
|
@@ -241,7 +239,8 @@ module Epuber
|
|
241
239
|
elsif dest_class.respond_to?(:new)
|
242
240
|
return dest_class.new(value)
|
243
241
|
else
|
244
|
-
raise StandardError,
|
242
|
+
raise StandardError,
|
243
|
+
"Object/class #{dest_class} doesn't support any convert method (#call, .parse or implicit .new)"
|
245
244
|
end
|
246
245
|
end
|
247
246
|
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
3
|
module Epuber
|
5
4
|
module DSL
|
6
5
|
module AttributeSupport
|
@@ -86,8 +85,9 @@ module Epuber
|
|
86
85
|
else
|
87
86
|
begin
|
88
87
|
@attributes_values[key] = attr.converted_value(value)
|
89
|
-
rescue
|
90
|
-
UI.warning("Invalid value `#{value}` for attribute `#{name}`, original error `#{e}`",
|
88
|
+
rescue StandardError => e
|
89
|
+
UI.warning("Invalid value `#{value}` for attribute `#{name}`, original error `#{e}`",
|
90
|
+
location: caller_locations[1])
|
91
91
|
end
|
92
92
|
end
|
93
93
|
end
|