audio_book_creator 0.0.1 → 0.2.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +2 -2
  4. data/CHANGELOG.md +24 -0
  5. data/Gemfile +3 -3
  6. data/README.md +9 -4
  7. data/audio_book_creator.gemspec +3 -3
  8. data/{bin → exe}/audio_book_creator +3 -0
  9. data/lib/audio_book_creator.rb +4 -2
  10. data/lib/audio_book_creator/binder.rb +2 -1
  11. data/lib/audio_book_creator/book_def.rb +2 -2
  12. data/lib/audio_book_creator/cached_hash.rb +1 -1
  13. data/lib/audio_book_creator/cascading_array.rb +8 -8
  14. data/lib/audio_book_creator/chapter.rb +1 -1
  15. data/lib/audio_book_creator/cli.rb +36 -29
  16. data/lib/audio_book_creator/conductor.rb +5 -3
  17. data/lib/audio_book_creator/defaulter.rb +41 -0
  18. data/lib/audio_book_creator/editor.rb +2 -3
  19. data/lib/audio_book_creator/page_db.rb +14 -8
  20. data/lib/audio_book_creator/page_def.rb +7 -15
  21. data/lib/audio_book_creator/runner.rb +5 -3
  22. data/lib/audio_book_creator/speaker.rb +1 -1
  23. data/lib/audio_book_creator/spider.rb +9 -28
  24. data/lib/audio_book_creator/surfer_def.rb +1 -5
  25. data/lib/audio_book_creator/url_filter.rb +1 -1
  26. data/lib/audio_book_creator/version.rb +1 -1
  27. data/lib/audio_book_creator/web_page.rb +49 -0
  28. data/run_mutant +89 -0
  29. data/spec/audio_book_creator/binder_spec.rb +3 -3
  30. data/spec/audio_book_creator/book_creator_spec.rb +2 -3
  31. data/spec/audio_book_creator/book_def_spec.rb +33 -22
  32. data/spec/audio_book_creator/cached_hash_spec.rb +4 -0
  33. data/spec/audio_book_creator/cli_spec.rb +189 -122
  34. data/spec/audio_book_creator/conductor_spec.rb +17 -6
  35. data/spec/audio_book_creator/defaulter_spec.rb +154 -0
  36. data/spec/audio_book_creator/editor_spec.rb +7 -7
  37. data/spec/audio_book_creator/page_db_spec.rb +73 -11
  38. data/spec/audio_book_creator/page_def_spec.rb +26 -40
  39. data/spec/audio_book_creator/speaker_spec.rb +2 -2
  40. data/spec/audio_book_creator/spider_spec.rb +10 -15
  41. data/spec/audio_book_creator/surfer_def_spec.rb +1 -4
  42. data/spec/audio_book_creator/url_filter_spec.rb +1 -1
  43. data/spec/audio_book_creator/web_page_spec.rb +65 -0
  44. data/spec/audio_book_creator_spec.rb +23 -0
  45. data/spec/spec_helper.rb +15 -12
  46. metadata +14 -20
@@ -16,4 +16,8 @@ describe AudioBookCreator::CachedHash do
16
16
  it { expect(subject[:key]).to eq("val") }
17
17
  it { subject[:key] ; expect(cache[:key]).to eq("val") }
18
18
  end
19
+
20
+ context "#with missing key" do
21
+ it { expect(subject[:key]).to be_nil }
22
+ end
19
23
  end
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'uri'
3
- require 'logger'
4
2
  # NOTE: cli class is not in the path by default
5
3
  # it is only included by running the command
6
4
  require 'audio_book_creator/cli'
@@ -8,8 +6,9 @@ require 'audio_book_creator/cli'
8
6
  describe AudioBookCreator::Cli do
9
7
  # this sidesteps creating a database file
10
8
  subject { described_class.new }
