epuber 0.7.4 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -2
  3. data/LICENSE.txt +1 -1
  4. data/README.md +4 -3
  5. data/epuber.gemspec +11 -16
  6. data/lib/epuber/book/contributor.rb +10 -7
  7. data/lib/epuber/book/file_request.rb +3 -3
  8. data/lib/epuber/book/target.rb +30 -33
  9. data/lib/epuber/book/toc_item.rb +2 -4
  10. data/lib/epuber/book.rb +21 -21
  11. data/lib/epuber/checker/bookspec_checker.rb +26 -0
  12. data/lib/epuber/checker/text_checker.rb +16 -7
  13. data/lib/epuber/checker.rb +16 -2
  14. data/lib/epuber/checker_transformer_base.rb +3 -6
  15. data/lib/epuber/command/build.rb +40 -25
  16. data/lib/epuber/command/from_file.rb +39 -0
  17. data/lib/epuber/command/init.rb +34 -32
  18. data/lib/epuber/command/server.rb +3 -3
  19. data/lib/epuber/command.rb +18 -20
  20. data/lib/epuber/compiler/compilation_context.rb +10 -8
  21. data/lib/epuber/compiler/file_database.rb +2 -4
  22. data/lib/epuber/compiler/file_finders/abstract.rb +36 -26
  23. data/lib/epuber/compiler/file_finders/imaginary.rb +40 -35
  24. data/lib/epuber/compiler/file_resolver.rb +79 -89
  25. data/lib/epuber/compiler/file_stat.rb +4 -4
  26. data/lib/epuber/compiler/file_types/abstract_file.rb +4 -7
  27. data/lib/epuber/compiler/file_types/bade_file.rb +20 -15
  28. data/lib/epuber/compiler/file_types/coffee_script_file.rb +1 -1
  29. data/lib/epuber/compiler/file_types/css_file.rb +103 -0
  30. data/lib/epuber/compiler/file_types/generated_file.rb +1 -1
  31. data/lib/epuber/compiler/file_types/image_file.rb +4 -2
  32. data/lib/epuber/compiler/file_types/nav_file.rb +0 -1
  33. data/lib/epuber/compiler/file_types/opf_file.rb +0 -1
  34. data/lib/epuber/compiler/file_types/source_file.rb +8 -3
  35. data/lib/epuber/compiler/file_types/stylus_file.rb +4 -3
  36. data/lib/epuber/compiler/file_types/xhtml_file.rb +67 -13
  37. data/lib/epuber/compiler/generator.rb +1 -2
  38. data/lib/epuber/compiler/meta_inf_generator.rb +1 -1
  39. data/lib/epuber/compiler/nav_generator.rb +10 -11
  40. data/lib/epuber/compiler/opf_generator.rb +26 -27
  41. data/lib/epuber/compiler/problem.rb +12 -21
  42. data/lib/epuber/compiler/xhtml_processor.rb +63 -32
  43. data/lib/epuber/compiler.rb +77 -25
  44. data/lib/epuber/config.rb +16 -10
  45. data/lib/epuber/dsl/attribute.rb +17 -18
  46. data/lib/epuber/dsl/attribute_support.rb +7 -7
  47. data/lib/epuber/dsl/object.rb +19 -17
  48. data/lib/epuber/dsl/tree_object.rb +2 -3
  49. data/lib/epuber/epubcheck.rb +15 -0
  50. data/lib/epuber/from_file/bookspec_generator.rb +371 -0
  51. data/lib/epuber/from_file/encryption_handler.rb +146 -0
  52. data/lib/epuber/from_file/from_file_executor.rb +140 -0
  53. data/lib/epuber/from_file/nav_file.rb +163 -0
  54. data/lib/epuber/from_file/opf_file.rb +219 -0
  55. data/lib/epuber/helper.rb +0 -1
  56. data/lib/epuber/lockfile.rb +7 -9
  57. data/lib/epuber/plugin.rb +2 -3
  58. data/lib/epuber/ruby_extensions/match_data.rb +1 -1
  59. data/lib/epuber/ruby_extensions/thread.rb +1 -0
  60. data/lib/epuber/server/base.styl +0 -1
  61. data/lib/epuber/server/basic.styl +1 -30
  62. data/lib/epuber/server/handlers.rb +1 -1
  63. data/lib/epuber/server.rb +81 -80
  64. data/lib/epuber/third_party/bower.rb +5 -5
  65. data/lib/epuber/transformer/book_transformer.rb +108 -0
  66. data/lib/epuber/transformer/text_transformer.rb +4 -2
  67. data/lib/epuber/transformer.rb +4 -2
  68. data/lib/epuber/user_interface.rb +49 -38
  69. data/lib/epuber/vendor/hash_binding.rb +9 -2
  70. data/lib/epuber/vendor/ruby_templater.rb +4 -8
  71. data/lib/epuber/vendor/version.rb +12 -12
  72. data/lib/epuber/version.rb +1 -1
  73. metadata +79 -100
  74. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Bold.ttf +0 -0
  75. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-BoldItalic.ttf +0 -0
  76. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Italic.ttf +0 -0
  77. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Regular.ttf +0 -0
