epuber 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6a67f5875818b18606d58bcf55c2095419e2a48b5f7766627d4196d7bf733c8
4
- data.tar.gz: 99b80c62fe55f485d6da21d9be273891ea4ebb7383476099972902d8d8aae014
3
+ metadata.gz: 2899b08ccdd624b08c96377e111df6872f4c6b0871ee689e28d1264d42bf5294
4
+ data.tar.gz: 6391e4b90172bc5d06d7c3f903aafa52efab3917ee0daaaf406723f3ee2d381f
5
5
  SHA512:
6
- metadata.gz: 0753d03cf0e27538cc09a95fccec5dac1299bcbec5e1d739e8718e59b870e91b523311627609fc303b0aa143b9fd0582925b8a1feb75f66b236943d6d975957a
7
- data.tar.gz: 13efd113cdd854e03dc17d62786d17fab9e0d7b3554eeca8caa5ddd2e5062eba15ef6c73a65eb2c24b7173873b9481d1538dd6919ad43ac135a12cf471d4c727
6
+ metadata.gz: 7a2df3f599de46ca5c5e976154d32752981fa9d2a76e0a46754b91f5583c3e671c3ab77c777bc8511dbda09f23ea0a8534d16656a1dfce4748b762fa7d7c3947
7
+ data.tar.gz: b5d8d5556ce730d2215a6239405a56505f87e649fa1b06078cb2145f524c2d59e82d2789b21d0873c573079daa807ff9cc3d22b16bf26d85f4e223ac20ead502
data/Gemfile CHANGED
@@ -5,4 +5,5 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in Epuber.gemspec
6
6
  gemspec
7
7
 