9
+ let(:minimal_args) { %w(http://site.com/title) }
11
10
 
12
- context "with no arguments" do
11
+ describe "#parse", "with no arguments" do
13
12
  it "displays an error" do
14
13
  expect($stdout).to receive(:puts).with(/url/, /Usage.*title/)
15
14
  expect(subject).to receive(:exit).with(2).and_raise("exited")
@@ -17,108 +16,50 @@ describe AudioBookCreator::Cli do
17
16
  end
18
17
  end
19
18
 
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))
19
+ describe "#parse" do
20
+ # not really part of this spec
21
+ it "defaults to non verbose" do
22
+ subject.parse(minimal_args)
29
23
  expect(AudioBookCreator.logger.level).to eq(Logger::WARN)
30
24
  end
31
- end
32
25
 
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))
26
+ it "sets to info" do
27
+ subject.parse(%w(http://site.com/title --no-verbose))
28
+ expect(AudioBookCreator.logger.level).to eq(Logger::WARN)
54
29
  end
55
- end
56
30
 
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
31
+ context "with verbose" do
32
+ it "sets to info" do
33
+ subject.parse(%w(http://site.com/title --verbose))
34
+ expect(AudioBookCreator.logger.level).to eq(Logger::INFO)
35
+ end
62
36
 
63
- it "defaults to warning" do
64
- subject.parse(%w(http://site.com/title -v))
65
- expect(AudioBookCreator.logger.level).to eq(Logger::INFO)
37
+ it "sets to info (abbreviated)" do
38
+ subject.parse(%w(http://site.com/title -v))
39
+ expect(AudioBookCreator.logger.level).to eq(Logger::INFO)
40
+ end
66
41
  end
67
- end
68
42
 
69
-
70
- context "#parse" do
71
43
  # 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")
44
+ it "can chain" do
45
+ expect(subject.parse(minimal_args)).to eq(subject)
103
46
  end
104
47
 
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")
48
+ it "provides usage" do
49
+ expect($stdout).to receive(:puts).with(/Usage: audio_book_creator.*\[title\] url/)
50
+ expect { subject.parse(%w(--help)) }.to raise_error(SystemExit)
108
51
  end
109
- end
110
52
 
111
- context "with version" do
112
- it "should provide version" do
53
+ it "provides version" do
113
54
  expect($stdout).to receive(:puts).with(/audio_book_creator #{AudioBookCreator::VERSION}/)
114
55
  expect { subject.parse(%w(--version)) }.to raise_error(SystemExit)
115
56
  end
116
- end
117
57
 
118
- context "#help" do
119
58
  {
120
59
  "-v" => "Run verbosely",
121
60
  "--verbose" => "Run verbosely",
61
+ "--default" => "Set these parameters as default for this url regular expression",
62
+ "--skip-defaults" => "Skip using defaults",
122
63
  "--title" => "Title css",
123
64
  "--body" => "Content css",
124
65
  "--link" => "Next Page css",
@@ -131,17 +72,16 @@ describe AudioBookCreator::Cli do
131
72
  "--voice" => "Set speaker voice",
132
73
  "--base-dir" => "Directory to hold files",
133
74
  "-A" => "Load book into itunes",
134
- "--itunes" => "Load book into itunes",
75
+ "--[no-]itunes" => "Load book into itunes",
135
76
  }.each do |switch, text|
136
77
  it "should display #{text} for #{switch} option" do
137
- expect($stdout).to receive(:puts).with(/#{switch}.*#{text}/)
78
+ expect($stdout).to receive(:puts).with(/#{Regexp.escape(switch)}.*#{text}/)
138
79
  expect { subject.parse(%w(--help)) }.to raise_error(SystemExit)
139
80
  end
140
81
  end
141
82
 
142
83
  it "should provide help" do
143
84
  expect($stdout).to receive(:puts).with(/Usage/)
144
- #expect(subject).to receive(:exit).with(1).and_raise("exited")
145
85
  expect { subject.parse(%w(--help)) }.to raise_error(SystemExit)
146
86
  end
147
87
 
@@ -151,41 +91,63 @@ describe AudioBookCreator::Cli do
151
91
  end
152
92
  end
153
93
 
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")
94
+ describe "#parse", "#set_defaults" do
95
+ it "defaults to no" do
96
+ subject.parse(minimal_args)
97
+ expect(subject.set_defaults).to be_falsey
98
+ end
99
+
100
+ it "sets to true" do
101
+ subject.parse(%w(http://site.com/title --default))
102
+ expect(subject.set_defaults).to eq(true)
103
+ end
104
+ end
105
+
106
+ describe "#parse", "#skip_defaults" do
107
+ it "defaults to no" do
108
+ subject.parse(minimal_args)
109
+ expect(subject.skip_defaults).to be_falsey
161
110
  end
162
111
 
163
- it "should support title" do
112
+ it "sets to true" do
113
+ subject.parse(%w(http://site.com/title --skip-defaults))
114
+ expect(subject.skip_defaults).to eq(true)
115
+ end
116
+ end
117
+
118
+ describe "#parse", "#page_def" do
119
+ it "#title" do
164
120
  subject.parse(%w(http://site.com/title --title h1.big))
165
121
  expect(subject.page_def.title_path).to eq("h1.big")
166
122
  end
167
123
 
168
- it "should support body" do
124
+ it "#body_path" do
169
125
  subject.parse(%w(http://site.com/title --body p.content))
170
126
  expect(subject.page_def.body_path).to eq("p.content")
171
127
  end
172
128
 
173
- it "should support link" do
129
+ it "#link_path" do
174
130
  subject.parse(%w(http://site.com/title --link a.next_page))
175
131
  expect(subject.page_def.link_path).to eq("a.next_page")
176
132
  end
133
+
134
+ it "#chapter_path" do
135
+ subject.parse(%w(http://site.com/title --chapter a.chapter))
136
+ expect(subject.page_def.chapter_path).to eq("a.chapter")
137
+ end
177
138
  end
178
139
 
179
- context "#book_def" do
140
+ context "#parse", "#book_def" do
180
141
  it "should create book_def" do
181
- subject.parse(%w(http://site.com/title))
142
+ subject.parse(minimal_args)
182
143
  # defaults
183
144
  expect(subject.book_def.base_dir).to eq("title")
184
145
  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
146
+ #expect(subject.book_def.author).to eq("Vicki")
147
+ #expect(subject.book_def.itunes).not_to be_truthy
187
148
  end
188
149
 
150
+ # MOVE to book_def
189
151
  it "should support basedir" do
190
152
  subject.parse(%w(http://site.com/title --base-dir dir))
191
153
  # defaults
@@ -196,17 +158,73 @@ describe AudioBookCreator::Cli do
196
158
  it "should set itunes" do
197
159
  subject.parse(%w(http://site.com/title -A))
198
160
  expect(subject.book_def.itunes).to be_truthy
161
+
162
+ subject.parse(%w(http://site.com/title --itunes))
163
+ expect(subject.book_def.itunes).to be_truthy
164
+ end
165
+
166
+ it "should unset itunes" do
167
+ subject.parse(%w(http://site.com/title --no-itunes))
168
+ expect(subject.book_def.itunes).to be_falsy
199
169
  end
200
170
 
201
171
  it "should pass all urls to book_def" do
202
172
  subject.parse(%w(http://site.com/title http://site.com/title http://site.com/title2))
203
173
  expect(subject.book_def.urls).to eq(%w(http://site.com/title http://site.com/title http://site.com/title2))
204
174
  end
175
+
176
+ describe "#title #urls" do
177
+ context "with url" do
178
+ it "assigns url abbreviation as title" do
179
+ subject.parse(minimal_args)
180
+ expect(subject.book_def.title).to eq("title")
181
+ expect(subject.book_def.urls).to eq(minimal_args)
182
+ end
183
+ end
184
+
185
+ context "with title and url" do
186
+ it "assigns title and url" do
187
+ subject.parse(%w(title http://site.com/))
188
+ expect(subject.book_def.title).to eq("title")
189
+ expect(subject.book_def.urls).to eq(%w(http://site.com/))
190
+ end
191
+ end
192
+
193
+ context "with multiple urls" do
194
+ it "assigns title and url" do
195
+ subject.parse(%w(http://site.com/title http://site.com/title2))
196
+ expect(subject.book_def.title).to eq("title")
197
+ expect(subject.book_def.urls).to eq(%w(http://site.com/title http://site.com/title2))
198
+ end
199
+ end
200
+
201
+ context "with title and multiple urls" do
202
+ it "has multiple urls" do
203
+ subject.parse(%w(title http://site.com/page1 http://site.com/page2))
204
+ expect(subject.book_def.title).to eq("title")
205
+ expect(subject.book_def.urls).to eq(%w(http://site.com/page1 http://site.com/page2))
206
+ end
207
+ end
208
+ end
209
+
210
+ # NOTE: file sanitization is tested in audio_book_creator.spec
211
+ describe "#base_dir" do
212
+ # MOVE to book_def
213
+ it "should support titles with spaces" do
214
+ subject.parse(["title !for", "http://site.com/"])
215
+ expect(subject.book_def.base_dir).to eq("title-for")
216
+ end
217
+
218
+ it "should override basedir" do
219
+ subject.parse(%w(title http://site.com/ --base-dir dir))
220
+ expect(subject.book_def.base_dir).to eq("dir")
221
+ end
222
+ end
205
223
  end
206
224
 
207
- context "#speaker_def" do
225
+ describe "#parse", "#speaker_def" do
208
226
  it "should default" do
209
- subject.parse(%w(http://site.com/title))
227
+ subject.parse(minimal_args)
210
228
  expect(subject.speaker_def.voice).to eq("Vicki")
211
229
  expect(subject.speaker_def.rate).to eq(280)
212
230
  expect(subject.speaker_def.channels).to eq(1)
@@ -232,43 +250,92 @@ describe AudioBookCreator::Cli do
232
250
  end
233
251
  end
234
252
 
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")
253
+ describe "#parse", "#surfer_def" do
254
+ it "defaults" do
255
+ subject.parse(minimal_args)
239
256
  end
240
- end
241
257
 
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)
258
+ context "#max" do
259
+ it "sets" do
260
+ subject.parse(%w(http://site.com/title --max 20))
261
+ expect(subject.surfer_def.max).to eq(20)
262
+ end
263
+
264
+ it "unsets" do
265
+ subject.parse(%w(http://site.com/title --max 20 --no-max))
266
+ expect(subject.surfer_def.max).not_to be_truthy
267
+ end
246
268
  end
247
269
 
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
270
+ context "#regen_html" do
271
+ it "sets" do
272
+ subject.parse(%w(http://site.com/title --force-html))
273
+ expect(subject.surfer_def.regen_html).to be_truthy
274
+ end
251
275
  end
252
276
  end
253
277
 
254
278
  describe "#conductor" do
255
279
  it "should create a conductor" do
256
- subject.parse(%w(http://site.com/title))
280
+ subject.parse(minimal_args)
257
281
  expect(subject.conductor.page_def).to eq(subject.page_def)
258
282
  expect(subject.conductor.book_def).to eq(subject.book_def)
259
283
  expect(subject.conductor.speaker_def).to eq(subject.speaker_def)
260
284
  expect(subject.conductor.surfer_def).to eq(subject.surfer_def)
261
285
  expect(subject.conductor).to respond_to(:run)
286
+ # this makes it not just look like the cli
287
+ expect(subject.conductor).to respond_to(:spider)
288
+ end
289
+ end
290
+
291
+ describe "#defaulter" do
292
+ it "creates a defaulter" do
293
+ subject.parse(minimal_args)
294
+ expect(subject.defaulter.page_def).to eq(subject.page_def)
295
+ expect(subject.defaulter.book_def).to eq(subject.book_def)
296
+ expect(subject.defaulter).to respond_to(:store)
262
297
  end
263
298
  end
264
299
 
265
300
  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)
301
+ it "call book conductor and loads from settings" do
302
+ subject.parse(minimal_args)
303
+ stub_component(:conductor) { |c| expect(c).to receive(:run).and_return("YAY") }
304
+ stub_component(:defaulter) { |d| expect(d).to receive(:load_unset_values) }
271
305
  expect(subject.run).to eq("YAY")
272
306
  end
307
+
308
+ it "call book conductor and loads from settings" do
309
+ subject.parse(minimal_args)
310
+ subject.skip_defaults = true
311
+ stub_component(:conductor) { |c| expect(c).to receive(:run).and_return("YAY") }
312
+ expect(subject).not_to receive(:defaulter)
313
+ expect(subject.run).to eq("YAY")
314
+ end
315
+
316
+ it "stores settings - and notify" do
317
+ subject.parse(minimal_args)
318
+ subject.set_defaults = true
319
+ expect($stdout).to receive(:puts).with("stored for host.com")
320
+ stub_component(:defaulter) do |d|
321
+ allow(d).to receive(:host).at_least(:once).and_return("host.com")
322
+ allow(d).to receive(:store).at_least(:once).and_return(true)
323
+ end
324
+ subject.run
325
+ end
326
+
327
+ it "stores settings - and notify failure" do
328
+ subject.parse(minimal_args)
329
+ subject.set_defaults = true
330
+ expect($stdout).to receive(:puts).with(/^not stored/)
331
+ stub_component(:defaulter) { |d| expect(d).to receive(:store).and_return(false) }
332
+ subject.run
333
+ end
334
+ end
335
+
336
+ def stub_component(name, &block)
337
+ dbl = double(name)
338
+ yield(dbl)
339
+ expect(subject).to receive(name).at_least(:once).and_return(dbl)
273
340
  end
274
341
  end
@@ -8,7 +8,7 @@ describe AudioBookCreator::Conductor do
8
8
  end
9
9
  end
10
10
  let(:speaker_def) { AudioBookCreator::SpeakerDef.new }
11
- let(:surfer_def) { AudioBookCreator::SurferDef.new("http://host.com/", 5, true, "database") }
11
+ let(:surfer_def) { AudioBookCreator::SurferDef.new(5, true) }
12
12
  subject { described_class.new(page_def, book_def, speaker_def, surfer_def) }
13
13
 
14
14
  context "#initialize" do
@@ -16,10 +16,21 @@ describe AudioBookCreator::Conductor do
16
16
  it { expect(subject.book_def).to eq(book_def) }
17
17
  it { expect(subject.speaker_def).to eq(speaker_def) }
18
18
  it { expect(subject.surfer_def).to eq(surfer_def) }
19
+ it { expect(subject.page_def.invalid_urls).to eq(subject.invalid_urls) }
19
20
  end
20
21
 
21
- context "#page_cache" do
22
- it { expect(subject.page_cache.filename).to eq(subject.surfer_def.cache_filename) }
22
+ describe "#page_cache" do
23
+ it "sets filename" do
24
+ expect(subject.page_cache.filename).to eq("pages.db")
25
+ end
26
+
27
+ it "sets table_name" do
28
+ expect(subject.page_cache.table_name).to eq("pages")
29
+ end
30
+
31
+ it "sets table_name" do
32
+ expect(subject.page_cache.encode).to eq(false)
33
+ end
23
34
  end
24
35
 
25
36
  context "#web" do
@@ -38,8 +49,9 @@ describe AudioBookCreator::Conductor do
38
49
 
39
50
  context "#invalid_urls" do
40
51
  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")
52
+ expect(subject.invalid_urls.host).to eq("www.host.com")
53
+ expect(subject.page_def.invalid_urls.host).to eq("www.host.com")
54
+ expect(subject.page_def.invalid_urls).to eq(subject.invalid_urls)
43
55
  end
44
56
  end
45
57
 
@@ -47,7 +59,6 @@ describe AudioBookCreator::Conductor do
47
59
  it "sets references" do
48
60
  expect(subject.spider.page_def).to eq(subject.page_def)
49
61
  expect(subject.spider.web).to eq(subject.cached_web)
50
- expect(subject.spider.invalid_urls).to eq(subject.invalid_urls)
51
62
  end
52
63
  end
53
64