epuber 0.8.0 → 0.9.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.
- checksums.yaml +4 -4
- data/Gemfile +9 -0
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/epuber.gemspec +3 -6
- data/lib/epuber/book/contributor.rb +10 -6
- data/lib/epuber/book/file_request.rb +2 -2
- data/lib/epuber/book/target.rb +10 -10
- data/lib/epuber/book.rb +2 -2
- data/lib/epuber/checker/text_checker.rb +14 -6
- data/lib/epuber/checker_transformer_base.rb +1 -1
- data/lib/epuber/command/build.rb +6 -1
- data/lib/epuber/command/from_file.rb +39 -0
- data/lib/epuber/command/init.rb +11 -9
- data/lib/epuber/command/server.rb +1 -1
- data/lib/epuber/command.rb +1 -0
- data/lib/epuber/compiler/file_database.rb +2 -2
- data/lib/epuber/compiler/file_finders/abstract.rb +3 -3
- data/lib/epuber/compiler/file_resolver.rb +3 -2
- data/lib/epuber/compiler/file_types/abstract_file.rb +1 -3
- data/lib/epuber/compiler/file_types/bade_file.rb +9 -9
- data/lib/epuber/compiler/file_types/css_file.rb +84 -0
- data/lib/epuber/compiler/file_types/source_file.rb +31 -0
- data/lib/epuber/compiler/file_types/stylus_file.rb +4 -3
- data/lib/epuber/compiler/nav_generator.rb +5 -5
- data/lib/epuber/compiler/opf_generator.rb +4 -4
- data/lib/epuber/compiler/xhtml_processor.rb +7 -25
- data/lib/epuber/compiler.rb +12 -7
- data/lib/epuber/config.rb +3 -3
- data/lib/epuber/dsl/attribute.rb +1 -1
- data/lib/epuber/dsl/attribute_support.rb +4 -4
- data/lib/epuber/dsl/object.rb +2 -2
- data/lib/epuber/from_file/bookspec_generator.rb +371 -0
- data/lib/epuber/from_file/encryption_handler.rb +146 -0
- data/lib/epuber/from_file/from_file_executor.rb +140 -0
- data/lib/epuber/from_file/nav_file.rb +163 -0
- data/lib/epuber/from_file/opf_file.rb +219 -0
- data/lib/epuber/plugin.rb +1 -1
- data/lib/epuber/server.rb +17 -17
- data/lib/epuber/transformer/book_transformer.rb +108 -0
- data/lib/epuber/transformer.rb +2 -0
- data/lib/epuber/user_interface.rb +2 -2
- data/lib/epuber/vendor/ruby_templater.rb +3 -3
- data/lib/epuber/vendor/version.rb +3 -3
- data/lib/epuber/version.rb +1 -1
- metadata +40 -59
@@ -5,9 +5,9 @@ require 'epuber-stylus'
|
|
5
5
|
module Epuber
|
6
6
|
class Compiler
|
7
7
|
module FileTypes
|
8
|
-
require_relative '
|
8
|
+
require_relative 'css_file'
|
9
9
|
|
10
|
-
class StylusFile <
|
10
|
+
class StylusFile < CSSFile
|
11
11
|
# @param [Compiler::CompilationContext] compilation_context
|
12
12
|
#
|
13
13
|
def process(compilation_context)
|
@@ -19,7 +19,8 @@ module Epuber
|
|
19
19
|
Stylus.define('__book_title', compilation_context.book.title)
|
20
20
|
Stylus.define('__const', compilation_context.target.constants)
|
21
21
|
|
22
|
-
|
22
|
+
css = Stylus.compile(File.new(abs_source_path))
|
23
|
+
write_compiled(process_css(css, compilation_context))
|
23
24
|
|
24
25
|
update_metadata!
|
25
26
|
end
|
@@ -94,7 +94,7 @@ module Epuber
|
|
94
94
|
@xml.ncx(nav_namespaces, version: '2005-1') do
|
95
95
|
# head
|
96
96
|
@xml.head do
|
97
|
-
@xml.meta(name: 'dtb:uid', content:
|
97
|
+
@xml.meta(name: 'dtb:uid', content: @target.identifier || "urn:isbn:#{@target.isbn}")
|
98
98
|
end
|
99
99
|
|
100
100
|
# title
|
@@ -111,7 +111,7 @@ module Epuber
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
# @param
|
114
|
+
# @param [Array<Epuber::Book::TocItem>] toc_items
|
115
115
|
#
|
116
116
|
def visit_toc_items(toc_items)
|
117
117
|
iterate_lambda = lambda do
|
@@ -133,7 +133,7 @@ module Epuber
|
|
133
133
|
toc_items.any? { |a| a.title || contains_item_with_title(a.sub_items) }
|
134
134
|
end
|
135
135
|
|
136
|
-
# @param
|
136
|
+
# @param [Epuber::Book::TocItem] toc_item
|
137
137
|
#
|
138
138
|
def visit_toc_item(toc_item)
|
139
139
|
result_file_path = pretty_path_for_toc_item(toc_item)
|
@@ -165,7 +165,7 @@ module Epuber
|
|
165
165
|
|
166
166
|
# --------------- landmarks -----------------------------
|
167
167
|
|
168
|
-
# @param
|
168
|
+
# @param [Array<Epuber::Book::TocItem>] toc_items
|
169
169
|
#
|
170
170
|
def landmarks_visit_toc_items(toc_items)
|
171
171
|
toc_items.each do |child_item|
|
@@ -173,7 +173,7 @@ module Epuber
|
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
-
# @param
|
176
|
+
# @param [Epuber::Book::TocItem] toc_item
|
177
177
|
#
|
178
178
|
def landmarks_visit_toc_item(toc_item)
|
179
179
|
landmarks = toc_item.landmarks
|
@@ -217,7 +217,7 @@ module Epuber
|
|
217
217
|
end
|
218
218
|
end
|
219
219
|
|
220
|
-
# @param
|
220
|
+
# @param [Array<Epuber::Book::TocItem>] toc_items
|
221
221
|
#
|
222
222
|
# @return nil
|
223
223
|
#
|
@@ -227,7 +227,7 @@ module Epuber
|
|
227
227
|
end
|
228
228
|
end
|
229
229
|
|
230
|
-
# @param
|
230
|
+
# @param [Epuber::Book::TocItem] toc_item
|
231
231
|
#
|
232
232
|
# @return nil
|
233
233
|
#
|
@@ -251,7 +251,7 @@ module Epuber
|
|
251
251
|
|
252
252
|
# Creates id from file path
|
253
253
|
#
|
254
|
-
# @param
|
254
|
+
# @param [String] path
|
255
255
|
#
|
256
256
|
# @return [String]
|
257
257
|
#
|
@@ -263,7 +263,7 @@ module Epuber
|
|
263
263
|
|
264
264
|
# Creates proper mime-type for file
|
265
265
|
#
|
266
|
-
# @param
|
266
|
+
# @param [Epuber::Compiler::FileTypes::AbstractFile | String] file
|
267
267
|
#
|
268
268
|
# @return [String]
|
269
269
|
#
|
@@ -50,7 +50,8 @@ module Epuber
|
|
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
|
53
|
-
Nokogiri::XML::ParseOptions::NOWARNING
|
53
|
+
Nokogiri::XML::ParseOptions::NOWARNING |
|
54
|
+
Nokogiri::XML::ParseOptions::NOENT
|
54
55
|
|
55
56
|
doc = Nokogiri::XML("#{before}<root>#{text}</root>", file_path, nil, parse_options)
|
56
57
|
text_for_errors = before + text
|
@@ -341,34 +342,15 @@ module Epuber
|
|
341
342
|
end
|
342
343
|
|
343
344
|
def self.resolve_resources_in(node_css_query, attribute_name, resource_group, xhtml_doc, file_path, file_resolver)
|
344
|
-
dirname = File.dirname(file_path)
|
345
|
-
|
346
345
|
xhtml_doc.css(node_css_query).each do |img|
|
347
346
|
path = img[attribute_name]
|
348
347
|
next if path.nil?
|
349
348
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
pkg_abs_path = File.expand_path(new_path, dirname).unicode_normalize
|
356
|
-
pkg_new_path = Pathname.new(pkg_abs_path).relative_path_from(Pathname.new(file_resolver.source_path)).to_s
|
357
|
-
|
358
|
-
file_class = FileResolver.file_class_for(File.extname(new_path))
|
359
|
-
file = file_class.new(pkg_new_path)
|
360
|
-
file.path_type = :manifest
|
361
|
-
file_resolver.add_file(file)
|
362
|
-
|
363
|
-
new_path = FileResolver.renamed_file_with_path(new_path)
|
364
|
-
rescue UnparseableLinkError, FileFinders::FileNotFoundError, FileFinders::MultipleFilesFoundError => e
|
365
|
-
UI.warning(e.to_s, location: img)
|
366
|
-
|
367
|
-
next
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
img[attribute_name] = new_path
|
349
|
+
new_path = Compiler::FileTypes::SourceFile.resolve_relative_file(file_path,
|
350
|
+
path,
|
351
|
+
file_resolver,
|
352
|
+
group: resource_group)
|
353
|
+
img[attribute_name] = new_path if new_path
|
372
354
|
end
|
373
355
|
end
|
374
356
|
|
data/lib/epuber/compiler.rb
CHANGED
@@ -39,8 +39,8 @@ module Epuber
|
|
39
39
|
#
|
40
40
|
attr_reader :compilation_context
|
41
41
|
|
42
|
-
# @param
|
43
|
-
# @param
|
42
|
+
# @param [Epuber::Book::Book] book
|
43
|
+
# @param [Epuber::Book::Target] target
|
44
44
|
#
|
45
45
|
def initialize(book, target)
|
46
46
|
@book = book
|
@@ -50,7 +50,7 @@ module Epuber
|
|
50
50
|
|
51
51
|
# Compile target to build folder
|
52
52
|
#
|
53
|
-
# @param
|
53
|
+
# @param [String] build_folder path to folder, where will be stored all compiled files
|
54
54
|
# @param [Bool] check should run non-release checkers
|
55
55
|
# @param [Bool] write should perform transformations of source files and write them back
|
56
56
|
# @param [Bool] release this is release build
|
@@ -88,6 +88,11 @@ module Epuber
|
|
88
88
|
|
89
89
|
process_all_target_files
|
90
90
|
generate_other_files
|
91
|
+
|
92
|
+
compilation_context.perform_plugin_things(Transformer, :after_all_text_files) do |transformer|
|
93
|
+
transformer.call(@book, compilation_context)
|
94
|
+
end
|
95
|
+
|
91
96
|
process_global_ids
|
92
97
|
|
93
98
|
# build folder cleanup
|
@@ -109,7 +114,7 @@ module Epuber
|
|
109
114
|
|
110
115
|
# Archives current target files to epub
|
111
116
|
#
|
112
|
-
# @param
|
117
|
+
# @param [String] path path to created archive
|
113
118
|
#
|
114
119
|
# @return [String] path
|
115
120
|
#
|
@@ -285,7 +290,7 @@ module Epuber
|
|
285
290
|
UI.processing_files_done
|
286
291
|
end
|
287
292
|
|
288
|
-
# @param
|
293
|
+
# @param [Epuber::Book::TocItem] toc_item
|
289
294
|
#
|
290
295
|
def parse_toc_item(toc_item)
|
291
296
|
unless toc_item.file_request.nil?
|
@@ -310,7 +315,7 @@ module Epuber
|
|
310
315
|
|
311
316
|
# Validates duplicity of global ids in all files + returns map of global ids to files
|
312
317
|
#
|
313
|
-
# @param
|
318
|
+
# @param [Array<FileTypes::XHTMLFile>] xhtml_files
|
314
319
|
# @return [Hash<String, FileTypes::XHTMLFile>]
|
315
320
|
#
|
316
321
|
def validate_global_ids(xhtml_files)
|
@@ -333,7 +338,7 @@ module Epuber
|
|
333
338
|
map
|
334
339
|
end
|
335
340
|
|
336
|
-
# @param
|
341
|
+
# @param [String] cmd
|
337
342
|
#
|
338
343
|
# @return [void]
|
339
344
|
#
|
data/lib/epuber/config.rb
CHANGED
@@ -14,7 +14,7 @@ module Epuber
|
|
14
14
|
@project_path ||= Dir.pwd.unicode_normalize
|
15
15
|
end
|
16
16
|
|
17
|
-
# @param
|
17
|
+
# @param [String] of_file absolute path to file
|
18
18
|
#
|
19
19
|
# @return [String] relative path to file from root of project
|
20
20
|
#
|
@@ -84,7 +84,7 @@ module Epuber
|
|
84
84
|
bookspec_lockfile.write_to_file
|
85
85
|
end
|
86
86
|
|
87
|
-
# @param
|
87
|
+
# @param [Epuber::Book::Target] target
|
88
88
|
#
|
89
89
|
# @return [String]
|
90
90
|
#
|
@@ -92,7 +92,7 @@ module Epuber
|
|
92
92
|
File.join(working_path, 'build', target.name.to_s)
|
93
93
|
end
|
94
94
|
|
95
|
-
# @param
|
95
|
+
# @param [Epuber::Book::Target] target
|
96
96
|
#
|
97
97
|
# @return [String]
|
98
98
|
#
|
data/lib/epuber/dsl/attribute.rb
CHANGED
@@ -9,8 +9,8 @@ module Epuber
|
|
9
9
|
# attribute :name
|
10
10
|
# attribute :title, required: true, inherited: true
|
11
11
|
#
|
12
|
-
# @param
|
13
|
-
# @param
|
12
|
+
# @param [Symbol] name attribute name
|
13
|
+
# @param [Hash] options
|
14
14
|
#
|
15
15
|
# @see Attribute
|
16
16
|
#
|
@@ -44,8 +44,8 @@ module Epuber
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
# @param
|
48
|
-
# @param
|
47
|
+
# @param [Symbol] name
|
48
|
+
# @param [Epuber::DSL::Attribute] attr
|
49
49
|
#
|
50
50
|
# @return nil
|
51
51
|
#
|
data/lib/epuber/dsl/object.rb
CHANGED
@@ -58,7 +58,7 @@ module Epuber
|
|
58
58
|
|
59
59
|
# Creates new instance by parsing ruby code from file
|
60
60
|
#
|
61
|
-
# @param
|
61
|
+
# @param [String] file_path
|
62
62
|
#
|
63
63
|
# @return [Self]
|
64
64
|
#
|
@@ -68,7 +68,7 @@ module Epuber
|
|
68
68
|
|
69
69
|
# Creates new instance by parsing ruby code from string
|
70
70
|
#
|
71
|
-
# @param
|
71
|
+
# @param [String] string
|
72
72
|
#
|
73
73
|
# @return [Self]
|
74
74
|
#
|
@@ -0,0 +1,371 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Epuber
|
6
|
+
class BookspecGenerator
|
7
|
+
class TocItem
|
8
|
+
# @return [String]
|
9
|
+
#
|
10
|
+
attr_accessor :href
|
11
|
+
|
12
|
+
# @return [String, nil]
|
13
|
+
#
|
14
|
+
attr_accessor :title
|
15
|
+
|
16
|
+
# @return [Array<TocItem>]
|
17
|
+
#
|
18
|
+
attr_accessor :children
|
19
|
+
|
20
|
+
# @return [Array<Symbol>]
|
21
|
+
#
|
22
|
+
attr_accessor :landmarks
|
23
|
+
|
24
|
+
def initialize(href, title = nil, landmarks = [], children = [])
|
25
|
+
@href = href
|
26
|
+
@title = title
|
27
|
+
@landmarks = landmarks
|
28
|
+
@children = children
|
29
|
+
end
|
30
|
+
|
31
|
+
def attribs
|
32
|
+
[href.inspect, title&.inspect, *landmarks.map(&:inspect)].compact.join(', ')
|
33
|
+
end
|
34
|
+
|
35
|
+
def ==(other)
|
36
|
+
other.is_a?(TocItem) &&
|
37
|
+
href == other.href &&
|
38
|
+
title == other.title &&
|
39
|
+
landmarks == other.landmarks &&
|
40
|
+
children == other.children
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s(level = 0)
|
44
|
+
indent = ' ' * level
|
45
|
+
children_str = children.map { |c| c.to_s(level + 2) }.join("\n")
|
46
|
+
%(#{indent}#{href.inspect} #{title.inspect} #{landmarks.inspect}\n#{children_str})
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
%(#<#{self.class.name} #{self}>)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param [Epuber::OpfFile] opf
|
55
|
+
# @param [Epuber::NavFile, nil] nav
|
56
|
+
#
|
57
|
+
def initialize(opf, nav)
|
58
|
+
@opf = opf
|
59
|
+
@nav = nav
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [String]
|
63
|
+
#
|
64
|
+
def generate_bookspec
|
65
|
+
@indent = 0
|
66
|
+
@bookspec = []
|
67
|
+
|
68
|
+
add_code('Epuber::Book.new do |book|', after: 'end') do
|
69
|
+
generate_titles
|
70
|
+
generate_authors
|
71
|
+
add_empty_line
|
72
|
+
generate_id
|
73
|
+
generate_language
|
74
|
+
generate_published
|
75
|
+
generate_publisher
|
76
|
+
add_empty_line
|
77
|
+
generate_cover
|
78
|
+
add_empty_line
|
79
|
+
generate_toc
|
80
|
+
end
|
81
|
+
add_empty_line
|
82
|
+
|
83
|
+
@bookspec.join("\n")
|
84
|
+
end
|
85
|
+
|
86
|
+
# @return [void]
|
87
|
+
#
|
88
|
+
def generate_titles
|
89
|
+
titles = @opf.metadata.css('title')
|
90
|
+
titles.each do |title|
|
91
|
+
is_main = titles.count == 1
|
92
|
+
|
93
|
+
id = title['id']
|
94
|
+
is_main = @opf.find_refines(id, 'title-type') == 'main' if id && !is_main
|
95
|
+
|
96
|
+
add_comment('alternate title found from original EPUB file (Epuber supports only one title)') unless is_main
|
97
|
+
add_setting_property(:title, title.text.inspect, commented: !is_main)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# @return [void]
|
102
|
+
#
|
103
|
+
def generate_authors
|
104
|
+
authors = @opf.metadata.css('creator')
|
105
|
+
if authors.empty?
|
106
|
+
add_setting_property(:author, nil)
|
107
|
+
elsif authors.count == 1
|
108
|
+
add_setting_property(:author, format_author(authors.first))
|
109
|
+
else
|
110
|
+
add_setting_property(:authors, authors.map { |auth| format_author(auth) })
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# @return [String]
|
115
|
+
#
|
116
|
+
def format_author(author_node)
|
117
|
+
name = author_node.text.strip
|
118
|
+
id = author_node['id']
|
119
|
+
|
120
|
+
if id
|
121
|
+
role = @opf.find_refines(id, 'role')
|
122
|
+
file_as = @opf.find_refines(id, 'file-as')
|
123
|
+
end
|
124
|
+
|
125
|
+
role ||= author_node['opf:role']
|
126
|
+
file_as ||= author_node['opf:file-as']
|
127
|
+
|
128
|
+
role_is_default = role.nil? || role == 'aut'
|
129
|
+
file_as_is_default = file_as.nil? || contributor_file_as_eq?(Book::Contributor.from_obj(name).file_as, file_as)
|
130
|
+
|
131
|
+
if role_is_default && file_as_is_default
|
132
|
+
name.inspect
|
133
|
+
elsif role_is_default && !file_as_is_default
|
134
|
+
%({ pretty_name: #{name.inspect}, file_as: #{file_as.inspect} })
|
135
|
+
elsif !role_is_default && file_as_is_default
|
136
|
+
%({ name: #{name.inspect}, role: #{role.inspect} })
|
137
|
+
else
|
138
|
+
%({ pretty_name: #{name.inspect}, file_as: #{file_as.inspect}, role: #{role.inspect} })
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# @return [void]
|
143
|
+
#
|
144
|
+
def generate_id
|
145
|
+
nodes = @opf.metadata.css('identifier')
|
146
|
+
|
147
|
+
nodes.each do |id_node|
|
148
|
+
value = id_node.text.strip
|
149
|
+
|
150
|
+
is_main = @opf.package['unique-identifier'] == id_node['id']
|
151
|
+
is_isbn = value.start_with?('urn:isbn:')
|
152
|
+
value = value.sub(/^urn:isbn:/, '').strip if is_isbn
|
153
|
+
key = is_isbn ? :isbn : :identifier
|
154
|
+
|
155
|
+
if is_main
|
156
|
+
add_setting_property(key, value.inspect)
|
157
|
+
else
|
158
|
+
add_comment('alternate identifier found from original EPUB file (Epuber supports only one identifier)')
|
159
|
+
add_setting_property(key, value.inspect, commented: true)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# @return [void]
|
165
|
+
#
|
166
|
+
def generate_language
|
167
|
+
language = @opf.metadata.at_css('language')
|
168
|
+
add_setting_property(:language, language.text.strip.inspect) if language
|
169
|
+
end
|
170
|
+
|
171
|
+
# @return [void]
|
172
|
+
#
|
173
|
+
def generate_published
|
174
|
+
published = @opf.metadata.at_css('date')
|
175
|
+
add_setting_property(:published, published.text.strip.inspect) if published
|
176
|
+
end
|
177
|
+
|
178
|
+
# @return [void]
|
179
|
+
#
|
180
|
+
def generate_publisher
|
181
|
+
publisher = @opf.metadata.at_css('publisher')
|
182
|
+
add_setting_property(:publisher, publisher.text.strip.inspect) if publisher
|
183
|
+
end
|
184
|
+
|
185
|
+
# @return [void]
|
186
|
+
#
|
187
|
+
def generate_cover
|
188
|
+
cover_property = Compiler::OPFGenerator::PROPERTIES_MAP[:cover_image]
|
189
|
+
|
190
|
+
cover_id = @opf.manifest_items.find { |_, item| item.properties&.include?(cover_property) }&.last&.id
|
191
|
+
cover_id ||= @opf.metadata.at_css('meta[name="cover"]')&.[]('content')
|
192
|
+
cover = @opf.manifest_file_by_id(cover_id) if cover_id
|
193
|
+
return unless cover
|
194
|
+
|
195
|
+
href = cover.href.sub(/#{Regexp.escape(File.extname(cover.href))}$/, '')
|
196
|
+
add_setting_property(:cover_image, href.inspect)
|
197
|
+
end
|
198
|
+
|
199
|
+
# @return [void]
|
200
|
+
#
|
201
|
+
def generate_toc
|
202
|
+
items = calculate_toc_items
|
203
|
+
|
204
|
+
render_toc_item = lambda do |item|
|
205
|
+
if item.children.empty?
|
206
|
+
add_code(%(toc.file #{item.attribs}))
|
207
|
+
else
|
208
|
+
add_code(%(toc.file #{item.attribs} do), after: 'end') do
|
209
|
+
item.children.each do |child|
|
210
|
+
render_toc_item.call(child)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
add_code('book.toc do |toc, target|', after: 'end') do
|
217
|
+
items.each do |toc_item|
|
218
|
+
render_toc_item.call(toc_item)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
# Add code to final file. When block is given, it will be indented.
|
226
|
+
#
|
227
|
+
# @param [String] code code to print into final file
|
228
|
+
# @param [Boolean] commented should be code commented?
|
229
|
+
# @param [String, nil] after code to print after this code
|
230
|
+
#
|
231
|
+
# @return [void]
|
232
|
+
#
|
233
|
+
def add_code(code, commented: false, after: nil)
|
234
|
+
indent_str = ' ' * @indent
|
235
|
+
comment_prefix = commented ? '# ' : ''
|
236
|
+
|
237
|
+
@bookspec << %(#{indent_str}#{comment_prefix}#{code})
|
238
|
+
|
239
|
+
if block_given?
|
240
|
+
increase_indent
|
241
|
+
yield
|
242
|
+
decrease_indent
|
243
|
+
end
|
244
|
+
|
245
|
+
add_code(after, commented: commented) if after
|
246
|
+
end
|
247
|
+
|
248
|
+
def add_setting_property(name, value, commented: false)
|
249
|
+
if value.is_a?(Array)
|
250
|
+
add_code(%(book.#{name} = [), commented: commented, after: ']') do
|
251
|
+
value.each do |v|
|
252
|
+
add_code(%(#{v},), commented: commented)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
else
|
256
|
+
add_code(%(book.#{name} = #{value}), commented: commented)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def add_comment(text)
|
261
|
+
add_code(text, commented: true)
|
262
|
+
end
|
263
|
+
|
264
|
+
def add_empty_line
|
265
|
+
return if @bookspec.last == ''
|
266
|
+
|
267
|
+
@bookspec << ''
|
268
|
+
end
|
269
|
+
|
270
|
+
def increase_indent
|
271
|
+
@indent += 2
|
272
|
+
end
|
273
|
+
|
274
|
+
def decrease_indent
|
275
|
+
@indent -= 2
|
276
|
+
@indent = 0 if @indent.negative?
|
277
|
+
end
|
278
|
+
|
279
|
+
# Compares two contributors by file_as, it will return true if file_as is same even when case is different
|
280
|
+
#
|
281
|
+
# @param [String] file_as_a
|
282
|
+
# @param [String] file_as_b
|
283
|
+
#
|
284
|
+
# @return [Boolean]
|
285
|
+
#
|
286
|
+
def contributor_file_as_eq?(file_as_a, file_as_b)
|
287
|
+
file_as_a == file_as_b || file_as_a.mb_chars.downcase == file_as_b.mb_chars.downcase
|
288
|
+
end
|
289
|
+
|
290
|
+
# @param [String] href
|
291
|
+
#
|
292
|
+
# @return [Array<Symbol>]
|
293
|
+
#
|
294
|
+
def landmark_for_href(href)
|
295
|
+
landmarks = @nav&.landmarks
|
296
|
+
landmark_map = NavFile::LANDMARKS_MAP unless landmarks.nil?
|
297
|
+
|
298
|
+
if landmarks.nil?
|
299
|
+
landmarks = @opf.guide_items
|
300
|
+
landmark_map = OpfFile::LANDMARKS_MAP
|
301
|
+
end
|
302
|
+
|
303
|
+
found = landmarks.select { |l| l.href == href }
|
304
|
+
.map(&:type)
|
305
|
+
.compact
|
306
|
+
.map { |t| landmark_map[t] }
|
307
|
+
.compact
|
308
|
+
|
309
|
+
return found unless found.empty?
|
310
|
+
|
311
|
+
# try to find by href without fragment
|
312
|
+
if href.include?('#')
|
313
|
+
href = href.split('#').first
|
314
|
+
return landmark_for_href(href)
|
315
|
+
end
|
316
|
+
|
317
|
+
[]
|
318
|
+
end
|
319
|
+
|
320
|
+
# @return [Array<Epuber::BookspecGenerator::TocItem>]
|
321
|
+
#
|
322
|
+
def calculate_toc_items
|
323
|
+
spine_items = @opf.spine_items
|
324
|
+
idrefs = spine_items.map(&:idref)
|
325
|
+
landmarks = Set.new
|
326
|
+
|
327
|
+
# @param [ManifestItem, nil] manifest_item
|
328
|
+
# @param [NavItem, nil] toc_item
|
329
|
+
#
|
330
|
+
# @return [Array<Epuber::BookspecGenerator::TocItem>]
|
331
|
+
#
|
332
|
+
render_toc_item = lambda do |manifest_item, toc_item|
|
333
|
+
# ignore this item when it was already rendered
|
334
|
+
next nil if manifest_item && !idrefs.include?(manifest_item.id)
|
335
|
+
|
336
|
+
manifest_item ||= @opf.manifest_file_by_href(toc_item.href)
|
337
|
+
|
338
|
+
href = toc_item&.href || manifest_item.href
|
339
|
+
toc_item ||= @nav&.find_by_href(href) || @nav&.find_by_href(href, ignore_fragment: true)
|
340
|
+
href = toc_item&.href || manifest_item.href
|
341
|
+
|
342
|
+
href_output = href.sub(/\.x?html$/, '')
|
343
|
+
.sub(/\.x?html#/, '#')
|
344
|
+
|
345
|
+
landmarks_for_this = landmark_for_href(href)
|
346
|
+
unless landmarks_for_this.empty?
|
347
|
+
diff = Set.new(landmarks_for_this) - landmarks
|
348
|
+
landmarks += diff
|
349
|
+
|
350
|
+
landmarks_for_this = diff.to_a
|
351
|
+
end
|
352
|
+
|
353
|
+
item = TocItem.new(href_output, toc_item&.title, landmarks_for_this)
|
354
|
+
item.children = toc_item&.children&.map do |child|
|
355
|
+
render_toc_item.call(nil, child)
|
356
|
+
end || []
|
357
|
+
|
358
|
+
idrefs.delete(manifest_item.id) if manifest_item
|
359
|
+
|
360
|
+
item
|
361
|
+
end
|
362
|
+
|
363
|
+
spine_items.map do |itemref|
|
364
|
+
idref = itemref.idref
|
365
|
+
next unless idref
|
366
|
+
|
367
|
+
render_toc_item.call(@opf.manifest_file_by_id(idref), nil)
|
368
|
+
end.compact
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|