audio_book_creator 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +4 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +8 -0
  6. data/README.md +60 -0
  7. data/Rakefile +8 -0
  8. data/audio_book_creator.gemspec +31 -0
  9. data/bin/audio_book_creator +6 -0
  10. data/lib/audio_book_creator.rb +59 -0
  11. data/lib/audio_book_creator/binder.rb +61 -0
  12. data/lib/audio_book_creator/book_creator.rb +31 -0
  13. data/lib/audio_book_creator/book_def.rb +36 -0
  14. data/lib/audio_book_creator/cached_hash.rb +20 -0
  15. data/lib/audio_book_creator/cascading_array.rb +57 -0
  16. data/lib/audio_book_creator/chapter.rb +33 -0
  17. data/lib/audio_book_creator/cli.rb +119 -0
  18. data/lib/audio_book_creator/conductor.rb +67 -0
  19. data/lib/audio_book_creator/editor.rb +20 -0
  20. data/lib/audio_book_creator/logging.rb +7 -0
  21. data/lib/audio_book_creator/page_db.rb +42 -0
  22. data/lib/audio_book_creator/page_def.rb +31 -0
  23. data/lib/audio_book_creator/runner.rb +22 -0
  24. data/lib/audio_book_creator/speaker.rb +54 -0
  25. data/lib/audio_book_creator/speaker_def.rb +39 -0
  26. data/lib/audio_book_creator/spider.rb +60 -0
  27. data/lib/audio_book_creator/spoken_chapter.rb +16 -0
  28. data/lib/audio_book_creator/surfer_def.rb +15 -0
  29. data/lib/audio_book_creator/url_filter.rb +33 -0
  30. data/lib/audio_book_creator/version.rb +3 -0
  31. data/lib/audio_book_creator/web.rb +44 -0
  32. data/spec/audio_book_creator/binder_spec.rb +103 -0
  33. data/spec/audio_book_creator/book_creator_spec.rb +63 -0
  34. data/spec/audio_book_creator/book_def_spec.rb +61 -0
  35. data/spec/audio_book_creator/cached_hash_spec.rb +19 -0
  36. data/spec/audio_book_creator/cascading_array_spec.rb +64 -0
  37. data/spec/audio_book_creator/chapter_spec.rb +80 -0
  38. data/spec/audio_book_creator/cli_spec.rb +274 -0
  39. data/spec/audio_book_creator/conductor_spec.rb +102 -0
  40. data/spec/audio_book_creator/editor_spec.rb +39 -0
  41. data/spec/audio_book_creator/logging_spec.rb +21 -0
  42. data/spec/audio_book_creator/page_db_spec.rb +74 -0
  43. data/spec/audio_book_creator/page_def_spec.rb +79 -0
  44. data/spec/audio_book_creator/runner_spec.rb +65 -0
  45. data/spec/audio_book_creator/speaker_def_spec.rb +39 -0
  46. data/spec/audio_book_creator/speaker_spec.rb +105 -0
  47. data/spec/audio_book_creator/spider_spec.rb +172 -0
  48. data/spec/audio_book_creator/spoken_chapter_spec.rb +30 -0
  49. data/spec/audio_book_creator/surfer_def_spec.rb +17 -0
  50. data/spec/audio_book_creator/url_filter_spec.rb +52 -0
  51. data/spec/audio_book_creator/version_spec.rb +5 -0
  52. data/spec/audio_book_creator/web_spec.rb +66 -0
  53. data/spec/audio_book_creator_spec.rb +25 -0
  54. data/spec/spec_helper.rb +106 -0
  55. data/spec/support/test_logger.rb +21 -0
  56. metadata +238 -0
