epub_tools 0.4.0 → 0.5.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3 -0
  3. data/.gitignore +1 -1
  4. data/.rubocop.yml +10 -17
  5. data/.tool-versions +1 -0
  6. data/CLAUDE.md +124 -0
  7. data/Gemfile +4 -4
  8. data/Gemfile.lock +44 -37
  9. data/README.md +10 -6
  10. data/Rakefile +2 -0
  11. data/bin/epub-tools +2 -0
  12. data/epub_tools.gemspec +3 -1
  13. data/lib/epub_tools/add_chapters.rb +48 -30
  14. data/lib/epub_tools/chapter_validator.rb +40 -0
  15. data/lib/epub_tools/cli/command_options_configurator.rb +115 -0
  16. data/lib/epub_tools/cli/command_registry.rb +2 -0
  17. data/lib/epub_tools/cli/option_builder.rb +5 -3
  18. data/lib/epub_tools/cli/runner.rb +59 -110
  19. data/lib/epub_tools/cli.rb +16 -29
  20. data/lib/epub_tools/compile_book.rb +48 -65
  21. data/lib/epub_tools/compile_workspace.rb +40 -0
  22. data/lib/epub_tools/epub_configuration.rb +33 -0
  23. data/lib/epub_tools/epub_file_writer.rb +57 -0
  24. data/lib/epub_tools/epub_initializer.rb +83 -162
  25. data/lib/epub_tools/epub_metadata_builder.rb +92 -0
  26. data/lib/epub_tools/loggable.rb +2 -0
  27. data/lib/epub_tools/pack_ebook.rb +28 -14
  28. data/lib/epub_tools/split_chapters.rb +42 -17
  29. data/lib/epub_tools/style_finder.rb +17 -6
  30. data/lib/epub_tools/unpack_ebook.rb +20 -10
  31. data/lib/epub_tools/version.rb +3 -1
  32. data/lib/epub_tools/xhtml_cleaner.rb +1 -0
  33. data/lib/epub_tools/xhtml_extractor.rb +20 -10
  34. data/lib/epub_tools/xhtml_generator.rb +71 -0
  35. data/lib/epub_tools.rb +2 -0
  36. data/test/add_chapters_test.rb +50 -26
  37. data/test/chapter_validator_test.rb +47 -0
  38. data/test/cli/command_registry_test.rb +2 -0
  39. data/test/cli/option_builder_test.rb +24 -14
  40. data/test/cli/runner_test.rb +15 -15
  41. data/test/cli_commands_test.rb +3 -1
  42. data/test/cli_test.rb +2 -0
  43. data/test/cli_version_test.rb +2 -0
  44. data/test/compile_book_test.rb +17 -102
  45. data/test/compile_workspace_test.rb +55 -0
  46. data/test/epub_initializer_test.rb +55 -27
  47. data/test/pack_ebook_test.rb +33 -9
  48. data/test/split_chapters_test.rb +27 -7
  49. data/test/style_finder_test.rb +2 -0
  50. data/test/test_helper.rb +2 -0
  51. data/test/unpack_ebook_test.rb +45 -20
  52. data/test/xhtml_cleaner_test.rb +2 -0
  53. data/test/xhtml_extractor_test.rb +3 -1
  54. metadata +15 -5
  55. data/.ruby-version +0 -1
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'test_helper'
2
4
  require_relative '../lib/epub_tools/compile_book'
3
5
 
@@ -11,7 +13,7 @@ class CompileBookTest < Minitest::Test
11
13
  end
12
14
 
13
15
  def teardown
14
- FileUtils.remove_entry(@tmp)
16
+ FileUtils.rm_rf(@tmp)
15
17
  end
16
18
 
17
19
  def test_default_output_file
@@ -67,39 +69,6 @@ class CompileBookTest < Minitest::Test
67
69
  refute cb.verbose
68
70
  end
69
71
 
