epub_tools 0.6.0 → 0.9.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3 -8
  3. data/.gitignore +0 -1
  4. data/.tool-versions +1 -1
  5. data/CLAUDE.md +17 -25
  6. data/Gemfile +5 -8
  7. data/Gemfile.lock +60 -54
  8. data/README.md +31 -4
  9. data/bin/epub-tools +1 -3
  10. data/epub_tools.gemspec +3 -4
  11. data/lib/epub_tools/add_chapters.rb +17 -18
  12. data/lib/epub_tools/append_book.rb +8 -15
  13. data/lib/epub_tools/book_builder.rb +28 -22
  14. data/lib/epub_tools/chapter_order.rb +33 -0
  15. data/lib/epub_tools/chapter_validator.rb +6 -3
  16. data/lib/epub_tools/cli.rb +121 -23
  17. data/lib/epub_tools/compile_book.rb +1 -1
  18. data/lib/epub_tools/epub_initializer.rb +93 -99
  19. data/lib/epub_tools/pack_ebook.rb +2 -14
  20. data/lib/epub_tools/pdf_converter.rb +113 -0
  21. data/lib/epub_tools/pdf_layout.rb +116 -0
  22. data/lib/epub_tools/set_cover.rb +116 -0
  23. data/lib/epub_tools/split_chapters.rb +22 -20
  24. data/lib/epub_tools/style_finder.rb +11 -40
  25. data/lib/epub_tools/unpack_ebook.rb +2 -20
  26. data/lib/epub_tools/version.rb +1 -1
  27. data/lib/epub_tools/xhtml_cleaner.rb +4 -7
  28. data/lib/epub_tools/xhtml_extractor.rb +1 -7
  29. data/lib/epub_tools.rb +2 -1
  30. data/test/add_chapters_test.rb +64 -0
  31. data/test/append_book_test.rb +11 -11
  32. data/test/chapter_validator_test.rb +12 -0
  33. data/test/cli_test.rb +40 -3
  34. data/test/compile_book_test.rb +14 -0
  35. data/test/epub_initializer_test.rb +18 -0
  36. data/test/pdf_converter_test.rb +69 -0
  37. data/test/pdf_layout_test.rb +57 -0
  38. data/test/set_cover_test.rb +68 -0
  39. data/test/split_chapters_test.rb +18 -12
  40. data/test/style_finder_test.rb +3 -9
  41. data/test/test_helper.rb +1 -1
  42. data/test/unpack_ebook_test.rb +1 -1
  43. data/test/xhtml_cleaner_test.rb +1 -4
  44. metadata +14 -35
  45. data/lib/epub_tools/chapter_marker_detector.rb +0 -46
  46. data/lib/epub_tools/cli/command_options_configurator.rb +0 -128
  47. data/lib/epub_tools/cli/command_registry.rb +0 -49
  48. data/lib/epub_tools/cli/option_builder.rb +0 -166
  49. data/lib/epub_tools/cli/runner.rb +0 -114
  50. data/lib/epub_tools/compile_workspace.rb +0 -40
  51. data/lib/epub_tools/epub_configuration.rb +0 -33
  52. data/lib/epub_tools/epub_file_writer.rb +0 -57
  53. data/lib/epub_tools/epub_metadata_builder.rb +0 -92
  54. data/lib/epub_tools/xhtml_generator.rb +0 -71
  55. data/test/cli/command_registry_test.rb +0 -68
  56. data/test/cli/option_builder_test.rb +0 -183
  57. data/test/cli/runner_test.rb +0 -91
  58. data/test/compile_workspace_test.rb +0 -55
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'securerandom'
4
- require 'time'
5
-
6
- module EpubTools
7
- # Handles configuration parsing and setup for EPUB initialization
8
- class EpubConfiguration
9
- attr_reader :title, :author, :destination, :uuid, :modified,
10
- :cover_image_path, :cover_image_fname, :cover_image_media_type, :verbose
11
-
12
- def initialize(options = {})
13
- @title = options.fetch(:title)
14
- @author = options.fetch(:author)
15
- @destination = File.expand_path(options.fetch(:destination))
16
- @uuid = "urn:uuid:#{SecureRandom.uuid}"
17
- @modified = Time.now.utc.iso8601
18
- @cover_image_path = options[:cover_image]
19
- @cover_image_fname = nil
20
- @cover_image_media_type = nil
21
- @verbose = options[:verbose] || false
22
- end
23
-
24
- def cover_image?
25
- !@cover_image_path.nil?
26
- end
27
-
28
- def update_cover_info(fname, media_type)
29
- @cover_image_fname = fname
30
- @cover_image_media_type = media_type
31
- end
32
- end
33
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'fileutils'
4
-
5
- module EpubTools
6
- # Handles writing files for EPUB structure
7
- class EpubFileWriter
8
- def initialize(destination)
9
- @destination = destination
10
- end
11
-
12
- # Creates the basic EPUB directory structure
13
- def create_structure
14
- FileUtils.mkdir_p("#{@destination}/META-INF")
15
- FileUtils.mkdir_p("#{@destination}/OEBPS")
16
- end
17
-
18
- # Writes the mimetype file
19
- def write_mimetype
20
- File.write("#{@destination}/mimetype", 'application/epub+zip')
21
- end
22
-
23
- # Writes the container.xml file
24
- def write_container
25
- content = <<~XML
26
- <?xml version="1.0" encoding="UTF-8"?>
27
- <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
28
- <rootfiles>
29
- <rootfile full-path="OEBPS/package.opf" media-type="application/oebps-package+xml"/>
30
- </rootfiles>
31
- </container>
32
- XML
33
- File.write("#{@destination}/META-INF/container.xml", content)
34
- end
35
-
36
- # Writes XHTML content to a file
37
- def write_xhtml(filename, content)
38
- File.write(File.join(@destination, 'OEBPS', filename), content)
39
- end
40
-
41
- # Writes the package.opf file
42
- def write_package_opf(content)
43
- File.write(File.join(@destination, 'OEBPS', 'package.opf'), content)
44
- end
45
-
46
- # Copies the project style.css to EPUB structure
47
- def write_style
48
- src = File.join(Dir.pwd, 'style.css')
49
- dest = File.join(@destination, 'OEBPS', 'style.css')
50
- unless File.exist?(src)
51
- warn "Warning: style.css not found in project root (#{src}), skipping copy."
52
- return
53
- end
54
- FileUtils.cp(src, dest)
55
- end
56
- end
57
- end
@@ -1,92 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EpubTools
4
- # Builds metadata content for EPUB package.opf files
5
- class EpubMetadataBuilder
6
- def initialize(config)
7
- @config = config
8
- end
9
-
10
- # Builds complete metadata array
11
- def build_metadata
12
- metadata = []
13
- add_dublin_core_metadata(metadata)
14
- add_schema_metadata(metadata)
15
- add_cover_metadata(metadata) if @config.cover_image_fname
16
- metadata
17
- end
18
-
19
- # Builds manifest and spine items
20
- def build_manifest_and_spine
21
- manifest_items = []
22
- spine_items = []
23
-
24
- add_base_manifest_items(manifest_items)
25
- add_cover_items(manifest_items, spine_items) if @config.cover_image_fname
26
- add_title_items(manifest_items, spine_items)
27
-
28
- [manifest_items, spine_items]
29
- end
30
-
31
- # Builds complete OPF XML content
32
- def build_opf_xml(metadata, manifest_items, spine_items)
33
- <<~XML
34
- <?xml version="1.0" encoding="utf-8"?>
35
- <package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="pub-id" xml:lang="en">
36
- <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
37
- #{metadata.map { |line| " #{line}" }.join("\n")}
38
- </metadata>
39
- <manifest>
40
- #{manifest_items.map { |line| " #{line}" }.join("\n")}
41
- </manifest>
42
- <spine>
43
- #{spine_items.map { |line| " #{line}" }.join("\n")}
44
- </spine>
45
- </package>
46
- XML
47
- end
48
-
49
- private
50
-
51
- def add_dublin_core_metadata(metadata)
52
- metadata << %(<dc:identifier id="pub-id">#{@config.uuid}</dc:identifier>)
53
- metadata << %(<dc:title>#{@config.title}</dc:title>)
54
- metadata << %(<dc:creator>#{@config.author}</dc:creator>)
55
- metadata << '<dc:language>en</dc:language>'
56
- metadata << %(<meta property="dcterms:modified">#{@config.modified}</meta>)
57
- end
58
-
59
- def add_schema_metadata(metadata)
60
- metadata << %(<meta property="schema:accessMode">textual</meta>)
61
- metadata << %(<meta property="schema:accessibilityFeature">unknown</meta>)
62
- metadata << %(<meta property="schema:accessibilityHazard">none</meta>)
63
- metadata << %(<meta property="schema:accessModeSufficient">textual</meta>)
64
- end
65
-
66
- def add_cover_metadata(metadata)
67
- metadata << %(<meta name="cover" content="cover-image"/>)
68
- end
69
-
70
- def add_base_manifest_items(manifest_items)
71
- manifest_items << mitem('style', 'style.css', 'text/css')
72
- manifest_items << mitem('nav', 'nav.xhtml', 'application/xhtml+xml', 'nav')
73
- end
74
-
75
- def add_cover_items(manifest_items, spine_items)
76
- manifest_items << mitem('cover-image', @config.cover_image_fname, @config.cover_image_media_type, 'cover-image')
77
- manifest_items << mitem('cover-page', 'cover.xhtml', 'application/xhtml+xml')
78
- spine_items << '<itemref idref="cover-page"/>'
79
- end
80
-
81
- def add_title_items(manifest_items, spine_items)
82
- manifest_items << mitem('title', 'title.xhtml', 'application/xhtml+xml')
83
- spine_items << '<itemref idref="title"/>'
84
- end
85
-
86
- def mitem(id, href, type, properties = nil)
87
- xml = "<item id=\"#{id}\" href=\"#{href}\" media-type=\"#{type}\""
88
- xml += " properties=\"#{properties}\"" if properties
89
- "#{xml}/>"
90
- end
91
- end
92
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EpubTools
4
- # Generates XHTML content for EPUB files
5
- class XhtmlGenerator
6
- attr_accessor :cover_image_fname
7
-
8
- def initialize(title:, author:)
9
- @title = title
10
- @author = author
11
- @cover_image_fname = nil
12
- end
13
-
14
- # Generates title page XHTML content
15
- def build_title_page
16
- <<~XHTML
17
- <?xml version="1.0" encoding="UTF-8"?>
18
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
19
- <head>
20
- <meta charset="UTF-8" />
21
- <title>#{@title}</title>
22
- <link rel="stylesheet" type="text/css" href="style.css"/>
23
- </head>
24
- <body>
25
- <h1 class="title">#{@title}</h1>
26
- <p class="author">by #{@author}</p>
27
- </body>
28
- </html>
29
- XHTML
30
- end
31
-
32
- # Generates cover page XHTML content
33
- def build_cover_page
34
- <<~XHTML
35
- <?xml version="1.0" encoding="UTF-8"?>
36
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
37
- <head>
38
- <meta charset="UTF-8" />
39
- <title>Cover</title>
40
- <link rel="stylesheet" type="text/css" href="style.css"/>
41
- </head>
42
- <body>
43
- <div class="cover-image">
44
- <img src="#{@cover_image_fname}" alt="Cover"/>
45
- </div>
46
- </body>
47
- </html>
48
- XHTML
49
- end
50
-
51
- # Generates navigation XHTML content
52
- def build_nav_page
53
- <<~XHTML
54
- <?xml version="1.0" encoding="utf-8"?>
55
- <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en">
56
- <head>
57
- <title>Table of Contents</title>
58
- </head>
59
- <body>
60
- <nav epub:type="toc" id="toc">
61
- <h1>Table of Contents</h1>
62
- <ol>
63
- <li><a href="title.xhtml">Title Page</a></li>
64
- </ol>
65
- </nav>
66
- </body>
67
- </html>
68
- XHTML
69
- end
70
- end
71
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../test_helper'
4
- require_relative '../../lib/epub_tools'
5
-
6
- class CommandRegistryTest < Minitest::Test
7
- class DummyCommand
8
- attr_reader :options
9
-
10
- def initialize(options)
11
- @options = options
12
- end
13
-
14
- def run
15
- true
16
- end
17
- end
18
-
19
- def setup
20
- @registry = EpubTools::CLI::CommandRegistry.new
21
- end
22
-
23
- def test_registry_initializes_empty
24
- assert_empty @registry.commands
25
- assert_empty @registry.available_commands
26
- end
27
-
28
- def test_register_command
29
- @registry.register('test', DummyCommand, [:required_option], { default: 'value' })
30
-
31
- assert_equal 1, @registry.commands.size
32
- assert_includes @registry.available_commands, 'test'
33
-
34
- command = @registry.get('test')
35
-
36
- assert_equal DummyCommand, command[:class]
37
- assert_equal [:required_option], command[:required_keys]
38
- assert_equal({ default: 'value' }, command[:default_options])
39
- end
40
-
41
- def test_register_multiple_commands
42
- @registry.register('test1', DummyCommand)
43
- @registry.register('test2', DummyCommand)
44
-
45
- assert_equal 2, @registry.commands.size
46
- assert_includes @registry.available_commands, 'test1'
47
- assert_includes @registry.available_commands, 'test2'
48
- end
49
-
50
- def test_get_nonexistent_command
51
- assert_nil @registry.get('nonexistent')
52
- end
53
-
54
- def test_command_exists
55
- @registry.register('test', DummyCommand)
56
-
57
- assert @registry.command_exists?('test')
58
- refute @registry.command_exists?('nonexistent')
59
- end
60
-
61
- def test_chained_registration
62
- result = @registry.register('test1', DummyCommand)
63
- .register('test2', DummyCommand)
64
-
65
- assert_equal @registry, result
66
- assert_equal 2, @registry.commands.size
67
- end
68
- end
@@ -1,183 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../test_helper'
4
- require_relative '../../lib/epub_tools'
5
- require 'stringio'
6
-
7
- class OptionBuilderTest < Minitest::Test
8
- def setup
9
- @builder = EpubTools::CLI::OptionBuilder.new
10
- end
11
-
12
- def test_initialize_with_defaults
13
- builder = EpubTools::CLI::OptionBuilder.new({ default: 'value' }, [:required])
14
-
15
- assert_equal({ default: 'value' }, builder.options)
16
- assert_equal [:required], builder.required_keys
17
- end
18
-
19
- def test_with_banner
20
- @builder.with_banner('Test Banner')
21
-
22
- assert_equal 'Test Banner', @builder.parser.banner
23
- end
24
-
25
- def test_with_help_option
26
- # This test is tricky as --help would exit, so we'll test indirectly
27
- @builder.with_help_option
28
-
29
- assert_includes @builder.parser.to_s, '-h, --help'
30
- end
31
-
32
- def test_with_verbose_option
33
- @builder.with_verbose_option
34
-
35
- assert @builder.options[:verbose]
36
-
37
- # Parse args with --quiet to change verbose to false
38
- @builder.parse(['--quiet'])
39
-
40
- refute @builder.options[:verbose]
41
- end
42
-
43
- def test_with_input_file
44
- @builder.with_input_file('Test input')
45
-
46
- verify_parser_option_format('-i, --input-file FILE', 'Test input (required)')
47
-
48
- builder2 = EpubTools::CLI::OptionBuilder.new
49
- builder2.with_input_file('Test input', required: false)
50
-
51
- verify_optional_parser_format(builder2, 'Test input')
52
-
53
- @builder.parse(['-i', 'file.txt'])
54
-
55
- assert_equal 'file.txt', @builder.options[:input_file]
56
- end
57
-
58
- def test_with_input_dir
59
- @builder.with_input_dir('Test input dir')
60
-
61
- assert_includes @builder.parser.to_s, '-i, --input-dir DIR'
62
- assert_includes @builder.parser.to_s, 'Test input dir (required)'
63
-
64
- @builder.parse(['-i', 'dir/path'])
65
-
66
- assert_equal 'dir/path', @builder.options[:input_dir]
67
- end
68
-
69
- def test_with_output_dir
70
- @builder.with_output_dir('Test output dir', 'default/path')
71
-
72
- verify_parser_option_format('-o, --output-dir DIR', 'Test output dir (default: default/path)')
73
-
74
- assert_equal 'default/path', @builder.options[:output_dir]
75
-
76
- builder2 = EpubTools::CLI::OptionBuilder.new
77
- builder2.with_output_dir('Test output dir')
78
- verify_required_parser_format(builder2, 'Test output dir (required)')
79
-
80
- @builder.parse(['-o', 'new/path'])
81
-
82
- assert_equal 'new/path', @builder.options[:output_dir]
83
- end
84
-
85
- def test_with_output_file
86
- @builder.with_output_file('Test output file')
87
-
88
- assert_includes @builder.parser.to_s, '-o, --output-file FILE'
89
- assert_includes @builder.parser.to_s, 'Test output file (required)'
90
-
91
- @builder.parse(['-o', 'output.txt'])
92
-
93
- assert_equal 'output.txt', @builder.options[:output_file]
94
- end
95
-
96
- def test_with_title_option
97
- @builder.with_title_option
98
-
99
- assert_includes @builder.parser.to_s, '-t, --title TITLE'
100
- assert_includes @builder.parser.to_s, 'Book title (required)'
101
-
102
- @builder.parse(['-t', 'Book Title'])
103
-
104
- assert_equal 'Book Title', @builder.options[:title]
105
- end
106
-
107
- def test_with_author_option
108
- @builder.with_author_option
109
-
110
- assert_includes @builder.parser.to_s, '-a, --author AUTHOR'
111
- assert_includes @builder.parser.to_s, 'Author name (required)'
112
-
113
- @builder.parse(['-a', 'Author Name'])
114
-
115
- assert_equal 'Author Name', @builder.options[:author]
116
- end
117
-
118
- def test_with_cover_option
119
- @builder.with_cover_option
120
-
121
- assert_includes @builder.parser.to_s, '-c, --cover PATH'
122
- assert_includes @builder.parser.to_s, 'Cover image file path (optional)'
123
-
124
- @builder.parse(['-c', 'cover.jpg'])
125
-
126
- assert_equal 'cover.jpg', @builder.options[:cover_image]
127
- end
128
-
129
- def test_with_option
130
- @builder.with_option('-x', '--extra VALUE', 'Extra option', :extra_option)
131
-
132
- assert_includes @builder.parser.to_s, '-x, --extra VALUE'
133
- assert_includes @builder.parser.to_s, 'Extra option'
134
-
135
- @builder.parse(['-x', 'extra-value'])
136
-
137
- assert_equal 'extra-value', @builder.options[:extra_option]
138
- end
139
-
140
- def test_with_custom_options
141
- @builder.with_custom_options do |opts, options|
142
- opts.on('-c', '--custom VALUE', 'Custom option') { |v| options[:custom] = v }
143
- end
144
-
145
- assert_includes @builder.parser.to_s, '-c, --custom VALUE'
146
- assert_includes @builder.parser.to_s, 'Custom option'
147
-
148
- @builder.parse(['-c', 'custom-value'])
149
-
150
- assert_equal 'custom-value', @builder.options[:custom]
151
- end
152
-
153
- def test_parse_validates_required_keys
154
- builder = EpubTools::CLI::OptionBuilder.new({}, [:required_option])
155
- assert_output('', /Missing required options/) do
156
- assert_raises(SystemExit) { builder.parse([]) }
157
- end
158
- end
159
-
160
- def test_method_chaining
161
- result = @builder.with_banner('Test')
162
- .with_verbose_option
163
- .with_title_option
164
-
165
- assert_equal @builder, result
166
- end
167
-
168
- private
169
-
170
- def verify_parser_option_format(option_format, description)
171
- assert_includes @builder.parser.to_s, option_format
172
- assert_includes @builder.parser.to_s, description
173
- end
174
-
175
- def verify_optional_parser_format(builder, description)
176
- assert_includes builder.parser.to_s, description
177
- refute_includes builder.parser.to_s, "#{description} (required)"
178
- end
179
-
180
- def verify_required_parser_format(builder, description)
181
- assert_includes builder.parser.to_s, description
182
- end
183
- end
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../test_helper'
4
- require_relative '../../lib/epub_tools'
5
- require 'stringio'
6
-
7
- class RunnerTest < Minitest::Test
8
- class TestCommand
9
- attr_reader :options, :run_called
10
-
11
- def initialize(options)
12
- @options = options
13
- @run_called = false
14
- end
15
-
16
- def run
17
- @run_called = true
18
- puts 'Called!'
19
- true
20
- end
21
- end
22
-
23
- def setup
24
- @runner = EpubTools::CLI::Runner.new('test-program')
25
-
26
- # Register a test command
27
- @runner.registry.register('test-cmd', TestCommand,
28
- [:required_option],
29
- { default_option: 'default' })
30
- end
31
-
32
- def test_initialize
33
- assert_equal 'test-program', @runner.program_name
34
- assert_kind_of EpubTools::CLI::CommandRegistry, @runner.registry
35
- end
36
-
37
- def test_handle_command
38
- @runner.registry.register('add', TestCommand)
39
-
40
- assert_output(/Usage: test-program add/) do
41
- assert_raises(SystemExit) { @runner.handle_command('add', ['-h']) }
42
- end
43
- end
44
-
45
- def test_handle_command_with_required_args
46
- runner = EpubTools::CLI::Runner.new('test-program')
47
- runner.registry.register('add', TestCommand)
48
-
49
- assert_output("Called!\n") { assert runner.handle_command('add') }
50
- end
51
-
52
- def test_handle_nonexistent_command
53
- result = @runner.handle_command('nonexistent')
54
-
55
- refute result # Should return false for nonexistent command
56
- end
57
-
58
- def test_run_with_version_flag
59
- assert_output(/^\d+\.\d+\.\d+$/) do
60
- assert_raises(SystemExit) { @runner.run(['-v']) }
61
- end
62
- end
63
-
64
- def test_run_with_no_args_shows_usage
65
- assert_output(/Usage: test-program COMMAND \[options\]/) do
66
- assert_raises(SystemExit) { @runner.run([]) }
67
- end
68
- end
69
-
70
- def test_program_name_defaults_to_current_program
71
- default_runner = EpubTools::CLI::Runner.new
72
-
73
- assert_equal File.basename($PROGRAM_NAME), default_runner.program_name
74
- end
75
-
76
- def test_configure_command_options
77
- # Test command configuration through public interface
78
- @runner.registry.register('add', TestCommand)
79
-
80
- # Should show help without errors
81
- assert_output(/Usage: test-program add/) do
82
- assert_raises(SystemExit) { @runner.handle_command('add', ['-h']) }
83
- end
84
- end
85
-
86
- def test_run_with_unknown_command
87
- assert_output(/Usage: test-program COMMAND \[options\]/) do
88
- assert_raises(SystemExit) { @runner.run(['unknown-command']) }
89
- end
90
- end
91
- end
@@ -1,55 +0,0 @@
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