8
- gem 'coveralls', require: false
8
+ gem 'ruby-debug-ide'
9
+ gem 'debase'
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Epuber
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/epuber.svg)](http://badge.fury.io/rb/epuber) [![Build Status](https://travis-ci.org/epuber-io/epuber.svg?branch=master)](https://travis-ci.org/epuber-io/epuber) [![Coverage Status](https://coveralls.io/repos/epuber-io/epuber/badge.svg?branch=master&service=github)](https://coveralls.io/github/epuber-io/epuber?branch=master) [![Inline docs](http://inch-ci.org/github/epuber-io/epuber.svg?branch=master)](http://inch-ci.org/github/epuber-io/epuber) [![Join the chat at https://gitter.im/epuber-io/epuber](https://badges.gitter.im/epuber-io/epuber.svg)](https://gitter.im/epuber-io/epuber?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
3
+ [![Gem Version](https://badge.fury.io/rb/epuber.svg)](http://badge.fury.io/rb/epuber) [![Build Status](https://github.com/epuber-io/epuber/actions/workflows/tests.yml/badge.svg)](https://github.com/epuber-io/epuber/actions) [![Coverage Status](https://coveralls.io/repos/epuber-io/epuber/badge.svg?branch=master&service=github)](https://coveralls.io/github/epuber-io/epuber?branch=master) [![Inline docs](https://inch-ci.org/github/epuber-io/epuber.svg?branch=master)](https://inch-ci.org/github/epuber-io/epuber)
4
4
 
5
5
  Epuber is simple tool to compile and pack source files into EPUB format. Offers to define multiple "targets" which allows to create multiple versions of the book by running only one command. Eliminates copying code and information, eliminates needs to use _git_ branches to differ ebook content.
6
6
 
@@ -46,37 +46,39 @@ end
46
46
 
47
47
  Except for paths to plugins `book.use`, every path could be only name of the file, even without extension. So you can rename them, move them, the correct path will always resolved. Only exception is when the same name has more then one file.
48
48
 
49
- | Epuber
50
- -----------|------------------------------------------------------------
51
- :book: | Creates seamless workflow for creating ebooks
52
- :monorail: | Defines different _targets_ for several book stores (iBookstore, Google Play store, ...)
53
- :wrench: | Extend and customise the functionality with _plugins_
54
- :pencil2: | Defines _constants_ so you can have link to related book in proper book store
55
- :pencil: | Defines mechanisms to deal with duplicated
56
- :tophat: | Easy setup assistant to get started in a few minutes
57
- :ghost: | Automatically validates generated text so you don't have to worry about typos and other mistakes
58
- :rocket: | Saves you **hours** when developing new or updating existing book
59
- :page_with_curl: | Supports template engines, CSS preprocessors and standard EPUB formats at the same time
60
- :computer: | Have local development web server to iterate and experiment quickly
61
- :loop: | Automatically refresh web browser when some source file changes
62
- :bomb: | Quick jumping through pages with arrow keys on keyboard
63
- :closed_book: | Supports EPUB 2 and 3
49
+ | | Epuber |
50
+ |-----------------|------------------------------------------------------------------------------------------------- |
51
+ |:book: | Creates seamless workflow for creating ebooks |
52
+ |:monorail: | Defines different _targets_ for several book stores (iBookstore, Google Play store, ...) |
53
+ |:wrench: | Extend and customise the functionality with _plugins_ |
54
+ |:pencil2: | Defines _constants_ so you can have link to related book in proper book store |
55
+ |:pencil: | Defines mechanisms to deal with duplicated |
56
+ |:tophat: | Easy setup assistant to get started in a few minutes |
57
+ |:ghost: | Automatically validates generated text so you don't have to worry about typos and other mistakes |
58
+ |:rocket: | Saves you **hours** when developing new or updating existing book |
59
+ |:page_with_curl: | Supports template engines, CSS preprocessors and standard EPUB formats at the same time |
60
+ |:computer: | Have local development web server to iterate and experiment quickly |
61
+ |:loop: | Automatically refresh web browser when some source file changes |
62
+ |:bomb: | Quick jumping through pages with arrow keys on keyboard |
63
+ |:closed_book: | Supports EPUB 2 and 3 |
64
64
 
65
65
 
66
66
  ## Installation
67
67
 
68
68
  First of all Epuber uses [RMagick](https://github.com/rmagick/rmagick) which has several external dependencies, so you have to install that first:
69
69
 
70
- - ImageMagick
70
+ - ImageMagick (only v6 for now)
71
71
  - pkg-config
72
72
 
73
73
  On OS X make sure you Xcode Command Line Tools installed:
74
74
 
75
75
  xcode-select --install
76
76
 
77
- And the easiest way to install prerequisites on OS X is to use [brew](http://brew.sh):
77
+ And the easiest way to install prerequisites on macOS is to use [brew](http://brew.sh):
78
78
 
79
- brew install imagemagick pkg-config
79
+ brew install imagemagick@6 node@12 pkg-config
80
+ brew link --force imagemagick@6
81
+ brew link --force --overwrite node@12
80
82
 
81
83
  On Ubuntu, you can run:
82
84
 
@@ -87,7 +89,7 @@ On Ubuntu, you can run:
87
89
 
88
90
  Then just type following line to terminal:
89
91
 
90
- sudo gem install epuber
92
+ [sudo] gem install epuber
91
93
 
92
94
  If everything goes well, try running following line in terminal:
93
95
 
data/epuber.gemspec CHANGED
@@ -14,14 +14,15 @@ Gem::Specification.new do |spec|
14
14
  spec.summary = 'Epuber is simple tool to compile and pack source files into EPUB format.'
15
15
  spec.homepage = Epuber::HOME_URL
16
16
  spec.license = 'MIT'
17
- spec.required_ruby_version = '>= 2.3'
17
+ spec.required_ruby_version = '>= 2.5'
18
18
 
19
19
  spec.files = Dir['bin/**/*'] + Dir['lib/**/*'] + %w(epuber.gemspec Gemfile LICENSE.txt README.md)
20
20
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
21
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
22
  spec.require_paths = ['lib']
23
23
 
24
- spec.add_runtime_dependency 'activesupport', '~> 5.0'
24
+ spec.add_runtime_dependency 'activesupport', '~> 6.0'
25
+ spec.add_runtime_dependency 'addressable', '~> 2.7'
25
26
  spec.add_runtime_dependency 'nokogiri', '~> 1.8', '>= 1.8.2'
26
27
  spec.add_runtime_dependency 'mime-types', '~> 3.0'
27
28
  spec.add_runtime_dependency 'claide', '~> 1.0'
@@ -33,8 +34,8 @@ Gem::Specification.new do |spec|
33
34
  spec.add_runtime_dependency 'sinatra-contrib', '~> 2.0'
34
35
  spec.add_runtime_dependency 'thin', '~> 1.6'
35
36
 
36
- spec.add_runtime_dependency 'rmagick', '~> 2.14'
37
- spec.add_runtime_dependency 'rubyzip', '~> 1.0'
37
+ spec.add_runtime_dependency 'rmagick', '~> 4.2'
38
+ spec.add_runtime_dependency 'rubyzip', '~> 2.3'
38
39
 
39
40
  spec.add_runtime_dependency 'epubcheck-ruby', '~> 4.0'
40
41
 
@@ -42,9 +43,9 @@ Gem::Specification.new do |spec|
42
43
  spec.add_runtime_dependency 'coffee-script', '~> 2.4'
43
44
  spec.add_runtime_dependency 'bade', '~> 0.2.4'
44
45
 
45
- spec.add_development_dependency 'bundler', '~> 1.15'
46
+ spec.add_development_dependency 'bundler'
46
47
  spec.add_development_dependency 'rspec', '~> 3.2'
47
- spec.add_development_dependency 'rubocop', '~> 0.49'
48
- spec.add_development_dependency 'rake', '~> 12.2'
49
- spec.add_development_dependency 'fakefs', '~> 0.6'
48
+ spec.add_development_dependency 'rubocop', '~> 1.14'
49
+ spec.add_development_dependency 'rake', '~> 13.0'
50
+ spec.add_development_dependency 'fakefs', '~> 1.3'
50
51
  end
@@ -161,7 +161,6 @@ module Epuber
161
161
  attribute :epub_version,
162
162
  required: true,
163
163
  inherited: true,
164
- types: [Version],
165
164
  auto_convert: { [String, Integer, Float] => Version },
166
165
  default_value: 3.0
167
166
 
@@ -11,7 +11,6 @@ module Epuber
11
11
  # @return [Epuber::Book::FileRequest]
12
12
  #
13
13
  attribute :file_request,
14
- types: [FileRequest],
15
14
  auto_convert: { String => FileRequest },
16
15
  inherited: true
17
16
 
@@ -4,85 +4,25 @@ require 'active_support/core_ext/string/access'
4
4
 
5
5
  require_relative '../ruby_extensions/match_data'
6
6
  require_relative '../checker'
7
-
7
+ require_relative '../compiler/problem'
8
8
 
9
9
  module Epuber
10
10
  class Checker
11
11
  class TextChecker < Checker
12
- class MatchProblem
12
+ class MatchProblem < Compiler::Problem
13
13
  # @param message [String]
14
14
  # @param file_path [String]
15
15
  # @param match [MatchData]
16
16
  #
17
17
  def initialize(match, message, file_path)
18
- @match = match
19
- @message = message
20
- @file_path = file_path
21
- end
22
-
23
- # Formats caret symbol with space indent
24
- #
25
- # @param [Fixnum] indent
26
- #
27
- # @return [String]
28
- #
29
- def caret_symbol(indent)
30
- ' ' * indent + '^'
31
- end
32
-
33
- # Formats caret symbols for indent and length
34
- #
35
- # @param [Fixnum] length
36
- # @param [Fixnum] indent
37
- #
38
- # @return [String]
39
- #
40
- def caret_symbols(indent, length)
41
- start_sign = caret_symbol(indent)
42
- end_sign = if length > 1
43
- caret_symbol(length-2)
44
- else
45
- ''
46
- end
47
-
48
- "#{start_sign}#{end_sign}"
49
- end
50
-
51
- def formatted_match_line
52
- match_line = @match.matched_string
53
- pre_line = @match.pre_match_lines.last || ''
54
-
55
- pre = match_pre_line = pre_line
56
- if remove_tabs(match_pre_line).length > 100
57
- pre = "#{match_pre_line.first(20)}...#{match_pre_line.last(30)}"
58
- end
59
-
60
- pre = remove_tabs(pre)
61
-
62
- post_line = @match.post_match_lines.first || ''
63
-
64
- post = if post_line.length > 50
65
- "#{post_line.first(50)}..."
66
- else
67
- post_line
68
- end
69
-
70
- [pre, match_line, post]
71
- end
72
-
73
- def remove_tabs(text)
74
- text.gsub("\t", ' ' * 4)
75
- end
76
-
77
- def to_s
78
- pre_original = @match.pre_match_lines.last || ''
79
- pre, match_text, post = formatted_match_line
18
+ whole_text = match.pre_match + match.matched_string + match.post_match
80
19
 
81
- pointers = caret_symbols(pre.length, match_text.length)
20
+ line = match.pre_match_lines.count
21
+ column = (match.pre_match_lines.last || '').length + 1
22
+ length = match.matched_string.length
23
+ location = Epuber::Compiler::Problem::Location.new(line, column, length)
82
24
 
83
- %{#{@file_path}:#{@match.line_number} column: #{pre_original.length} --- #{@message}
84
- #{pre + match_text.ansi.red + post}
85
- #{pointers}}
25
+ super(:warn, message, whole_text, location: location, file_path: file_path)
86
26
  end
87
27
  end
88
28
 
@@ -74,5 +74,14 @@ module Epuber
74
74
  Epuber::Config.instance.save_lockfile
75
75
  end
76
76
  end
77
+
78
+ def pre_build_checks
79
+ Config.instance.warn_for_outdated_versions!
80
+
81
+ if !Config.instance.same_version_as_last_run? && File.exist?(Config.instance.working_path)
82
+ UI.warning('Using different version of Epuber or Bade, removing all build caches')
83
+ Config.instance.remove_build_caches
84
+ end
85
+ end
77
86
  end
78
87
  end
@@ -45,7 +45,7 @@ module Epuber
45
45
  verify_one_bookspec_exists!
46
46
  verify_all_targets_exists!
47
47
 
48
- Config.instance.warn_for_outdated_versions!
48
+ pre_build_checks
49
49
  end
50
50
 
51
51
  def run
@@ -30,7 +30,7 @@ module Epuber
30
30
  super
31
31
  verify_one_bookspec_exists!
32
32
 
33
- Config.instance.warn_for_outdated_versions!
33
+ pre_build_checks
34
34
  end
35
35
 
36
36
  def run
@@ -1,6 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- require_relative '../ruby_extensions/string'
4
3
  require 'active_support/core_ext/object/try'
5
4
 
6
5
  module Epuber
@@ -68,11 +68,11 @@ module Epuber
68
68
  xhtml_content
69
69
  end
70
70
 
71
- # @param [Array] errors
71
+ # @param [Array<Epuber::Compiler::Problem>] errors
72
72
  #
73
73
  def process_nokogiri_errors(errors)
74
- errors.each do |e|
75
- UI.warning(e)
74
+ errors.each do |problem|
75
+ UI.warning(problem, location: self)
76
76
  end
77
77
  end
78
78
 
@@ -86,25 +86,18 @@ module Epuber
86
86
  book = compilation_context.book
87
87
  file_resolver = compilation_context.file_resolver
88
88
 
89
- xhtml_doc = UI.print_step_processing_time('parsing XHTML file') do
90
- XHTMLProcessor.xml_document_from_string(content, source_path)
89
+ xhtml_doc, errors = UI.print_step_processing_time('parsing XHTML file') do
90
+ XHTMLProcessor.xml_doc_from_str_with_errors(content, source_path)
91
91
  end
92
92
 
93
93
  if compilation_context.release_build && xhtml_doc.errors.count > 0
94
- process_nokogiri_errors(xhtml_doc.errors)
94
+ process_nokogiri_errors(errors)
95
95
  end
96
96
 
97
97
  UI.print_step_processing_time('adding missing elements') do
98
98
  XHTMLProcessor.add_missing_root_elements(xhtml_doc, book.title, target.epub_version)
99
99
  end
100
100
 
101
- UI.print_step_processing_time('adding default things') do
102
- XHTMLProcessor.add_styles(xhtml_doc, default_styles(target, file_resolver))
103
- XHTMLProcessor.add_scripts(xhtml_doc, default_scripts(target, file_resolver))
104
-
105
- XHTMLProcessor.add_viewport(xhtml_doc, target.default_viewport) unless target.default_viewport.nil?
106
- end
107
-
108
101
  # resolve links to files, add other linked resources and compute correct path
109
102
  UI.print_step_processing_time('resolving links') do
110
103
  XHTMLProcessor.resolve_links(xhtml_doc, destination_path, file_resolver.dest_finder)
@@ -119,6 +112,13 @@ module Epuber
119
112
  XHTMLProcessor.resolve_stylesheets(xhtml_doc, destination_path, file_resolver)
120
113
  end
121
114
 
115
+ UI.print_step_processing_time('adding default things') do
116
+ XHTMLProcessor.add_styles(xhtml_doc, default_styles(target, file_resolver))
117
+ XHTMLProcessor.add_scripts(xhtml_doc, default_scripts(target, file_resolver))
118
+
119
+ XHTMLProcessor.add_viewport(xhtml_doc, target.default_viewport) unless target.default_viewport.nil?
120
+ end
121
+
122
122
  XHTMLProcessor.resolve_mathml_namespace(xhtml_doc)
123
123
 
124
124
  UI.print_step_processing_time('investigating properties') do
@@ -121,7 +121,7 @@ module Epuber
121
121
  end
122
122
  end
123
123
 
124
- if @target.epub_version >= 3 && toc_items.length > 0
124
+ if @target.epub_version >= 3 && toc_items.length > 0 && contains_item_with_title(toc_items)
125
125
  @xml.ol do
126
126
  iterate_lambda.call
127
127
  end
@@ -130,6 +130,10 @@ module Epuber
130
130
  end
131
131
  end
132
132
 
133
+ def contains_item_with_title(toc_items)
134
+ toc_items.any? { |a| a.title || contains_item_with_title(a.sub_items) }
135
+ end
136
+
133
137
  # @param toc_item [Epuber::Book::TocItem]
134
138
  #
135
139
  def visit_toc_item(toc_item)
@@ -257,18 +257,30 @@ module Epuber
257
257
  # @return [String]
258
258
  #
259
259
  def create_id_from_path(path)
260
- path && path.gsub('/', '.')
260
+ return nil if path.nil?
261
+
262
+ path.gsub('/', '.').gsub(/^[0-9]*/, '')
261
263
  end
262
264
 
263
265
  # Creates proper mime-type for file
264
266
  #
265
- # @param file [Epuber::Book::File]
267
+ # @param file [Epuber::Compiler::FileTypes::AbstractFile | String]
266
268
  #
267
269
  # @return [String]
268
270
  #
269
271
  def mime_type_for(file)
270
- filename = file.destination_path
271
- MIME::Types.of(filename).first.content_type
272
+ filename = if file.is_a?(String)
273
+ file
274
+ else
275
+ file.destination_path
276
+ end
277
+
278
+ case File.extname(filename)
279
+ when '.ttf', '.otf'
280
+ 'application/vnd.ms-opentype'
281
+ else
282
+ MIME::Types.of(filename).first.content_type
283
+ end
272
284
  end
273
285
 
274
286
  # Creates hash of namespaces for root package element
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ module Epuber
5
+ class Compiler
6
+ class Problem
7
+ class Location
8
+ attr_reader :line
9
+ attr_reader :column
10
+ attr_reader :length
11
+
12
+ def initialize(line, column, length = nil)
13
+ @line = line
14
+ @column = column
15
+ @length = length || 1
16
+ end
17
+ end
18
+
19
+ attr_reader :level
20
+ attr_reader :message
21
+ attr_reader :source
22
+ attr_reader :location
23
+ attr_reader :file_path
24
+
25
+ def initialize(level, message, source, location: nil, line: nil, column: nil, length: nil, file_path: nil)
26
+ @level = level
27
+ @message = message
28
+ @source = source
29
+ @location = location
30
+ if @location.nil? && line && column
31
+ @location = Location.new(line, column, length)
32
+ end
33
+
34
+ @file_path = file_path
35
+ end
36
+
37
+ # Formats caret symbol with space indent
38
+ #
39
+ # @param [Fixnum] indent
40
+ #
41
+ # @return [String]
42
+ #
43
+ def self.caret_symbol(indent)
44
+ ' ' * indent + '^'
45
+ end
46
+
47
+ # Formats caret symbols for indent and length
48
+ #
49
+ # @param [Fixnum] length
50
+ # @param [Fixnum] indent
51
+ #
52
+ # @return [String]
53
+ #
54
+ def self.caret_symbols(indent, length)
55
+ start_sign = caret_symbol(indent)
56
+ end_sign = if length > 1
57
+ caret_symbol(length-2)
58
+ else
59
+ ''
60
+ end
61
+
62
+ "#{start_sign}#{end_sign}"
63
+ end
64
+
65
+ def self.remove_tabs(text)
66
+ text.gsub("\t", ' ' * 4)
67
+ end
68
+
69
+ # @param [Location] location
70
+ #
71
+ def self.text_at(text, location)
72
+ line_index = location.line - 1
73
+ column_index = location.column - 1
74
+
75
+ lines = text.split("\n")
76
+
77
+ line = lines[line_index] || ''
78
+ matched_text = line[column_index ... column_index + location.length] || ''
79
+
80
+ pre = (lines[0 ... line_index] + [line[0 ... column_index]]).join("\n")
81
+ post = ([line[column_index + location.length .. line.length]] + (lines[location.line .. lines.count] || [])).join("\n")
82
+
83
+ [pre, matched_text, post]
84
+ end
85
+
86
+ def self.formatted_match_line(text, location)
87
+ pre, matched, post = text_at(text, location)
88
+
89
+ pre_line = pre.split("\n").last || ''
90
+ post_line = post.split("\n").first || ''
91
+
92
+ pre = match_pre_line = pre_line
93
+ if remove_tabs(match_pre_line).length > 100
94
+ pre = "#{match_pre_line.first(20)}...#{match_pre_line.last(30)}"
95
+ end
96
+
97
+ pre = remove_tabs(pre)
98
+
99
+ post = if post_line.length > 50
100
+ "#{post_line.first(50)}..."
101
+ else
102
+ post_line
103
+ end
104
+
105
+ [pre, matched, post]
106
+ end
107
+
108
+ def to_s
109
+ pre, match_text, post = self.class.formatted_match_line(@source, @location)
110
+
111
+ pointers = self.class.caret_symbols(pre.length, @location.length)
112
+ colored_match_text = match_text.empty? ? match_text : match_text.ansi.red
113
+ column = @location.column
114
+ line = [@location.line, 1].max
115
+
116
+ [
117
+ "#{@file_path}:#{line} column: #{column} --- #{@message}",
118
+ ' ' + pre + colored_match_text + post,
119
+ ' ' + pointers,
120
+ ].join("\n")
121
+ end
122
+ end
123
+ end
124
+ end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'nokogiri'
4
- require 'uri'
4
+ require 'addressable'
5
5
 
6
6
 
7
7
  module Epuber
@@ -19,14 +19,14 @@ module Epuber
19
19
  #
20
20
  # @return [Nokogiri::XML::Document] parsed document
21
21
  #
22
- def self.xml_document_from_string(text, file_path = nil)
22
+ def self.xml_doc_from_str_with_errors(text, file_path = nil)
23
23
  if /\A[\n\r ]+(<\?xml)/ =~ text
24
24
  UI.warning('XML header must be at the beginning of document', location: UI::Location.new(file_path, 1))
25
25
 
26
26
  text = text.lstrip
27
27
  end
28
28
 
29
- xml_header = ''
29
+ xml_header = nil
30
30
  if /\A\s*(<\?xml[^>]*\?>)/ =~ text
31
31
  match = Regexp.last_match
32
32
  xml_header = text[match.begin(1)...match.end(1)]
@@ -50,20 +50,38 @@ module Epuber
50
50
  Nokogiri::XML::ParseOptions::NOERROR | # to silence any errors or warnings printing into console
51
51
  Nokogiri::XML::ParseOptions::NOWARNING
52
52
 
53
- doc = Nokogiri::XML("#{before}<root>#{text}</root>", nil, nil, parse_options)
53
+ doc = Nokogiri::XML("#{before}<root>#{text}</root>", file_path, nil, parse_options)
54
+ text_for_errors = before + text
54
55
  doc.encoding = 'UTF-8'
55
56
  doc.file_path = file_path
56
57
 
58
+ if doc.errors.empty?
59
+ errors = []
60
+ else
61
+ errors = doc.errors.map do |e|
62
+ Problem.new(:error, e.message, text_for_errors, line: e.line, column: e.column, file_path: file_path)
63
+ end
64
+ end
65
+
57
66
  root = root_node = doc.root
58
67
  root_elements = root.children.select { |a| a.element? || a.comment? }
59
68
 
60
69
  if root_elements.count == 1
61
70
  doc.root = root_elements.first
71
+ elsif root_node.at_css('html')
72
+ doc.root = root_node.at_css('html')
62
73
  elsif root_node.at_css('body').nil?
63
74
  root_node.node_name = 'body'
75
+ else
76
+ root_node.node_name = 'html'
64
77
  end
65
78
 
66
- doc
79
+ [doc, errors]
80
+ end
81
+
82
+ def self.xml_document_from_string(text, file_path = nil)
83
+ xml, errros = self.xml_doc_from_str_with_errors(text, file_path)
84
+ xml
67
85
  end
68
86
 
69
87
 
@@ -83,25 +101,37 @@ module Epuber
83
101
  def self.add_missing_root_elements(xhtml_doc, title, epub_version)
84
102
  # add missing body element
85
103
  if xhtml_doc.at_css('body').nil?
86
- xhtml_doc.root.surround_with_element('body')
104
+ if xhtml_doc.root.node_name == 'html'
105
+ xhtml_doc.root << xhtml_doc.create_element('body')
106
+ else
107
+ xhtml_doc.root.surround_with_element('body')
108
+ end
87
109
  end
88
110
 
111
+ html = xhtml_doc.at_css('html')
112
+
89
113
  # add missing root html element
90
- if xhtml_doc.at_css('html').nil?
114
+ if html.nil?
91
115
  attrs = {}
92
116
  attrs['xmlns'] = 'http://www.w3.org/1999/xhtml'
93
117
  attrs['xmlns:epub'] = 'http://www.idpf.org/2007/ops' if epub_version >= 3
94
- xhtml_doc.root.surround_with_element('html', attrs)
118
+ html = xhtml_doc.root.surround_with_element('html', attrs)
119
+ elsif html.namespaces.empty?
120
+ html['xmlns'] = 'http://www.w3.org/1999/xhtml'
121
+ html['xmlns:epub'] = 'http://www.idpf.org/2007/ops' if epub_version >= 3
95
122
  end
96
123
 
97
124
  # add missing head in html
98
125
  if xhtml_doc.at_css('html > head').nil?
99
- html = xhtml_doc.css('html').first
100
126
  head = xhtml_doc.create_element('head')
101
127
  head << xhtml_doc.create_element('title', title)
102
128
  head << xhtml_doc.create_element('meta', charset: 'utf-8') if epub_version >= 3.0
103
129
 
104
- html.children.first.before(head)
130
+ if (first = html.children.first)
131
+ first.before(head)
132
+ else
133
+ html << head
134
+ end
105
135
  end
106
136
 
107
137
  # https://github.com/IDPF/epubcheck/issues/631
@@ -178,7 +208,7 @@ module Epuber
178
208
  uri = URI(path)
179
209
  rescue URI::InvalidURIError
180
210
  begin
181
- uri = URI(URI::encode(path))
211
+ uri = URI(Addressable::URI.encode(path))
182
212
  rescue URI::InvalidURIError
183
213
  # skip not valid uri
184
214
  raise UnparseableLinkError, "Unparseable link `#{path}`"
data/lib/epuber/config.rb CHANGED
@@ -123,14 +123,26 @@ module Epuber
123
123
 
124
124
  def warn_for_outdated_versions!
125
125
  if bookspec_lockfile.epuber_version > Epuber::VERSION
126
- UI.warning('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`')
126
+ UI.warning('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`.')
127
127
  end
128
128
 
129
129
  if bookspec_lockfile.bade_version && bookspec_lockfile.bade_version > Bade::VERSION
130
- UI.warning('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`')
130
+ UI.warning('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`.')
131
131
  end
132
132
  end
133
133
 
134
+ def same_version_as_last_run?
135
+ !(bookspec_lockfile.epuber_version != Epuber::VERSION ||
136
+ bookspec_lockfile.bade_version.nil? ||
137
+ bookspec_lockfile.bade_version != Bade::VERSION)
138
+ end
139
+
140
+ def remove_build_caches
141
+ FileUtils.rm_rf(File.join(working_path, 'build_cache'))
142
+ FileUtils.rm_rf(File.join(working_path, 'build'))
143
+ FileUtils.rm_rf(File.join(working_path, 'metadata'))
144
+ end
145
+
134
146
  # ---------------------------------------------------------------------------------------------------------------- #
135
147
 
136
148
  class << self
@@ -47,8 +47,10 @@ module Epuber
47
47
  @auto_convert = auto_convert
48
48
  @types = if !types.nil?
49
49
  types
50
- elsif @default_value
50
+ elsif @default_value && @auto_convert.empty?
51
51
  [@default_value.class]
52
+ elsif !@auto_convert.empty?
53
+ [@auto_convert.values.first]
52
54
  else
53
55
  [String]
54
56
  end
@@ -234,6 +236,8 @@ module Epuber
234
236
  return dest_class.call(value)
235
237
  elsif dest_class.respond_to?(:parse)
236
238
  return dest_class.parse(value)
239
+ elsif dest_class <= String
240
+ return value.to_s
237
241
  elsif dest_class.respond_to?(:new)
238
242
  return dest_class.new(value)
239
243
  else
@@ -66,12 +66,8 @@ module Epuber
66
66
  parent.send(key)
67
67
 
68
68
  elsif !attr.default_value.nil?
69
- # write default value on first access to root object
70
- root_obj = self.class.find_root(self) || self
71
- root_obj.send(attr.writer_name, attr.default_value)
72
-
73
- # and return the default value
74
- attr.default_value
69
+ # just return the default value
70
+ attr.converted_value(attr.default_value)
75
71
  end
76
72
  end
77
73
 
@@ -19,11 +19,6 @@ module Epuber
19
19
  super
20
20
  @attributes_values = {}
21
21
  @file_path = nil
22
-
23
- # iterate over all attributes to write default values
24
- self.class.dsl_attributes.each do |key, _attr|
25
- self.send(key)
26
- end
27
22
  end
28
23
 
29
24
  # @return [String]
@@ -71,7 +71,7 @@ mixin iterate_spine(toc_item)
71
71
 
72
72
 
73
73
  +section('Targets')
74
- - book.all_targets.each do |b_target|
74
+ - book.buildable_targets.each do |b_target|
75
75
  p(class: 'target_selected' if target == b_target): a(href: "/change_target/#{b_target.name}")= b_target.name
76
76
  - end
77
77
 
@@ -191,7 +191,13 @@ module Epuber
191
191
 
192
192
  comps = []
193
193
  comps << message.to_s
194
- comps << " (in file #{location.path} line #{location.lineno}" unless location.nil?
194
+ if !location.nil? && !(message.is_a?(Epuber::Compiler::Problem) || message.is_a?(Epuber::Checker::TextChecker::MatchProblem))
195
+ if location.lineno
196
+ comps << " (in file #{location.path} line #{location.lineno})"
197
+ else
198
+ comps << " (in file #{location.path})"
199
+ end
200
+ end
195
201
 
196
202
  comps.join("\n").ansi.send(_color_from_level(level))
197
203
  end
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Epuber
3
- VERSION = '0.5.3'
3
+ VERSION = '0.6.0'
4
4
 
5
5
  HOME_URL = 'https://github.com/epuber-io/epuber'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: epuber
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Kříž
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-12 00:00:00.000000000 Z
11
+ date: 2021-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '6.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '5.0'
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: addressable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.7'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: nokogiri
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -162,28 +176,28 @@ dependencies:
162
176
  requirements:
163
177
  - - "~>"
164
178
  - !ruby/object:Gem::Version
165
- version: '2.14'
179
+ version: '4.2'
166
180
  type: :runtime
167
181
  prerelease: false
168
182
  version_requirements: !ruby/object:Gem::Requirement
169
183
  requirements:
170
184
  - - "~>"
171
185
  - !ruby/object:Gem::Version
172
- version: '2.14'
186
+ version: '4.2'
173
187
  - !ruby/object:Gem::Dependency
174
188
  name: rubyzip
175
189
  requirement: !ruby/object:Gem::Requirement
176
190
  requirements:
177
191
  - - "~>"
178
192
  - !ruby/object:Gem::Version
179
- version: '1.0'
193
+ version: '2.3'
180
194
  type: :runtime
181
195
  prerelease: false
182
196
  version_requirements: !ruby/object:Gem::Requirement
183
197
  requirements:
184
198
  - - "~>"
185
199
  - !ruby/object:Gem::Version
186
- version: '1.0'
200
+ version: '2.3'
187
201
  - !ruby/object:Gem::Dependency
188
202
  name: epubcheck-ruby
189
203
  requirement: !ruby/object:Gem::Requirement
@@ -250,16 +264,16 @@ dependencies:
250
264
  name: bundler
251
265
  requirement: !ruby/object:Gem::Requirement
252
266
  requirements:
253
- - - "~>"
267
+ - - ">="
254
268
  - !ruby/object:Gem::Version
255
- version: '1.15'
269
+ version: '0'
256
270
  type: :development
257
271
  prerelease: false
258
272
  version_requirements: !ruby/object:Gem::Requirement
259
273
  requirements:
260
- - - "~>"
274
+ - - ">="
261
275
  - !ruby/object:Gem::Version
262
- version: '1.15'
276
+ version: '0'
263
277
  - !ruby/object:Gem::Dependency
264
278
  name: rspec
265
279
  requirement: !ruby/object:Gem::Requirement
@@ -280,43 +294,43 @@ dependencies:
280
294
  requirements:
281
295
  - - "~>"
282
296
  - !ruby/object:Gem::Version
283
- version: '0.49'
297
+ version: '1.14'
284
298
  type: :development
285
299
  prerelease: false
286
300
  version_requirements: !ruby/object:Gem::Requirement
287
301
  requirements:
288
302
  - - "~>"
289
303
  - !ruby/object:Gem::Version
290
- version: '0.49'
304
+ version: '1.14'
291
305
  - !ruby/object:Gem::Dependency
292
306
  name: rake
293
307
  requirement: !ruby/object:Gem::Requirement
294
308
  requirements:
295
309
  - - "~>"
296
310
  - !ruby/object:Gem::Version
297
- version: '12.2'
311
+ version: '13.0'
298
312
  type: :development
299
313
  prerelease: false
300
314
  version_requirements: !ruby/object:Gem::Requirement
301
315
  requirements:
302
316
  - - "~>"
303
317
  - !ruby/object:Gem::Version
304
- version: '12.2'
318
+ version: '13.0'
305
319
  - !ruby/object:Gem::Dependency
306
320
  name: fakefs
307
321
  requirement: !ruby/object:Gem::Requirement
308
322
  requirements:
309
323
  - - "~>"
310
324
  - !ruby/object:Gem::Version
311
- version: '0.6'
325
+ version: '1.3'
312
326
  type: :development
313
327
  prerelease: false
314
328
  version_requirements: !ruby/object:Gem::Requirement
315
329
  requirements:
316
330
  - - "~>"
317
331
  - !ruby/object:Gem::Version
318
- version: '0.6'
319
- description:
332
+ version: '1.3'
333
+ description:
320
334
  email:
321
335
  - samnung@gmail.com
322
336
  executables:
@@ -369,6 +383,7 @@ files:
369
383
  - lib/epuber/compiler/meta_inf_generator.rb
370
384
  - lib/epuber/compiler/nav_generator.rb
371
385
  - lib/epuber/compiler/opf_generator.rb
386
+ - lib/epuber/compiler/problem.rb
372
387
  - lib/epuber/compiler/xhtml_processor.rb
373
388
  - lib/epuber/config.rb
374
389
  - lib/epuber/dsl/attribute.rb
@@ -379,7 +394,6 @@ files:
379
394
  - lib/epuber/lockfile.rb
380
395
  - lib/epuber/plugin.rb
381
396
  - lib/epuber/ruby_extensions/match_data.rb
382
- - lib/epuber/ruby_extensions/string.rb
383
397
  - lib/epuber/ruby_extensions/thread.rb
384
398
  - lib/epuber/server.rb
385
399
  - lib/epuber/server/auto_refresh/auto_refresh.coffee
@@ -538,7 +552,7 @@ homepage: https://github.com/epuber-io/epuber
538
552
  licenses:
539
553
  - MIT
540
554
  metadata: {}
541
- post_install_message:
555
+ post_install_message:
542
556
  rdoc_options: []
543
557
  require_paths:
544
558
  - lib
@@ -546,16 +560,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
546
560
  requirements:
547
561
  - - ">="
548
562
  - !ruby/object:Gem::Version
549
- version: '2.3'
563
+ version: '2.5'
550
564
  required_rubygems_version: !ruby/object:Gem::Requirement
551
565
  requirements:
552
566
  - - ">="
553
567
  - !ruby/object:Gem::Version
554
568
  version: '0'
555
569
  requirements: []
556
- rubyforge_project:
557
- rubygems_version: 2.7.7
558
- signing_key:
570
+ rubygems_version: 3.2.17
571
+ signing_key:
559
572
  specification_version: 4
560
573
  summary: Epuber is simple tool to compile and pack source files into EPUB format.
561
574
  test_files: []
@@ -1,16 +0,0 @@
1
-
2
- begin
3
- require 'unicode_normalize'
4
- rescue LoadError
5
- # silently fail
6
-
7
- require 'active_support/multibyte/unicode'
8
-
9
- class String
10
- unless respond_to?(:unicode_normalize)
11
- def unicode_normalize
12
- ActiveSupport::Multibyte::Unicode.normalize(self)
13
- end
14
- end
15
- end
16
- end