70
- def test_clean_build_dir_removes_directory
71
- build = File.join(@tmp, 'build')
72
- FileUtils.mkdir_p(build)
73
- File.write(File.join(build, 'foo'), 'bar')
74
- cb = EpubTools::CompileBook.new(
75
- title: @title,
76
- author: @author,
77
- source_dir: @source,
78
- build_dir: build
79
- )
80
-
81
- assert Dir.exist?(build)
82
- cb.send(:clean_build_dir)
83
-
84
- refute Dir.exist?(build)
85
- end
86
-
87
- def test_prepare_dirs_creates_xhtml_and_chapters_directories
88
- build = File.join(@tmp, 'build')
89
- cb = EpubTools::CompileBook.new(
90
- title: @title,
91
- author: @author,
92
- source_dir: @source,
93
- build_dir: build
94
- )
95
- cb.send(:prepare_dirs)
96
- xhtml_dir = cb.send(:xhtml_dir)
97
- chapters_dir = cb.send(:chapters_dir)
98
-
99
- assert Dir.exist?(xhtml_dir)
100
- assert Dir.exist?(chapters_dir)
101
- end
102
-
103
72
  def test_log_outputs_when_verbose
104
73
  cb = EpubTools::CompileBook.new(
105
74
  title: @title,
@@ -122,81 +91,27 @@ class CompileBookTest < Minitest::Test
122
91
  assert_silent { cb.send(:log, 'hello') }
123
92
  end
124
93
 
125
- def test_validate_sequence_raises_when_no_chapters
126
- cb = EpubTools::CompileBook.new(
127
- title: @title,
128
- author: @author,
129
- source_dir: @source,
130
- build_dir: @tmp
131
- )
132
- FileUtils.mkdir_p(cb.send(:chapters_dir))
133
- err = assert_raises(RuntimeError) { cb.send(:validate_sequence) }
134
- assert_match(/No chapter files found/, err.message)
135
- end
136
-
137
- def test_validate_sequence_raises_on_missing_chapters
138
- build = File.join(@tmp, 'build')
94
+ def test_run_completes_workflow
95
+ # Test that run method executes the complete workflow
139
96
  cb = EpubTools::CompileBook.new(
140
97
  title: @title,
141
98
  author: @author,
142
99
  source_dir: @source,
143
- build_dir: build
100
+ build_dir: @tmp,
101
+ output_file: 'test.epub'
144
102
  )
145
- chapters = cb.send(:chapters_dir)
146
- FileUtils.mkdir_p(chapters)
147
- File.write(File.join(chapters, 'chap_1.xhtml'), '')
148
- File.write(File.join(chapters, 'chap_3.xhtml'), '')
149
- err = assert_raises(RuntimeError) { cb.send(:validate_sequence) }
150
- assert_match(/Missing chapter numbers: 2/, err.message)
151
- end
152
103
 
153
- def test_validate_sequence_succeeds_on_complete_sequence
154
- build = File.join(@tmp, 'build')
155
- cb = EpubTools::CompileBook.new(
156
- title: @title,
157
- author: @author,
158
- source_dir: @source,
159
- build_dir: build
160
- )
161
- chapters = cb.send(:chapters_dir)
162
- FileUtils.mkdir_p(chapters)
163
- File.write(File.join(chapters, 'chap_1.xhtml'), '')
164
- File.write(File.join(chapters, 'chap_2.xhtml'), '')
165
- File.write(File.join(chapters, 'chap_3.xhtml'), '')
104
+ # Mock the workflow methods to avoid complex file setup
105
+ def cb.extract_xhtmls; end
106
+ def cb.split_xhtmls; end
107
+ def cb.validate_chapters; end
108
+ def cb.initialize_epub; end
109
+ def cb.add_chapters; end
110
+ def cb.pack_epub; end
166
111
 
167
- assert_nil cb.send(:validate_sequence)
168
- end
112
+ # Should complete without error
113
+ result = cb.run
169
114
 
170
- def test_run_calls_all_steps_in_order
171
- cb = EpubTools::CompileBook.new(
172
- title: @title,
173
- author: @author,
174
- source_dir: @source,
175
- build_dir: @tmp,
176
- output_file: 'o.epub'
177
- )
178
- seq = []
179
- cb.define_singleton_method(:clean_build_dir) { seq << :clean }
180
- cb.define_singleton_method(:prepare_dirs) { seq << :prepare }
181
- cb.define_singleton_method(:extract_xhtmls) { seq << :extract }
182
- cb.define_singleton_method(:split_xhtmls) { seq << :split }
183
- cb.define_singleton_method(:validate_sequence) { seq << :validate }
184
- cb.define_singleton_method(:initialize_epub) { seq << :init }
185
- cb.define_singleton_method(:add_chapters) { seq << :add }
186
- cb.define_singleton_method(:pack_epub) { seq << :pack }
187
- cb.define_singleton_method(:log) { |msg| seq << [:log, msg] }
188
- cb.run
189
- expected = [
190
- :clean, :prepare, :extract, :split,
191
- :validate, :init, :add, :pack,
192
- [:log, /Done\. Output EPUB: .*o\.epub/],
193
- :clean
194
- ]
195
-
196
- assert_equal expected[0..7], seq[0..7]
197
- assert_kind_of Array, seq[8]
198
- assert_equal :log, seq[8][0]
199
- assert_match expected[8][1], seq[8][1]
200
- assert_equal expected[9], seq[9]
115
+ assert_equal 'test.epub', result
201
116
  end
202
117
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'test_helper'
4
+ require_relative '../lib/epub_tools/compile_workspace'
5
+
6
+ class CompileWorkspaceTest < Minitest::Test
7
+ def setup
8
+ @tmp = Dir.mktmpdir
9
+ @workspace = EpubTools::CompileWorkspace.new(@tmp)
10
+ end
11
+
12
+ def teardown
13
+ FileUtils.rm_rf(@tmp)
14
+ end
15
+
16
+ def test_initialize_sets_build_dir
17
+ assert_equal @tmp, @workspace.build_dir
18
+ end
19
+
20
+ def test_prepare_directories_creates_required_dirs
21
+ @workspace.prepare_directories
22
+
23
+ assert Dir.exist?(@workspace.xhtml_dir)
24
+ assert Dir.exist?(@workspace.chapters_dir)
25
+ end
26
+
27
+ def test_directory_paths_are_correct
28
+ assert_equal File.join(@tmp, 'xhtml'), @workspace.xhtml_dir
29
+ assert_equal File.join(@tmp, 'chapters'), @workspace.chapters_dir
30
+ assert_equal File.join(@tmp, 'epub'), @workspace.epub_dir
31
+ end
32
+
33
+ def test_directory_paths_are_memoized
34
+ # First call creates the path
35
+ path1 = @workspace.xhtml_dir
36
+ # Second call should return the same object
37
+ path2 = @workspace.xhtml_dir
38
+
39
+ assert_equal path1, path2
40
+ end
41
+
42
+ def test_clean_removes_build_directory
43
+ # Create the directory and some content
44
+ FileUtils.mkdir_p(@tmp)
45
+ test_file = File.join(@tmp, 'test.txt')
46
+ File.write(test_file, 'test content')
47
+
48
+ assert Dir.exist?(@tmp)
49
+ assert_path_exists test_file
50
+
51
+ @workspace.clean
52
+
53
+ refute Dir.exist?(@tmp)
54
+ end
55
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'test_helper'
2
4
  require_relative '../lib/epub_tools/epub_initializer'
3
5
 
@@ -16,34 +18,10 @@ class EpubInitializerTest < Minitest::Test
16
18
  def test_run_creates_basic_structure
17
19
  result = EpubTools::EpubInitializer.new(title: @title, author: @author, destination: @dest).run
18
20
 
19
- # Check return value is the destination directory
20
21
  assert_equal @dest, result
21
-
22
- # Check directories
23
- assert Dir.exist?(@dest)
24
- assert File.directory?(File.join(@dest, 'META-INF'))
25
- assert File.directory?(File.join(@dest, 'OEBPS'))
26
- # Check files
27
- mimetype = File.join(@dest, 'mimetype')
28
-
29
- assert_path_exists mimetype
30
- assert_equal 'application/epub+zip', File.read(mimetype)
31
- assert_path_exists File.join(@dest, 'META-INF', 'container.xml')
32
- assert_path_exists File.join(@dest, 'OEBPS', 'title.xhtml')
33
- assert_path_exists File.join(@dest, 'OEBPS', 'nav.xhtml')
34
- assert_path_exists File.join(@dest, 'OEBPS', 'package.opf')
35
- assert_path_exists File.join(@dest, 'OEBPS', 'style.css')
36
- # Check content of title.xhtml
37
- title_page = File.read(File.join(@dest, 'OEBPS', 'title.xhtml'))
38
-
39
- assert_includes title_page, "<h1 class=\"title\">#{@title}</h1>"
40
- assert_includes title_page, "<p class=\"author\">by #{@author}</p>"
41
- # Check package.opf metadata
42
- opf = File.read(File.join(@dest, 'OEBPS', 'package.opf'))
43
-
44
- assert_includes opf, "<dc:title>#{@title}</dc:title>"
45
- assert_includes opf, "<dc:creator>#{@author}</dc:creator>"
46
- refute_includes opf, 'cover.xhtml'
22
+ verify_directory_structure
23
+ verify_required_files
24
+ verify_file_contents
47
25
  end
48
26
 
49
27
  def test_run_with_cover_image
@@ -136,4 +114,54 @@ class EpubInitializerTest < Minitest::Test
136
114
 
137
115
  refute_includes opf, 'cover-image'
138
116
  end
117
+
118
+ private
119
+
120
+ def verify_directory_structure
121
+ assert Dir.exist?(@dest)
122
+ assert File.directory?(File.join(@dest, 'META-INF'))
123
+ assert File.directory?(File.join(@dest, 'OEBPS'))
124
+ end
125
+
126
+ def verify_required_files
127
+ required_files = [
128
+ 'mimetype',
129
+ File.join('META-INF', 'container.xml'),
130
+ File.join('OEBPS', 'title.xhtml'),
131
+ File.join('OEBPS', 'nav.xhtml'),
132
+ File.join('OEBPS', 'package.opf'),
133
+ File.join('OEBPS', 'style.css')
134
+ ]
135
+
136
+ required_files.each do |file|
137
+ assert_path_exists File.join(@dest, file)
138
+ end
139
+ end
140
+
141
+ def verify_file_contents
142
+ verify_mimetype_content
143
+ verify_title_page_content
144
+ verify_opf_metadata
145
+ end
146
+
147
+ def verify_mimetype_content
148
+ mimetype = File.read(File.join(@dest, 'mimetype'))
149
+
150
+ assert_equal 'application/epub+zip', mimetype
151
+ end
152
+
153
+ def verify_title_page_content
154
+ title_page = File.read(File.join(@dest, 'OEBPS', 'title.xhtml'))
155
+
156
+ assert_includes title_page, "<h1 class=\"title\">#{@title}</h1>"
157
+ assert_includes title_page, "<p class=\"author\">by #{@author}</p>"
158
+ end
159
+
160
+ def verify_opf_metadata
161
+ opf = File.read(File.join(@dest, 'OEBPS', 'package.opf'))
162
+
163
+ assert_includes opf, "<dc:title>#{@title}</dc:title>"
164
+ assert_includes opf, "<dc:creator>#{@author}</dc:creator>"
165
+ refute_includes opf, 'cover.xhtml'
166
+ end
139
167
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'test_helper'
2
4
  require_relative '../lib/epub_tools/pack_ebook'
3
5
  require 'zip'
@@ -14,37 +16,59 @@ class PackEbookTest < Minitest::Test
14
16
  end
15
17
 
16
18
  def test_run_creates_epub_with_expected_entries
17
- # Create minimal EPUB directory
19
+ create_minimal_epub_structure
20
+ output = File.join(@tmp, 'out.epub')
21
+ result = EpubTools::PackEbook.new(input_dir: @epub_dir, output_file: output).run
22
+
23
+ verify_return_value(output, result)
24
+ verify_epub_entries(output)
25
+ end
26
+
27
+ private
28
+
29
+ def create_minimal_epub_structure
18
30
  File.write(File.join(@epub_dir, 'mimetype'), 'application/epub+zip')
19
31
  FileUtils.mkdir_p(File.join(@epub_dir, 'META-INF'))
20
32
  File.write(File.join(@epub_dir, 'META-INF', 'container.xml'), '<container/>')
21
33
  FileUtils.mkdir_p(File.join(@epub_dir, 'OEBPS'))
22
34
  File.write(File.join(@epub_dir, 'OEBPS', 'title.xhtml'), '<html/>')
35
+ end
23
36
 
24
- output = File.join(@tmp, 'out.epub')
25
- result = EpubTools::PackEbook.new(input_dir: @epub_dir, output_file: output).run
37
+ def verify_return_value(expected_output, result)
38
+ assert_equal expected_output, result
39
+ assert_path_exists expected_output, 'Expected output EPUB to exist'
40
+ end
41
+
42
+ def verify_epub_entries(output_file)
43
+ entries = extract_zip_entries(output_file)
44
+ verify_mimetype_entry(entries)
45
+ verify_expected_files(entries)
46
+ end
26
47
 
27
- # Check return value is the output file path
28
- assert_equal output, result
29
- assert_path_exists output, 'Expected output EPUB to exist'
48
+ def extract_zip_entries(output_file)
30
49
  entries = []
31
- Zip::File.open(output) do |zip|
50
+ Zip::File.open(output_file) do |zip|
32
51
  zip.each do |entry|
33
52
  entries << { name: entry.name, compression: entry.compression_method }
34
53
  end
35
54
  end
55
+ entries
56
+ end
36
57
 
37
- # First entry should be mimetype, stored without compression
58
+ def verify_mimetype_entry(entries)
38
59
  assert_equal 'mimetype', entries.first[:name]
39
60
  assert_equal 0, entries.first[:compression]
61
+ end
40
62
 
41
- # Check presence of other files
63
+ def verify_expected_files(entries)
42
64
  names = entries.map { |e| e[:name] }
43
65
 
44
66
  assert_includes names, 'META-INF/container.xml'
45
67
  assert_includes names, 'OEBPS/title.xhtml'
46
68
  end
47
69
 
70
+ public
71
+
48
72
  def test_missing_input_dir_raises_error
49
73
  assert_raises(ArgumentError) do
50
74
  EpubTools::PackEbook.new(input_dir: File.join(@tmp, 'nonexistent'), output_file: 'out.epub').run
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'test_helper'
2
4
  require_relative '../lib/epub_tools/split_chapters'
3
5
 
@@ -30,10 +32,19 @@ class SplitChaptersTest < Minitest::Test
30
32
  result = EpubTools::SplitChapters.new(input_file: @input, book_title: 'BookTitle', output_dir: @out,
31
33
  output_prefix: 'chap').run
32
34
 
33
- # Check return value is an array of chapter file paths
35
+ verify_return_value(result)
36
+ verify_generated_files_exist(result)
37
+ verify_chapter_contents
38
+ end
39
+
40
+ private
41
+
42
+ def verify_return_value(result)
34
43
  assert_instance_of Array, result
35
44
  assert_equal 3, result.size
45
+ end
36
46
 
47
+ def verify_generated_files_exist(result)
37
48
  expected_paths = [
38
49
  File.join(@out, 'chap_0.xhtml'),
39
50
  File.join(@out, 'chap_1.xhtml'),
@@ -47,25 +58,34 @@ class SplitChaptersTest < Minitest::Test
47
58
 
48
59
  files = Dir.children(@out)
49
60
 
50
- assert_includes files, 'chap_0.xhtml'
51
- assert_includes files, 'chap_1.xhtml'
52
- assert_includes files, 'chap_2.xhtml'
61
+ ['chap_0.xhtml', 'chap_1.xhtml', 'chap_2.xhtml'].each do |file|
62
+ assert_includes files, file
63
+ end
64
+ end
65
+
66
+ def verify_chapter_contents
67
+ verify_prologue_content
68
+ verify_chapter_one_content
69
+ verify_chapter_two_content
70
+ end
53
71
 
54
- # Prologue
72
+ def verify_prologue_content
55
73
  prologue = File.read(File.join(@out, 'chap_0.xhtml'))
56
74
 
57
75
  assert_includes prologue, '<h1>Prologue</h1>'
58
76
  assert_includes prologue, 'Intro text'
59
77
  refute_includes prologue, 'Chapter 1'
78
+ end
60
79
 
61
- # Chapter 1
80
+ def verify_chapter_one_content
62
81
  ch1 = File.read(File.join(@out, 'chap_1.xhtml'))
63
82
 
64
83
  assert_includes ch1, '<h1>Chapter 1</h1>'
65
84
  assert_includes ch1, 'First paragraph'
66
85
  refute_includes ch1, 'Chapter 2'
86
+ end
67
87
 
68
- # Chapter 2
88
+ def verify_chapter_two_content
69
89
  ch2 = File.read(File.join(@out, 'chap_2.xhtml'))
70
90
 
71
91
  assert_includes ch2, '<h1>Chapter 2</h1>'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
  require_relative 'test_helper'
3
5
  require_relative '../lib/epub_tools/style_finder'
data/test/test_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'simplecov'
2
4
  SimpleCov.start do
3
5
  add_filter '/test/'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'test_helper'
2
4
  require_relative '../lib/epub_tools/unpack_ebook'
3
5
  require 'zip'
@@ -5,37 +7,60 @@ require 'zip'
5
7
  class UnpackEbookTest < Minitest::Test
6
8
  def setup
7
9
  @tmp = Dir.mktmpdir
8
- # Build a minimal EPUB directory for zipping
9
10
  @build_dir = File.join(@tmp, 'build')
11
+ @epub_file = File.join(@tmp, 'test.epub')
12
+ @dest_dir = File.join(@tmp, 'output')
13
+
14
+ create_epub_build_directory
15
+ create_zip_file_from_build_dir
16
+ end
17
+
18
+ private
19
+
20
+ def create_epub_build_directory
10
21
  FileUtils.mkdir_p(File.join(@build_dir, 'META-INF'))
11
22
  FileUtils.mkdir_p(File.join(@build_dir, 'OEBPS'))
23
+
24
+ write_epub_files
25
+ end
26
+
27
+ def write_epub_files
12
28
  File.write(File.join(@build_dir, 'mimetype'), 'application/epub+zip')
13
29
  File.write(File.join(@build_dir, 'META-INF', 'container.xml'), '<container/>')
14
30
  File.write(File.join(@build_dir, 'OEBPS', 'title.xhtml'), '<html/>')
31
+ end
15
32
 
16
- # Create .epub zip file
17
- @epub_file = File.join(@tmp, 'test.epub')
18
- # Create .epub zip file with absolute src paths to avoid cwd issues
19
- Zip::File.open(@epub_file, Zip::File::CREATE) do |zip|
20
- # Add mimetype first, uncompressed
21
- mime_src = File.join(@build_dir, 'mimetype')
22
- zip.add_stored('mimetype', mime_src)
23
- # Add directories and files
24
- Dir.glob(File.join(@build_dir, '**', '*'), File::FNM_DOTMATCH).sort.each do |src_path|
25
- rel_path = src_path.sub(%r{^#{Regexp.escape(@build_dir)}/?}, '')
26
- next if rel_path.empty? || rel_path == 'mimetype'
27
-
28
- if File.directory?(src_path)
29
- zip.mkdir(rel_path)
30
- else
31
- zip.add(rel_path, src_path)
32
- end
33
- end
33
+ def create_zip_file_from_build_dir
34
+ Zip::File.open(@epub_file, create: true) do |zip|
35
+ add_mimetype_to_zip(zip)
36
+ add_remaining_files_to_zip(zip)
34
37
  end
38
+ end
35
39
 
36
- @dest_dir = File.join(@tmp, 'output')
40
+ def add_mimetype_to_zip(zip)
41
+ mime_src = File.join(@build_dir, 'mimetype')
42
+ zip.add_stored('mimetype', mime_src)
43
+ end
44
+
45
+ def add_remaining_files_to_zip(zip)
46
+ Dir.glob(File.join(@build_dir, '**', '*'), File::FNM_DOTMATCH).sort.each do |src_path|
47
+ add_file_or_directory_to_zip(zip, src_path)
48
+ end
37
49
  end
38
50
 
51
+ def add_file_or_directory_to_zip(zip, src_path)
52
+ rel_path = src_path.sub(%r{^#{Regexp.escape(@build_dir)}/?}, '')
53
+ return if rel_path.empty? || rel_path == 'mimetype'
54
+
55
+ if File.directory?(src_path)
56
+ zip.mkdir(rel_path)
57
+ else
58
+ zip.add(rel_path, src_path)
59
+ end
60
+ end
61
+
62
+ public
63
+
39
64
  def teardown
40
65
  FileUtils.remove_entry(@tmp)
41
66
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
  require_relative 'test_helper'
3
5
  require_relative '../lib/epub_tools/xhtml_cleaner'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'test_helper'
2
4
  require 'zip'
3
5
  require_relative '../lib/epub_tools/xhtml_extractor'
@@ -9,7 +11,7 @@ class XHTMLExtractorTest < Minitest::Test
9
11
  @tgt = File.join(@tmp, 'tgt')
10
12
  Dir.mkdir(@src)
11
13
  @file = File.join(@src, 'sample.epub')
12
- Zip::File.open(@file, Zip::File::CREATE) do |zip|
14
+ Zip::File.open(@file, create: true) do |zip|
13
15
  zip.get_output_stream('chapter1.xhtml') { |f| f.write '<html><body><p>One</p></body></html>' }
14
16
  zip.get_output_stream('nav.xhtml') { |f| f.write '<html><body>Nav</body></html>' }
15
17
  zip.get_output_stream('folder/ch2.xhtml') { |f| f.write '<html><body><p>Two</p></body></html>' }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: epub_tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaime Rodas
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '2.4'
46
+ version: '3.2'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '2.4'
53
+ version: '3.2'
54
54
  email:
55
55
  - rodas@hey.com
56
56
  executables:
@@ -63,7 +63,8 @@ files:
63
63
  - ".gitignore"
64
64
  - ".nova/Configuration.json"
65
65
  - ".rubocop.yml"
66
- - ".ruby-version"
66
+ - ".tool-versions"
67
+ - CLAUDE.md
67
68
  - Gemfile
68
69
  - Gemfile.lock
69
70
  - LICENSE
@@ -73,12 +74,18 @@ files:
73
74
  - epub_tools.gemspec
74
75
  - lib/epub_tools.rb
75
76
  - lib/epub_tools/add_chapters.rb
77
+ - lib/epub_tools/chapter_validator.rb
76
78
  - lib/epub_tools/cli.rb
79
+ - lib/epub_tools/cli/command_options_configurator.rb
77
80
  - lib/epub_tools/cli/command_registry.rb
78
81
  - lib/epub_tools/cli/option_builder.rb
79
82
  - lib/epub_tools/cli/runner.rb
80
83
  - lib/epub_tools/compile_book.rb
84
+ - lib/epub_tools/compile_workspace.rb
85
+ - lib/epub_tools/epub_configuration.rb
86
+ - lib/epub_tools/epub_file_writer.rb
81
87
  - lib/epub_tools/epub_initializer.rb
88
+ - lib/epub_tools/epub_metadata_builder.rb
82
89
  - lib/epub_tools/loggable.rb
83
90
  - lib/epub_tools/pack_ebook.rb
84
91
  - lib/epub_tools/split_chapters.rb
@@ -87,8 +94,10 @@ files:
87
94
  - lib/epub_tools/version.rb
88
95
  - lib/epub_tools/xhtml_cleaner.rb
89
96
  - lib/epub_tools/xhtml_extractor.rb
97
+ - lib/epub_tools/xhtml_generator.rb
90
98
  - style.css
91
99
  - test/add_chapters_test.rb
100
+ - test/chapter_validator_test.rb
92
101
  - test/cli/command_registry_test.rb
93
102
  - test/cli/option_builder_test.rb
94
103
  - test/cli/runner_test.rb
@@ -96,6 +105,7 @@ files:
96
105
  - test/cli_test.rb
97
106
  - test/cli_version_test.rb
98
107
  - test/compile_book_test.rb
108
+ - test/compile_workspace_test.rb
99
109
  - test/epub_initializer_test.rb
100
110
  - test/pack_ebook_test.rb
101
111
  - test/split_chapters_test.rb
@@ -125,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
135
  - !ruby/object:Gem::Version
126
136
  version: '0'
127
137
  requirements: []
128
- rubygems_version: 3.6.7
138
+ rubygems_version: 3.7.0
129
139
  specification_version: 4
130
140
  summary: Tools to extract, split, and compile EPUB books
131
141
  test_files: []
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 3.4.3