@@ -0,0 +1,80 @@
1
+ require "spec_helper"
2
+
3
+ describe AudioBookCreator::Chapter do
4
+ subject { described_class.new(number: 1, title: "title1", body: ["body1"]) }
5
+
6
+ it "should set number" do
7
+ expect(subject.number).to eq(1)
8
+ end
9
+
10
+ it "should set title" do
11
+ expect(subject.title).to eq("title1")
12
+ end
13
+
14
+ it "should set body" do
15
+ expect(subject.body).to eq("body1")
16
+ end
17
+
18
+ it "should support string body (mostly for tests)" do
19
+ expect(described_class.new(body: "body1").body).to eq("body1")
20
+ end
21
+
22
+ it "should support string multiple body entries" do
23
+ expect(described_class.new(body: ["body1", nil, "body2"]).body).to eq("body1\n\nbody2")
24
+ end
25
+
26
+ it "should support other values for number, title, and body" do
27
+ other = described_class.new(number: 2, title: "title2")
28
+ expect(other.number).to eq(2)
29
+ expect(other.title).to eq("title2")
30
+ end
31
+
32
+ it "should set filename" do
33
+ expect(subject.filename).to eq("chapter01")
34
+ end
35
+
36
+ # this is how the values are currently passed from page_def into chapter
37
+ describe "#to_s" do
38
+ context "with dom nodes" do
39
+ subject { described_class.new(number: 1, title: "title1", body: dom_nodes("body1")) }
40
+ it "should support dom nodes with to_s" do
41
+ expect(subject.to_s).to eq("title1\n\nbody1\n")
42
+ end
43
+ end
44
+
45
+ it "should provide to_s" do
46
+ expect(subject.to_s).to eq("title1\n\nbody1\n")
47
+ end
48
+ end
49
+
50
+ it { expect(subject).not_to be_empty }
51
+ it { expect(subject).to be_present }
52
+ it { expect(described_class.new).to be_empty }
53
+ it { expect(described_class.new).not_to be_present }
54
+
55
+ describe "#eq1" do
56
+ it "should understand ==" do
57
+ expect(subject).to eq(Class.new(described_class).new(number: 1.0, title: "title1", body: "body1"))
58
+ end
59
+
60
+ it "should understand != nil" do
61
+ expect(subject).not_to eq(nil)
62
+ end
63
+
64
+ it "should understand != different class" do
65
+ expect(subject).not_to eq("abc")
66
+ end
67
+
68
+ it "should understand != number" do
69
+ expect(subject).not_to eq(described_class.new(number: 2, title: "title1", body: "body1"))
70
+ end
71
+
72
+ it "should understand != title" do
73
+ expect(subject).not_to eq(described_class.new(number: 1, title: "title2", body: "body1"))
74
+ end
75
+
76
+ it "should understand != body" do
77
+ expect(subject).not_to eq(described_class.new(number: 1, title: "title1", body: "body2"))
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,274 @@
1
+ require 'spec_helper'
2
+ require 'uri'
3
+ require 'logger'
4
+ # NOTE: cli class is not in the path by default
5
+ # it is only included by running the command
6
+ require 'audio_book_creator/cli'
7
+
8
+ describe AudioBookCreator::Cli do
9
+ # this sidesteps creating a database file
10
+ subject { described_class.new }
11
+
12
+ context "with no arguments" do
13
+ it "displays an error" do
14
+ expect($stdout).to receive(:puts).with(/url/, /Usage.*title/)
15
+ expect(subject).to receive(:exit).with(2).and_raise("exited")
16
+ expect { subject.parse([]) }.to raise_error("exited")
17
+ end
18
+ end
19
+
20
+ context "with one argument" do
21
+ it "assigns title and url" do
22
+ subject.parse(%w(http://site.com/title))
23
+ expect(subject.book_def.title).to eq("title")
24
+ expect(subject.book_def.urls).to eq(%w(http://site.com/title))
25
+ end
26
+
27
+ it "defaults to warn" do
28
+ subject.parse(%w(http://site.com/title))
29
+ expect(AudioBookCreator.logger.level).to eq(Logger::WARN)
30
+ end
31
+ end
32
+
33
+ context "with title and url" do
34
+ it "assigns title and url" do
35
+ subject.parse(%w(title http://site.com/))
36
+ expect(subject.book_def.title).to eq("title")
37
+ expect(subject.book_def.urls).to eq(%w(http://site.com/))
38
+ end
39
+ end
40
+
41
+ context "with multiple urls" do
42
+ it "assigns title and url" do
43
+ subject.parse(%w(http://site.com/title http://site.com/title2))
44
+ expect(subject.book_def.title).to eq("title")
45
+ expect(subject.book_def.urls).to eq(%w(http://site.com/title http://site.com/title2))
46
+ end
47
+ end
48
+
49
+ context "with title and multiple urls" do
50
+ it "has multiple urls" do
51
+ subject.parse(%w(title http://site.com/page1 http://site.com/page2))
52
+ expect(subject.book_def.title).to eq("title")
53
+ expect(subject.book_def.urls).to eq(%w(http://site.com/page1 http://site.com/page2))
54
+ end
55
+ end
56
+
57
+ context "with verbose" do
58
+ it "defaults to warning logging" do
59
+ subject.parse(%w(http://site.com/title --verbose))
60
+ expect(AudioBookCreator.logger.level).to eq(Logger::INFO)
61
+ end
62
+
63
+ it "defaults to warning" do
64
+ subject.parse(%w(http://site.com/title -v))
65
+ expect(AudioBookCreator.logger.level).to eq(Logger::INFO)
66
+ end
67
+ end
68
+
69
+
70
+ context "#parse" do
71
+ # actual cli calls subject.parse.run, so it needs to chain
72
+ it { expect(subject.parse(%w(http://site.com/title))).to eq(subject) }
73
+ end
74
+
75
+ # parameters
76
+
77
+ context "#defaults" do
78
+ it "should default values" do
79
+ # NOTE: calling with no constructor
80
+ pristine = described_class.new
81
+ expect(subject.surfer_def.max).not_to be_truthy
82
+ expect(subject.page_def.title_path).to eq("h1")
83
+ expect(subject.page_def.body_path).to eq("p")
84
+ expect(subject.page_def.link_path).to eq("a")
85
+ end
86
+ end
87
+
88
+ # file sanitization is tested in audio_book_creator.spec
89
+ context "#base_dir" do
90
+ it "should derive base_dir from title" do
91
+ subject.parse(%w(title http://site.com/))
92
+ expect(subject.book_def.base_dir).to eq("title")
93
+ end
94
+
95
+ it "should support titles with spaces" do
96
+ subject.parse(["title !for", "http://site.com/"])
97
+ expect(subject.book_def.base_dir).to eq("title-for")
98
+ end
99
+
100
+ it "should support titles with extra stuff" do
101
+ subject.parse(["title,for!", "http://site.com/"])
102
+ expect(subject.book_def.base_dir).to eq("title-for")
103
+ end
104
+
105
+ it "should override basedir" do
106
+ subject.parse(%w(title http://site.com/ --base-dir dir))
107
+ expect(subject.book_def.base_dir).to eq("dir")
108
+ end
109
+ end
110
+
111
+ context "with version" do
112
+ it "should provide version" do
113
+ expect($stdout).to receive(:puts).with(/audio_book_creator #{AudioBookCreator::VERSION}/)
114
+ expect { subject.parse(%w(--version)) }.to raise_error(SystemExit)
115
+ end
116
+ end
117
+
118
+ context "#help" do
119
+ {
120
+ "-v" => "Run verbosely",
121
+ "--verbose" => "Run verbosely",
122
+ "--title" => "Title css",
123
+ "--body" => "Content css",
124
+ "--link" => "Next Page css",
125
+ "--chapter" => "Next Chapter css",
126
+ "--no-max" => "Don't limit the number of pages to visit",
127
+ "--max" => "Maximum number of pages to visit",
128
+ "--force-audio" => "Regerate the audio",
129
+ "--force-html" => "Regerate the audio",
130
+ "--rate" => "Set words per minute",
131
+ "--voice" => "Set speaker voice",
132
+ "--base-dir" => "Directory to hold files",
133
+ "-A" => "Load book into itunes",
134
+ "--itunes" => "Load book into itunes",
135
+ }.each do |switch, text|
136
+ it "should display #{text} for #{switch} option" do
137
+ expect($stdout).to receive(:puts).with(/#{switch}.*#{text}/)
138
+ expect { subject.parse(%w(--help)) }.to raise_error(SystemExit)
139
+ end
140
+ end
141
+
142
+ it "should provide help" do
143
+ expect($stdout).to receive(:puts).with(/Usage/)
144
+ #expect(subject).to receive(:exit).with(1).and_raise("exited")
145
+ expect { subject.parse(%w(--help)) }.to raise_error(SystemExit)
146
+ end
147
+
148
+ it "should provide help (with short option)" do
149
+ expect($stdout).to receive(:puts).with(/Usage/)
150
+ expect { subject.parse(%w(-h)) }.to raise_error(SystemExit)
151
+ end
152
+ end
153
+
154
+ context "#page_def" do
155
+ it "should create page_def" do
156
+ subject.parse(%w(http://site.com/title))
157
+ # defaults
158
+ expect(subject.page_def.title_path).to eq("h1")
159
+ expect(subject.page_def.body_path).to eq("p")
160
+ expect(subject.page_def.link_path).to eq("a")
161
+ end
162
+
163
+ it "should support title" do
164
+ subject.parse(%w(http://site.com/title --title h1.big))
165
+ expect(subject.page_def.title_path).to eq("h1.big")
166
+ end
167
+
168
+ it "should support body" do
169
+ subject.parse(%w(http://site.com/title --body p.content))
170
+ expect(subject.page_def.body_path).to eq("p.content")
171
+ end
172
+
173
+ it "should support link" do
174
+ subject.parse(%w(http://site.com/title --link a.next_page))
175
+ expect(subject.page_def.link_path).to eq("a.next_page")
176
+ end
177
+ end
178
+
179
+ context "#book_def" do
180
+ it "should create book_def" do
181
+ subject.parse(%w(http://site.com/title))
182
+ # defaults
183
+ expect(subject.book_def.base_dir).to eq("title")
184
+ expect(subject.book_def.title).to eq("title")
185
+ expect(subject.book_def.author).to eq("Vicki")
186
+ expect(subject.book_def.itunes).not_to be_truthy
187
+ end
188
+
189
+ it "should support basedir" do
190
+ subject.parse(%w(http://site.com/title --base-dir dir))
191
+ # defaults
192
+ expect(subject.book_def.base_dir).to eq("dir")
193
+ expect(subject.book_def.title).to eq("title")
194
+ end
195
+
196
+ it "should set itunes" do
197
+ subject.parse(%w(http://site.com/title -A))
198
+ expect(subject.book_def.itunes).to be_truthy
199
+ end
200
+
201
+ it "should pass all urls to book_def" do
202
+ subject.parse(%w(http://site.com/title http://site.com/title http://site.com/title2))
203
+ expect(subject.book_def.urls).to eq(%w(http://site.com/title http://site.com/title http://site.com/title2))
204
+ end
205
+ end
206
+
207
+ context "#speaker_def" do
208
+ it "should default" do
209
+ subject.parse(%w(http://site.com/title))
210
+ expect(subject.speaker_def.voice).to eq("Vicki")
211
+ expect(subject.speaker_def.rate).to eq(280)
212
+ expect(subject.speaker_def.channels).to eq(1)
213
+ expect(subject.speaker_def.max_hours).to eq(7)
214
+ expect(subject.speaker_def.bit_rate).to eq(32)
215
+ expect(subject.speaker_def.sample_rate).to eq(22_050)
216
+ expect(subject.speaker_def.regen_audio).not_to be_truthy
217
+ end
218
+
219
+ it "should set voice" do
220
+ subject.parse(%w(http://site.com/title --voice Serena))
221
+ expect(subject.speaker_def.voice).to eq("Serena")
222
+ end
223
+
224
+ it "should set rate" do
225
+ subject.parse(%w(http://site.com/title --rate 200))
226
+ expect(subject.speaker_def.rate).to eq(200)
227
+ end
228
+
229
+ it "should set force" do
230
+ subject.parse(%w(http://site.com/title --force-audio))
231
+ expect(subject.speaker_def.regen_audio).to be_truthy
232
+ end
233
+ end
234
+
235
+ context "#surfer_def" do
236
+ it "assigns cache_filename" do
237
+ subject.parse(%w(http://site.com/title))
238
+ expect(subject.surfer_def.cache_filename).to eq("pages.db")
239
+ end
240
+ end
241
+
242
+ context "max param" do
243
+ it "should have a max" do
244
+ subject.parse(%w(http://site.com/title --max 20))
245
+ expect(subject.surfer_def.max).to eq(20)
246
+ end
247
+
248
+ it "should have no max" do
249
+ subject.parse(%w(http://site.com/title --max 20 --no-max))
250
+ expect(subject.surfer_def.max).not_to be_truthy
251
+ end
252
+ end
253
+
254
+ describe "#conductor" do
255
+ it "should create a conductor" do
256
+ subject.parse(%w(http://site.com/title))
257
+ expect(subject.conductor.page_def).to eq(subject.page_def)
258
+ expect(subject.conductor.book_def).to eq(subject.book_def)
259
+ expect(subject.conductor.speaker_def).to eq(subject.speaker_def)
260
+ expect(subject.conductor.surfer_def).to eq(subject.surfer_def)
261
+ expect(subject.conductor).to respond_to(:run)
262
+ end
263
+ end
264
+
265
+ describe "#run" do
266
+ it "should call book conductor" do
267
+ subject.parse(%w(http://site.com/title))
268
+ conductor = double(:conductor)
269
+ expect(conductor).to receive(:run).and_return("YAY")
270
+ expect(subject).to receive(:conductor).and_return(conductor)
271
+ expect(subject.run).to eq("YAY")
272
+ end
273
+ end
274
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ describe AudioBookCreator::Conductor do
4
+ let(:page_def) { AudioBookCreator::PageDef.new("h1.title", "div", "a.link", "a.chapter") }
5
+ let(:book_def) do
6
+ AudioBookCreator::BookDef.new("the title", "author", "dir", %w(a b), true).tap do |bd|
7
+ bd.urls = %w(http://www.host.com/ http://www.host.com/)
8
+ end
9
+ end
10
+ let(:speaker_def) { AudioBookCreator::SpeakerDef.new }
11
+ let(:surfer_def) { AudioBookCreator::SurferDef.new("http://host.com/", 5, true, "database") }
12
+ subject { described_class.new(page_def, book_def, speaker_def, surfer_def) }
13
+
14
+ context "#initialize" do
15
+ it { expect(subject.page_def).to eq(page_def) }
16
+ it { expect(subject.book_def).to eq(book_def) }
17
+ it { expect(subject.speaker_def).to eq(speaker_def) }
18
+ it { expect(subject.surfer_def).to eq(surfer_def) }
19
+ end
20
+
21
+ context "#page_cache" do
22
+ it { expect(subject.page_cache.filename).to eq(subject.surfer_def.cache_filename) }
23
+ end
24
+
25
+ context "#web" do
26
+ it "sets references" do
27
+ expect(subject.web.max).to eq(subject.surfer_def.max)
28
+ end
29
+ end
30
+
31
+ context "#cached_web" do
32
+ it "sets references" do
33
+ expect(subject.cached_web.cache).to eq(subject.page_cache)
34
+ expect(subject.cached_web.main).to eq(subject.web)
35
+ expect(subject.cached_web).to respond_to(:main)
36
+ end
37
+ end
38
+
39
+ context "#invalid_urls" do
40
+ it "sets references" do
41
+ #expect(subject.invalid_urls.host).to eq(subject.surfer_def.host)
42
+ expect(subject.invalid_urls.host).to eq("host.com")
43
+ end
44
+ end
45
+
46
+ context "#spider" do
47
+ it "sets references" do
48
+ expect(subject.spider.page_def).to eq(subject.page_def)
49
+ expect(subject.spider.web).to eq(subject.cached_web)
50
+ expect(subject.spider.invalid_urls).to eq(subject.invalid_urls)
51
+ end
52
+ end
53
+
54
+ context "#editor" do
55
+ it "sets references" do
56
+ expect(subject.editor.page_def).to eq(subject.page_def)
57
+ # needs to be an editor
58
+ expect(subject.editor).to respond_to(:parse)
59
+ # hack
60
+ expect(subject.editor).not_to eq(subject)
61
+ end
62
+ end
63
+
64
+ context "#speaker" do
65
+ it "should create speaker" do
66
+ expect(subject.speaker.speaker_def).to eq(subject.speaker_def)
67
+ expect(subject.speaker.book_def).to eq(subject.book_def)
68
+ expect(subject.speaker).to respond_to(:say)
69
+ end
70
+ end
71
+
72
+ context "#binder" do
73
+ it "should create a binder" do
74
+ expect(subject.binder.book_def).to eq(subject.book_def)
75
+ expect(subject.binder.speaker_def).to eq(subject.speaker_def)
76
+ expect(subject.binder).to respond_to(:create)
77
+ end
78
+ end
79
+
80
+ describe "#creator" do
81
+ it "should create a book creator" do
82
+ expect(subject.creator.spider).to eq(subject.spider)
83
+ expect(subject.creator.editor).to eq(subject.editor)
84
+ expect(subject.creator.speaker).to eq(subject.speaker)
85
+ expect(subject.creator.binder).to eq(subject.binder)
86
+ expect(subject.creator).to respond_to(:create)
87
+ end
88
+ end
89
+
90
+ describe "#outstanding" do
91
+ it "should set outstanding" do
92
+ expect(subject.outstanding).to eq(book_def.unique_urls)
93
+ end
94
+ end
95
+
96
+ describe "#run" do
97
+ it do
98
+ expect(subject.creator).to receive(:create).with(subject.outstanding)
99
+ subject.run
100
+ end
101
+ end
102
+ end