@@ -11,6 +11,8 @@ module Epuber
11
11
  #
12
12
  attr_accessor :entries
13
13
 
14
+ # @return [String]
15
+ #
14
16
  attr_reader :name
15
17
 
16
18
  def initialize(name)
@@ -32,8 +34,12 @@ module Epuber
32
34
  end
33
35
 
34
36
  class FileEntry
37
+ # @return [String]
38
+ #
35
39
  attr_reader :name
36
40
 
41
+ # @return [String]
42
+ #
37
43
  attr_reader :absolute_path
38
44
 
39
45
  def initialize(name, absolute_path)
@@ -42,7 +48,7 @@ module Epuber
42
48
  end
43
49
 
44
50
  def ==(other)
45
- other.is_a?(FileEntry) ? name == other.name : name == other.to_s
51
+ name == (other.is_a?(FileEntry) ? other.name : other.to_s)
46
52
  end
47
53
  end
48
54
 
@@ -83,14 +89,11 @@ module Epuber
83
89
  make_dir_p(path)[file_name] = FileEntry.new(file_name, file_path)
84
90
  end
85
91
 
86
-
87
92
  def __core_find_files_from_pattern(pattern)
88
93
  parts = self.class.path_parts(pattern)
89
94
  found_entries = find_recurser(root, parts).flatten
90
95
  file_entries = found_entries.reject { |entry| entry.is_a?(DirEntry) }
91
- file_entries.map do |item|
92
- item.absolute_path
93
- end
96
+ file_entries.map(&:absolute_path)
94
97
  end
95
98
 
96
99
  def __core_file?(path)
@@ -104,12 +107,14 @@ module Epuber
104
107
  current.is_a?(FileEntry)
105
108
  end
106
109
 
107
- private
108
-
109
- def self.path_parts(path)
110
- path.split(File::SEPARATOR).reject(&:empty?)
110
+ class << self
111
+ def path_parts(path)
112
+ path.split(File::SEPARATOR).reject(&:empty?)
113
+ end
111
114
  end
112
115
 
116
+ private
117
+
113
118
  def find_recurser(dir, parts)
114
119
  return [] unless dir.respond_to? :[]
115
120
 
@@ -117,25 +122,25 @@ module Epuber
117
122
  return [] if pattern.nil?
118
123
 
119
124
  matches = case pattern
120
- when '**'
121
- case parts
122
- when ['*']
123
- parts = [] # end recursion
124
- directories_under(dir).map do |d|
125
- d.entries.select do |f|
126
- (f.is_a?(FileEntry) || f.is_a?(DirEntry)) &&
127
- f.name.match(/\A(?!\.)/)
128
- end
129
- end.flatten.uniq
130
- when []
131
- parts = [] # end recursion
132
- dir.entries.values.flatten.uniq
133
- else
134
- directories_under(dir)
135
- end
125
+ when '**'
126
+ case parts
127
+ when ['*']
128
+ parts = [] # end recursion
129
+ directories_under(dir).map do |d|
130
+ d.entries.select do |f|
131
+ (f.is_a?(FileEntry) || f.is_a?(DirEntry)) &&
132
+ f.name.match(/\A(?!\.)/)
133
+ end
134
+ end.flatten.uniq
135
+ when []
136
+ parts = [] # end recursion
137
+ dir.entries.values.flatten.uniq
136
138
  else
137
- regex_body = pattern_to_regex(pattern)
138
- dir.entries.reject { |k, _v| /\A#{regex_body}\Z/ !~ k }.values
139
+ directories_under(dir)
140
+ end
141
+ else
142
+ regex_body = pattern_to_regex(pattern)
143
+ dir.entries.select { |k, _v| /\A#{regex_body}\Z/ =~ k }.values
139
144
  end
140
145
 
141
146
  if parts.empty? # we're done recursing
@@ -156,14 +161,14 @@ module Epuber
156
161
 
157
162
  def pattern_to_regex(pattern)
158
163
  pattern.gsub('.', '\.')
159
- .gsub('?', '.')
160
- .gsub('*', '.*')
161
- .gsub('(', '\(')
162
- .gsub(')', '\)')
163
- .gsub(/\{(.*?)\}/) do
164
- "(#{Regexp.last_match[1].gsub(',', '|')})"
165
- end
166
- .gsub(/\A\./, '(?!\.).')
164
+ .gsub('?', '.')
165
+ .gsub('*', '.*')
166
+ .gsub('(', '\(')
167
+ .gsub(')', '\)')
168
+ .gsub(/\{(.*?)\}/) do
169
+ "(#{Regexp.last_match[1].gsub(',', '|')})"
170
+ end
171
+ .gsub(/\A\./, '(?!\.).')
167
172
  end
168
173
  end
169
174
  end
@@ -20,12 +20,12 @@ module Epuber
20
20
  require_relative 'file_types/container_xml_file'
21
21
  require_relative 'file_types/ibooks_display_options_file'
22
22
  require_relative 'file_types/coffee_script_file'
23
-
23
+ require_relative 'file_types/css_file'
24
24
 
25
25
  class FileResolver
26
26
  class ResolveError < StandardError; end
27
27
 
28
- PATH_TYPES = [:spine, :manifest, :package, nil]
28
+ PATH_TYPES = [:spine, :manifest, :package, nil].freeze
29
29
 
30
30
  # @return [String] path where should look for source files
31
31
  #
@@ -125,24 +125,16 @@ module Epuber
125
125
  existing_file = @final_destination_path_to_file[file.final_destination_path]
126
126
 
127
127
  # save mapping from file_request to file, file_request can be different, but result file could be the same ...
128
- unless file.try(:file_request).nil?
129
- @request_to_files[file.file_request] << (existing_file || file)
130
- end
128
+ @request_to_files[file.file_request] << (existing_file || file) unless file.try(:file_request).nil?
131
129
 
132
130
  # return existing file if already exists, new file will be thrown away
133
131
  return existing_file unless existing_file.nil?
134
132
 
135
- if [:spine].include?(type)
136
- @spine_files << file
137
- end
133
+ @spine_files << file if [:spine].include?(type)
138
134
 
139
- if [:spine, :manifest].include?(type)
140
- @manifest_files << file
141
- end
135
+ @manifest_files << file if %i[spine manifest].include?(type)
142
136
 
143
- if [:spine, :manifest, :package].include?(type)
144
- @package_files << file
145
- end
137
+ @package_files << file if %i[spine manifest package].include?(type)
146
138
 
147
139
  @files << file
148
140
 
@@ -151,13 +143,11 @@ module Epuber
151
143
 
152
144
  @final_destination_path_to_file[file.final_destination_path] = file
153
145
 
154
- if file.respond_to?(:source_path) && !file.source_path.nil?
155
- @source_path_to_file[file.source_path] = file
156
- end
146
+ @source_path_to_file[file.source_path] = file if file.respond_to?(:source_path) && !file.source_path.nil?
157
147
 
158
- if file.respond_to?(:abs_source_path) && !file.abs_source_path.nil?
159
- @abs_source_path_to_file[file.abs_source_path] = file
160
- end
148
+ return unless file.respond_to?(:abs_source_path) && !file.abs_source_path.nil?
149
+
150
+ @abs_source_path_to_file[file.abs_source_path] = file
161
151
  end
162
152
 
163
153
  # Get instance of file from request instance
@@ -184,7 +174,7 @@ module Epuber
184
174
  end
185
175
 
186
176
  if file_request.only_one
187
- files.first # @request_to_files always returns array, see #initialize method
177
+ files.first # @request_to_files always returns array, see #initialize method
188
178
  else
189
179
  files
190
180
  end
@@ -219,99 +209,99 @@ module Epuber
219
209
  # @return [Array<String>] list of files that should be deleted in destination directory
220
210
  #
221
211
  def unneeded_files_in_destination
222
- requested_paths = files.map do |file|
223
- file.pkg_destination_path
224
- end
212
+ requested_paths = files.map(&:pkg_destination_path)
225
213
 
226
214
  existing_paths = FileFinders::Normal.new(destination_path).find_all('*')
227
215
 
228
216
  unnecessary_paths = existing_paths - requested_paths
229
217
 
230
- unnecessary_paths.select! do |path|
231
- !::File.directory?(File.join(destination_path, path))
218
+ unnecessary_paths.reject! do |path|
219
+ ::File.directory?(File.join(destination_path, path))
232
220
  end
233
221
 
234
222
  unnecessary_paths
235
223
  end
236
224
 
237
-
238
225
  ##################################################################################################################
239
226
 
240
- private
241
-
242
- # @param [String] path path to some file
243
- #
244
- # @return [String] path with changed extension
245
- #
246
- def self.renamed_file_with_path(path)
247
- extname = File.extname(path)
248
- new_extname = FileFinders::EXTENSIONS_RENAME[extname]
249
-
250
- if new_extname.nil?
251
- path
252
- else
253
- path.sub(/#{Regexp.escape(extname)}$/, new_extname)
254
- end
255
- end
256
-
257
- # @param file [Epuber::Compiler::AbstractFile]
258
- #
259
- # @return [nil]
260
- #
261
- def resolve_destination_path(file)
262
- if file.final_destination_path.nil?
263
- dest_path = if file.respond_to?(:source_path) && !file.source_path.nil?
264
- file.abs_source_path = File.expand_path(file.source_path, source_path)
265
- self.class.renamed_file_with_path(file.source_path)
266
- elsif !file.destination_path.nil?
267
- file.destination_path
268
- else
269
- raise ResolveError, "What should I do with file that doesn't have source path or destination path? file: #{file.inspect}"
270
- end
271
-
272
- file.destination_path = dest_path
273
- file.pkg_destination_path = File.join(*self.class.path_comps_for(file.path_type), dest_path)
274
- file.final_destination_path = File.join(destination_path, file.pkg_destination_path)
227
+ class << self
228
+ # @param [String] path path to some file
229
+ #
230
+ # @return [String] path with changed extension
231
+ #
232
+ def renamed_file_with_path(path)
233
+ extname = File.extname(path)
234
+ new_extname = FileFinders::EXTENSIONS_RENAME[extname]
235
+
236
+ if new_extname.nil?
237
+ path
238
+ else
239
+ path.sub(/#{Regexp.escape(extname)}$/, new_extname)
240
+ end
275
241
  end
276
- end
277
242
 
278
- # @param [String] extname extension of file
279
- #
280
- # @return [Class]
281
- #
282
- def self.file_class_for(extname)
283
- mapping = {
284
- '.styl' => FileTypes::StylusFile,
243
+ # @param [String] extname extension of file
244
+ #
245
+ # @return [Class]
246
+ #
247
+ def file_class_for(extname)
248
+ mapping = {
249
+ '.styl' => FileTypes::StylusFile,
250
+ '.css' => FileTypes::CSSFile,
285
251
 
286
- '.coffee' => FileTypes::CoffeeScriptFile,
252
+ '.coffee' => FileTypes::CoffeeScriptFile,
287
253
 
288
- '.bade' => FileTypes::BadeFile,
289
- '.xhtml' => FileTypes::XHTMLFile,
290
- '.html' => FileTypes::XHTMLFile,
254
+ '.bade' => FileTypes::BadeFile,
255
+ '.xhtml' => FileTypes::XHTMLFile,
256
+ '.html' => FileTypes::XHTMLFile,
291
257
 
292
- '.jpg' => FileTypes::ImageFile,
293
- '.jpeg' => FileTypes::ImageFile,
294
- '.png' => FileTypes::ImageFile,
295
- }
258
+ '.jpg' => FileTypes::ImageFile,
259
+ '.jpeg' => FileTypes::ImageFile,
260
+ '.png' => FileTypes::ImageFile,
261
+ }
296
262
 
297
- mapping[extname] || FileTypes::StaticFile
298
- end
263
+ mapping[extname] || FileTypes::StaticFile
264
+ end
299
265
 
300
- # @param [String] root_path path to root of the package
301
- # @param [Symbol] path_type path type of file
302
- #
303
- # @return [Array<String>] path components
304
- #
305
- def self.path_comps_for(root_path = nil, path_type)
306
- case path_type
266
+ # @param [String] root_path path to root of the package
267
+ # @param [Symbol] path_type path type of file
268
+ #
269
+ # @return [Array<String>] path components
270
+ #
271
+ def path_comps_for(root_path, path_type)
272
+ case path_type
307
273
  when :spine, :manifest
308
274
  Array(root_path) + [Compiler::EPUB_CONTENT_FOLDER]
309
275
  when :package
310
276
  Array(root_path)
311
- else
312
- nil
277
+ end
313
278
  end
314
279
  end
280
+
281
+ private
282
+
283
+ # @param [Epuber::Compiler::AbstractFile] file
284
+ #
285
+ # @return [nil]
286
+ #
287
+ def resolve_destination_path(file)
288
+ return unless file.final_destination_path.nil?
289
+
290
+ dest_path = if file.respond_to?(:source_path) && !file.source_path.nil?
291
+ file.abs_source_path = File.expand_path(file.source_path, source_path)
292
+ self.class.renamed_file_with_path(file.source_path)
293
+ elsif !file.destination_path.nil?
294
+ file.destination_path
295
+ else
296
+ raise ResolveError, <<~ERROR
297
+ What should I do with file that doesn't have source path or destination path? file: #{file.inspect}
298
+ ERROR
299
+ end
300
+
301
+ file.destination_path = dest_path
302
+ file.pkg_destination_path = File.join(*self.class.path_comps_for(nil, file.path_type), dest_path)
303
+ file.final_destination_path = File.join(destination_path, file.pkg_destination_path)
304
+ end
315
305
  end
316
306
  end
317
307
  end
@@ -36,7 +36,7 @@ module Epuber
36
36
  @mtime = stat.mtime
37
37
  @ctime = stat.ctime
38
38
  @size = stat.size
39
- rescue
39
+ rescue StandardError
40
40
  # noop
41
41
  end
42
42
  end
@@ -66,9 +66,9 @@ module Epuber
66
66
  raise AttributeError, "other must be class of #{self.class}" unless other.is_a?(FileStat)
67
67
 
68
68
  file_path == other.file_path &&
69
- size == other.size &&
70
- mtime == other.mtime &&
71
- ctime == other.ctime
69
+ size == other.size &&
70
+ mtime == other.mtime &&
71
+ ctime == other.ctime
72
72
  end
73
73
  end
74
74
  end
@@ -4,18 +4,18 @@ module Epuber
4
4
  class Compiler
5
5
  module FileTypes
6
6
  class AbstractFile
7
-
8
7
  # @return [String] relative destination path
9
8
  #
10
9
  attr_accessor :destination_path
11
10
 
12
- # @return [Symbol] group of this file (:text, :image, :font, ...), see Epuber::Compiler::FileFinder::GROUP_EXTENSIONS
11
+ # @return [Symbol] group of this file (:text, :image, :font, ...), see
12
+ # Epuber::Compiler::FileFinder::GROUP_EXTENSIONS
13
13
  #
14
14
  attr_accessor :group
15
15
 
16
16
  # @return [Set<Symbol>] list of properties
17
17
  #
18
- attr_accessor :properties
18
+ attr_writer :properties
19
19
 
20
20
  # @return [Set<Symbol>] list of properties
21
21
  #
@@ -23,7 +23,6 @@ module Epuber
23
23
  @properties ||= Set.new
24
24
  end
25
25
 
26
-
27
26
  # @return [String] final relative destination path from root of the package calculated by FileResolver
28
27
  #
29
28
  attr_accessor :pkg_destination_path
@@ -88,9 +87,7 @@ module Epuber
88
87
  def self.write_to_file!(content, to_path)
89
88
  FileUtils.mkdir_p(File.dirname(to_path))
90
89
 
91
- File.open(to_path, 'w') do |file_handle|
92
- file_handle.write(content)
93
- end
90
+ File.write(to_path, content)
94
91
  end
95
92
  end
96
93
  end
@@ -26,10 +26,15 @@ module Epuber
26
26
  __file_resolver: file_resolver,
27
27
  __file: self,
28
28
  __toc_item: toc_item,
29
- __const: Hash.new { |_hash, key| UI.warning("Undefined constant with key `#{key}`", location: caller_locations[0]) }.merge!(target.constants),
29
+ __const: Hash.new do |_hash, key|
30
+ UI.warning("Undefined constant with key `#{key}`", location: caller_locations[0])
31
+ end.merge!(target.constants),
30
32
  }
31
33
 
32
- should_load_from_precompiled = up_to_date && precompiled_exists && compilation_context.incremental_build? && (!compilation_context.should_write)
34
+ should_load_from_precompiled = up_to_date &&
35
+ precompiled_exists &&
36
+ compilation_context.incremental_build? &&
37
+ !compilation_context.should_write
33
38
 
34
39
  precompiled = if should_load_from_precompiled
35
40
  begin
@@ -40,16 +45,10 @@ module Epuber
40
45
  end
41
46
  end
42
47
 
43
- if !precompiled.nil?
44
- xhtml_content = UI.print_step_processing_time('rendering precompiled Bade') do
45
- renderer = Bade::Renderer.from_precompiled(precompiled)
46
- .with_locals(variables)
47
- renderer.file_path = source_path
48
-
49
- renderer.render(new_line: '', indent: '')
48
+ if precompiled.nil?
49
+ if compilation_context.incremental_build?
50
+ UI.print_processing_debug_info('Parsing new version of source file')
50
51
  end
51
- else
52
- UI.print_processing_debug_info('Parsing new version of source file') if compilation_context.incremental_build?
53
52
 
54
53
  bade_content = load_source(compilation_context)
55
54
 
@@ -58,13 +57,19 @@ module Epuber
58
57
  .with_locals(variables)
59
58
 
60
59
  # turn on optimizations when can
61
- if renderer.respond_to?(:optimize=)
62
- renderer.optimize = true
63
- end
60
+ renderer.optimize = true if renderer.respond_to?(:optimize=)
64
61
 
65
62
  FileUtils.mkdir_p(File.dirname(precompiled_path))
66
63
  renderer.precompiled.write_yaml_to_file(precompiled_path)
67
64
 
65
+ renderer.render(new_line: '', indent: '')
66
+ end
67
+ else
68
+ xhtml_content = UI.print_step_processing_time('rendering precompiled Bade') do
69
+ renderer = Bade::Renderer.from_precompiled(precompiled)
70
+ .with_locals(variables)
71
+ renderer.file_path = source_path
72
+
68
73
  renderer.render(new_line: '', indent: '')
69
74
  end
70
75
  end
@@ -82,7 +87,7 @@ module Epuber
82
87
  # @return [String]
83
88
  #
84
89
  def precompiled_path
85
- File.join(Config.instance.build_cache_path(PRECOMPILED_CACHE_NAME), source_path + '.precompiled.yml')
90
+ File.join(Config.instance.build_cache_path(PRECOMPILED_CACHE_NAME), "#{source_path}.precompiled.yml")
86
91
  end
87
92
 
88
93
  def pretty_precompiled_path
@@ -10,7 +10,7 @@ module Epuber
10
10
  class CoffeeScriptFile < SourceFile
11
11
  # @param [Compiler::CompilationContext] compilation_context
12
12
  #
13
- def process(compilation_context)
13
+ def process(_compilation_context)
14
14
  return if destination_file_up_to_date?
15
15
 
16
16
  write_compiled(CoffeeScript.compile(File.new(abs_source_path)))
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'css_parser'
4
+
5
+ module Epuber
6
+ class Compiler
7
+ module FileTypes
8
+ require_relative 'source_file'
9
+
10
+ class CSSFile < SourceFile
11
+ DECLARATION_TO_FILE_GROUP_MAP = {
12
+ 'background' => :image,
13
+ 'background-image' => :image,
14
+ 'list-style' => :image,
15
+ 'list-style-image' => :image,
16
+ 'content' => :image,
17
+ 'cursor' => :image,
18
+ 'border-image' => :image,
19
+ 'border-image-source' => :image,
20
+ 'mask-image' => :image,
21
+ 'mask-box-image' => :image,
22
+ 'src' => :font,
23
+ }.freeze
24
+
25
+ URL_REGEXP = /url\((.+)\)/.freeze
26
+
27
+ # @param [Compiler::CompilationContext] compilation_context
28
+ #
29
+ def process(compilation_context)
30
+ return if destination_file_up_to_date?
31
+
32
+ write_processed(process_css(File.read(abs_source_path), compilation_context))
33
+ end
34
+
35
+ # Processes CSS file, resolves all linked files and adds them to file resolver
36
+ #
37
+ # @param [String] content
38
+ # @param [Compiler::CompilationContext] compilation_context
39
+ #
40
+ # @return [String]
41
+ #
42
+ def process_css(content, compilation_context)
43
+ file_resolver = compilation_context.file_resolver
44
+
45
+ parser = UI.print_step_processing_time('css parsing') do
46
+ parser = CssParser::Parser.new
47
+ parser.load_string!(content)
48
+ parser
49
+ end
50
+
51
+ # resolve links to files, add other linked resources and compute correct path
52
+ UI.print_step_processing_time('resolving url()') do
53
+ parser.each_rule_set do |rule_set, _media_types|
54
+ declarations = rule_set.instance_eval { @declarations }
55
+ declarations.each do |property, decl_value|
56
+ value = decl_value.to_s
57
+ next unless value =~ URL_REGEXP
58
+
59
+ path = Regexp.last_match(1)
60
+ if path.start_with?('"') && path.end_with?('"')
61
+ path = path[1..-2]
62
+ quote = '"'
63
+ end
64
+ if path.start_with?("'") && path.end_with?("'")
65
+ path = path[1..-2]
66
+ quote = "'"
67
+ end
68
+
69
+ next if path.start_with?('data:') || path.start_with?('http://') || path.start_with?('https://')
70
+
71
+ resource_group = DECLARATION_TO_FILE_GROUP_MAP[property]
72
+ dirname = File.dirname(destination_path)
73
+
74
+ begin
75
+ new_path = file_resolver.dest_finder.find_file(path, groups: resource_group, context_path: dirname)
76
+ rescue FileFinders::FileNotFoundError, FileFinders::MultipleFilesFoundError
77
+ new_path = XHTMLProcessor.resolved_link_to_file(path,
78
+ resource_group,
79
+ dirname,
80
+ file_resolver.source_finder).to_s
81
+ pkg_abs_path = File.expand_path(new_path, dirname).unicode_normalize
82
+ pkg_new_path = Pathname.new(pkg_abs_path)
83
+ .relative_path_from(Pathname.new(file_resolver.source_path))
84
+ .to_s
85
+
86
+ file_class = FileResolver.file_class_for(File.extname(new_path))
87
+ file = file_class.new(pkg_new_path)
88
+ file.path_type = :manifest
89
+ file_resolver.add_file(file)
90
+ end
91
+
92
+ new_url = FileResolver.renamed_file_with_path(new_path)
93
+ content = content.gsub(value, "url(#{quote}#{new_url}#{quote})")
94
+ end
95
+ end
96
+ end
97
+
98
+ content
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -12,7 +12,7 @@ module Epuber
12
12
 
13
13
  # @param [Compiler::CompilationContext] compilation_context
14
14
  #
15
- def process(compilation_context)
15
+ def process(_compilation_context)
16
16
  write_generate(content.to_s)
17
17
  end
18
18
 
@@ -16,14 +16,16 @@ module Epuber
16
16
  dest = final_destination_path
17
17
  source = abs_source_path
18
18
 
19
- img = Magick::Image::read(source).first
19
+ img = Magick::Image.read(source).first
20
20
 
21
21
  resolution = img.columns * img.rows
22
22
  max_resolution = 3_000_000
23
23
 
24
24
  if resolution > max_resolution
25
25
  img = img.change_geometry("#{max_resolution}@>") do |width, height, b_img|
26
- UI.print_processing_debug_info("downscaling from resolution #{b_img.columns}x#{b_img.rows} to #{width}x#{height}")
26
+ UI.print_processing_debug_info(<<~MSG)
27
+ downscaling from resolution #{b_img.columns}x#{b_img.rows} to #{width}x#{height}
28
+ MSG
27
29
  b_img.resize!(width, height)
28
30
  end
29
31
 
@@ -6,7 +6,6 @@ module Epuber
6
6
  require_relative 'generated_file'
7
7
 
8
8
  class NavFile < GeneratedFile
9
-
10
9
  # @return [Epuber::Version]
11
10
  #
12
11
  attr_reader :epub_version
@@ -6,7 +6,6 @@ module Epuber
6
6
  require_relative 'generated_file'
7
7
 
8
8
  class OPFFile < GeneratedFile
9
-
10
9
  def initialize
11
10
  super
12
11