audio-feed-manager 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.
- checksums.yaml +7 -0
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Guardfile +17 -0
- data/LICENSE.txt +22 -0
- data/README.md +86 -0
- data/Rakefile +2 -0
- data/audio-feed-manager.gemspec +32 -0
- data/bin/afm +5 -0
- data/lib/audio-feed-manager.rb +1 -0
- data/lib/audio_feed_manager/application.rb +39 -0
- data/lib/audio_feed_manager/audio_file.rb +9 -0
- data/lib/audio_feed_manager/audio_file_adder.rb +14 -0
- data/lib/audio_feed_manager/audio_file_repository.rb +42 -0
- data/lib/audio_feed_manager/cli/add_audio_file.rb +39 -0
- data/lib/audio_feed_manager/cli/add_feed.rb +20 -0
- data/lib/audio_feed_manager/cli/arguments.rb +27 -0
- data/lib/audio_feed_manager/cli/arguments_parser.rb +67 -0
- data/lib/audio_feed_manager/cli/arguments_specification.rb +103 -0
- data/lib/audio_feed_manager/cli/command.rb +23 -0
- data/lib/audio_feed_manager/cli/commands_list.rb +120 -0
- data/lib/audio_feed_manager/cli/get_feed_url.rb +20 -0
- data/lib/audio_feed_manager/cli/initialize_project.rb +44 -0
- data/lib/audio_feed_manager/cli/list_feeds.rb +38 -0
- data/lib/audio_feed_manager/cli/publish.rb +21 -0
- data/lib/audio_feed_manager/cli/show_feed.rb +44 -0
- data/lib/audio_feed_manager/cli/update_feed_rss.rb +19 -0
- data/lib/audio_feed_manager/cli.rb +19 -0
- data/lib/audio_feed_manager/config.rb +5 -0
- data/lib/audio_feed_manager/config_repository.rb +14 -0
- data/lib/audio_feed_manager/console.rb +28 -0
- data/lib/audio_feed_manager/directory_lister.rb +9 -0
- data/lib/audio_feed_manager/error.rb +4 -0
- data/lib/audio_feed_manager/feed.rb +9 -0
- data/lib/audio_feed_manager/feed_items_repository.rb +30 -0
- data/lib/audio_feed_manager/feed_repository.rb +32 -0
- data/lib/audio_feed_manager/feed_syncer.rb +20 -0
- data/lib/audio_feed_manager/file_storage.rb +20 -0
- data/lib/audio_feed_manager/id3_tags.rb +14 -0
- data/lib/audio_feed_manager/new_model_creator.rb +15 -0
- data/lib/audio_feed_manager/rss_generator.rb +10 -0
- data/lib/audio_feed_manager/rss_repository.rb +36 -0
- data/lib/audio_feed_manager/s3_gateway.rb +39 -0
- data/lib/audio_feed_manager/secret_token_generator.rb +9 -0
- data/lib/audio_feed_manager/stop_application.rb +4 -0
- data/lib/audio_feed_manager/support/getter_setter_method.rb +18 -0
- data/lib/audio_feed_manager/support/hash_constructor.rb +9 -0
- data/lib/audio_feed_manager/tags.rb +9 -0
- data/lib/audio_feed_manager/unique_id_generator.rb +19 -0
- data/lib/audio_feed_manager/url_maker.rb +13 -0
- data/lib/audio_feed_manager/version.rb +3 -0
- data/lib/audio_feed_manager.rb +57 -0
- data/spec/audio_feed_manager/audio_file_adder_spec.rb +49 -0
- data/spec/audio_feed_manager/audio_file_repository_spec.rb +58 -0
- data/spec/audio_feed_manager/cli/add_audio_file_spec.rb +44 -0
- data/spec/audio_feed_manager/cli/add_feed_spec.rb +27 -0
- data/spec/audio_feed_manager/cli/arguments_parser_spec.rb +85 -0
- data/spec/audio_feed_manager/cli/arguments_specification_spec.rb +51 -0
- data/spec/audio_feed_manager/cli/commands_list_spec.rb +91 -0
- data/spec/audio_feed_manager/cli/get_feed_url_spec.rb +26 -0
- data/spec/audio_feed_manager/cli/initialize_project_spec.rb +47 -0
- data/spec/audio_feed_manager/cli/list_feeds_spec.rb +27 -0
- data/spec/audio_feed_manager/cli/show_feed_spec.rb +41 -0
- data/spec/audio_feed_manager/cli/update_feed_rss_spec.rb +26 -0
- data/spec/audio_feed_manager/cli_spec.rb +42 -0
- data/spec/audio_feed_manager/directory_lister_spec.rb +23 -0
- data/spec/audio_feed_manager/feed_items_repository_spec.rb +34 -0
- data/spec/audio_feed_manager/feeds_repository_spec.rb +40 -0
- data/spec/audio_feed_manager/file_storage_spec.rb +22 -0
- data/spec/audio_feed_manager/id3_tags_spec.rb +26 -0
- data/spec/audio_feed_manager/new_model_creator_spec.rb +44 -0
- data/spec/audio_feed_manager/rss_repository_spec.rb +34 -0
- data/spec/audio_feed_manager/s3_gateway_spec.rb +51 -0
- data/spec/audio_feed_manager/secret_token_generator_spec.rb +13 -0
- data/spec/audio_feed_manager/support/getter_setter_method_spec.rb +77 -0
- data/spec/audio_feed_manager/unique_id_generator_spec.rb +23 -0
- data/spec/fixtures/test.mp3 +0 -0
- data/spec/fixtures/test.txt +1 -0
- data/spec/help_spec.rb +64 -0
- data/spec/initializing_spec.rb +12 -0
- data/spec/managing_audio_files_spec.rb +21 -0
- data/spec/managing_feeds_spec.rb +51 -0
- data/spec/publishing_spec.rb +24 -0
- data/spec/s3_credentials.yml.sample +5 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/builders.rb +26 -0
- data/spec/support/fake_console.rb +13 -0
- data/spec/support/fakes.rb +5 -0
- data/spec/support/integration_helpers.rb +38 -0
- metadata +297 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
class UniqueIdGenerator
|
3
|
+
takes :directory_lister
|
4
|
+
|
5
|
+
def generate(name, directory)
|
6
|
+
existing_ids = directory_lister.list(directory)
|
7
|
+
base_id = name.downcase.gsub(/[\s\.,']/, '-').gsub(/[^a-z0-9\-]/, '')
|
8
|
+
|
9
|
+
proposed_id = base_id
|
10
|
+
idx = 1
|
11
|
+
while existing_ids.include?(proposed_id)
|
12
|
+
proposed_id = "#{base_id}-#{idx}"
|
13
|
+
idx += 1
|
14
|
+
end
|
15
|
+
|
16
|
+
proposed_id
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
class UrlMaker
|
3
|
+
takes :rss_files_prefix, :data_files_prefix, :s3_gateway
|
4
|
+
|
5
|
+
def feed_url(feed)
|
6
|
+
s3_gateway.url("#{rss_files_prefix}/#{feed.secret_token}.xml")
|
7
|
+
end
|
8
|
+
|
9
|
+
def audio_file_url(audio_file)
|
10
|
+
s3_gateway.url("#{data_files_prefix}/#{audio_file.secret_token}#{audio_file.extension}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "dependor"
|
2
|
+
require "dependor/shorty"
|
3
|
+
|
4
|
+
require_relative "audio_feed_manager/support/getter_setter_method"
|
5
|
+
require_relative "audio_feed_manager/support/hash_constructor"
|
6
|
+
|
7
|
+
require_relative "audio_feed_manager/error"
|
8
|
+
require_relative "audio_feed_manager/cli/command"
|
9
|
+
|
10
|
+
require_relative "audio_feed_manager/application"
|
11
|
+
require_relative "audio_feed_manager/audio_file"
|
12
|
+
require_relative "audio_feed_manager/audio_file_adder"
|
13
|
+
require_relative "audio_feed_manager/audio_file_repository"
|
14
|
+
require_relative "audio_feed_manager/config"
|
15
|
+
require_relative "audio_feed_manager/config_repository"
|
16
|
+
require_relative "audio_feed_manager/cli"
|
17
|
+
require_relative "audio_feed_manager/cli/arguments"
|
18
|
+
require_relative "audio_feed_manager/cli/arguments_parser"
|
19
|
+
require_relative "audio_feed_manager/cli/arguments_specification"
|
20
|
+
require_relative "audio_feed_manager/console"
|
21
|
+
require_relative "audio_feed_manager/directory_lister"
|
22
|
+
require_relative "audio_feed_manager/feed"
|
23
|
+
require_relative "audio_feed_manager/feed_items_repository"
|
24
|
+
require_relative "audio_feed_manager/feed_repository"
|
25
|
+
require_relative "audio_feed_manager/feed_syncer"
|
26
|
+
require_relative "audio_feed_manager/file_storage"
|
27
|
+
require_relative "audio_feed_manager/id3_tags"
|
28
|
+
require_relative "audio_feed_manager/new_model_creator"
|
29
|
+
require_relative "audio_feed_manager/rss_generator"
|
30
|
+
require_relative "audio_feed_manager/rss_repository"
|
31
|
+
require_relative "audio_feed_manager/s3_gateway"
|
32
|
+
require_relative "audio_feed_manager/secret_token_generator"
|
33
|
+
require_relative "audio_feed_manager/stop_application"
|
34
|
+
require_relative "audio_feed_manager/tags"
|
35
|
+
require_relative "audio_feed_manager/unique_id_generator"
|
36
|
+
require_relative "audio_feed_manager/url_maker"
|
37
|
+
require_relative "audio_feed_manager/version"
|
38
|
+
|
39
|
+
require_relative "audio_feed_manager/cli/add_audio_file"
|
40
|
+
require_relative "audio_feed_manager/cli/add_feed"
|
41
|
+
require_relative "audio_feed_manager/cli/initialize_project"
|
42
|
+
require_relative "audio_feed_manager/cli/list_feeds"
|
43
|
+
require_relative "audio_feed_manager/cli/show_feed"
|
44
|
+
require_relative "audio_feed_manager/cli/get_feed_url"
|
45
|
+
require_relative "audio_feed_manager/cli/update_feed_rss"
|
46
|
+
require_relative "audio_feed_manager/cli/publish"
|
47
|
+
|
48
|
+
require_relative "audio_feed_manager/cli/commands_list"
|
49
|
+
|
50
|
+
module AudioFeedManager
|
51
|
+
def self.run(pwd: Dir.pwd, argv: ARGV, stdin: $stdin, stdout: $stdout, stderr: $stderr, exit: ->(code) { exit code })
|
52
|
+
app = Application.new(directory: pwd, stdin: stdin, stdout: stdout, stderr: stderr)
|
53
|
+
app.cli.run(argv)
|
54
|
+
rescue StopApplication
|
55
|
+
exit.call(1)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module AudioFeedManager
|
4
|
+
describe AudioFileAdder do
|
5
|
+
let(:feed) { build_feed }
|
6
|
+
let(:saved_audio_file) { AudioFile.new(id: 'audio_files/saved') }
|
7
|
+
|
8
|
+
fake(:id3_tags)
|
9
|
+
fake(:feed_items_repository)
|
10
|
+
let(:audio_file_repository) { fake(:audio_file_repository, add: saved_audio_file) }
|
11
|
+
|
12
|
+
let(:audio_file_adder) { isolate(AudioFileAdder) }
|
13
|
+
|
14
|
+
it "adds the file based on ID3 tags to the specified feed" do
|
15
|
+
stub(id3_tags).read("/some/file") { Tags.new(title: "Some Audio File", artist: "Some Author") }
|
16
|
+
audio_file = AudioFile.new(title: "Some Audio File", author: "Some Author")
|
17
|
+
|
18
|
+
audio_file_adder.call(feed, "/some/file")
|
19
|
+
|
20
|
+
expect(audio_file_repository).to have_received.add(audio_file, "/some/file")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "adds the audio file to the specified feed" do
|
24
|
+
stub(id3_tags).read("/some/file") { Tags.new(title: "Some Audio File", artist: "Some Author") }
|
25
|
+
|
26
|
+
audio_file_adder.call(feed, "/some/file")
|
27
|
+
|
28
|
+
expect(feed_items_repository).to have_received.add(feed, saved_audio_file)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "fetches title from the lambda if no title discovered" do
|
32
|
+
stub(id3_tags).read("/some/file") { Tags.new(artist: "Some Author") }
|
33
|
+
audio_file = AudioFile.new(title: "some title", author: "Some Author")
|
34
|
+
|
35
|
+
audio_file_adder.call(feed, "/some/file", title: ->() { "some title" })
|
36
|
+
|
37
|
+
expect(audio_file_repository).to have_received.add(audio_file, "/some/file")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "fetches author from the lambda if no author discovered" do
|
41
|
+
stub(id3_tags).read("/some/file") { Tags.new(title: "Some Audio File") }
|
42
|
+
audio_file = AudioFile.new(title: "Some Audio File", author: "some author")
|
43
|
+
|
44
|
+
audio_file_adder.call(feed, "/some/file", author: ->() { "some author" })
|
45
|
+
|
46
|
+
expect(audio_file_repository).to have_received.add(audio_file, "/some/file")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe AudioFileRepository do
|
3
|
+
let(:audio_file) { AudioFile.new(title: "hello", author: "test") }
|
4
|
+
let(:saved_audio_file) { AudioFile.new(id: "audio_files/foo", secret_token: "abcd", extension: ".mp3") }
|
5
|
+
|
6
|
+
let(:audio_files_prefix) { "audio_files" }
|
7
|
+
let(:audio_files_directory) { "/tmp/foo/audio_files" }
|
8
|
+
let(:data_files_directory) { Pathname.new("/tmp/foo/data") }
|
9
|
+
let(:new_model_creator) { fake(:new_model_creator, create: saved_audio_file) }
|
10
|
+
fake(:storage)
|
11
|
+
|
12
|
+
let(:audio_file_repository) { isolate(AudioFileRepository) }
|
13
|
+
|
14
|
+
before do
|
15
|
+
FileUtils.rm_rf("/tmp/foo/data")
|
16
|
+
FileUtils.mkdir_p("/tmp/foo/data")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "saves the metadata while generating a secret token and ID" do
|
20
|
+
audio_file_repository.add(audio_file, fixture_file("test.mp3"))
|
21
|
+
|
22
|
+
expect(new_model_creator).to have_received.create(audio_file, prefix: "audio_files", directory: "/tmp/foo/audio_files")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "saves the file extension" do
|
26
|
+
modified_audio_file = AudioFile.new(title: audio_file.title,
|
27
|
+
author: audio_file.author,
|
28
|
+
extension: ".mp3",
|
29
|
+
size: 11305,
|
30
|
+
content_type: "audio/mpeg")
|
31
|
+
audio_file_repository.add(audio_file, fixture_file("test.mp3"))
|
32
|
+
|
33
|
+
expect(new_model_creator).to have_received.create(modified_audio_file, prefix: "audio_files", directory: "/tmp/foo/audio_files")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "copies the given file to a location based on the secret token" do
|
37
|
+
audio_file_repository.add(audio_file, fixture_file("test.mp3"))
|
38
|
+
|
39
|
+
expect(File.exist?("/tmp/foo/data/abcd.mp3")).to be(true)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "fetches the audio files" do
|
43
|
+
stub(storage).read("audio_files/foo") { {id: "audio_files/foo", title: "Foo"} }
|
44
|
+
|
45
|
+
audio_file = audio_file_repository.fetch("audio_files/foo")
|
46
|
+
|
47
|
+
expect(audio_file).to eq(AudioFile.new(id: "audio_files/foo", title: "Foo"))
|
48
|
+
end
|
49
|
+
|
50
|
+
it "raises an error if audio file was not found" do
|
51
|
+
stub(storage).read("audio_files/foo") { raise FileNotFound }
|
52
|
+
|
53
|
+
expect{
|
54
|
+
audio_file_repository.fetch("audio_files/foo")
|
55
|
+
}.to raise_error(AudioFileNotFound)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe AddAudioFile do
|
3
|
+
let(:feed) { build_feed }
|
4
|
+
let(:directory) { Pathname.new('/tmp/foo') }
|
5
|
+
fake(:feed_repository)
|
6
|
+
fake(:audio_file_adder)
|
7
|
+
fake(:console)
|
8
|
+
fake(:rss_generator)
|
9
|
+
|
10
|
+
let(:add_audio_file) { isolate(AddAudioFile) }
|
11
|
+
|
12
|
+
it "adds the audio file to the feed" do
|
13
|
+
stub(feed_repository).fetch("feeds/some-id") { feed }
|
14
|
+
|
15
|
+
add_audio_file.run(feed: "feeds/some-id", files: ["file"])
|
16
|
+
|
17
|
+
expect(audio_file_adder).to have_received.call(feed, Pathname.new("/tmp/foo/file"), title: any(Proc), author: any(Proc))
|
18
|
+
end
|
19
|
+
|
20
|
+
it "prints an error message when the feed was not found" do
|
21
|
+
stub(feed_repository).fetch("feeds/some-id") { raise FeedNotFound }
|
22
|
+
|
23
|
+
add_audio_file.run(feed: "feeds/some-id", files: ["/some/file"])
|
24
|
+
|
25
|
+
expect(console).to have_received.die(any_args)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "prints an error message when the file was not found" do
|
29
|
+
stub(feed_repository).fetch("feeds/some-id") { raise Errno::ENOENT }
|
30
|
+
|
31
|
+
add_audio_file.run(feed: "feeds/some-id", files: ["/some/file"])
|
32
|
+
|
33
|
+
expect(console).to have_received.die(any_args)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "generates rss after adding the file" do
|
37
|
+
stub(feed_repository).fetch("feeds/some-id") { feed }
|
38
|
+
|
39
|
+
add_audio_file.run(feed: "feeds/some-id", files: ["file"])
|
40
|
+
|
41
|
+
expect(rss_generator).to have_received.generate(feed)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe AddFeed do
|
3
|
+
fake(:console)
|
4
|
+
fake(:feed_repository)
|
5
|
+
fake(:rss_generator)
|
6
|
+
|
7
|
+
let(:add_feed) { isolate(AddFeed) }
|
8
|
+
let(:feed) { Feed.new(id: "feeds/hello-world") }
|
9
|
+
|
10
|
+
before do
|
11
|
+
stub(console).ask("Description", default: "Hello World!") { "some description" }
|
12
|
+
stub(feed_repository).add(any_args) { feed }
|
13
|
+
end
|
14
|
+
|
15
|
+
it "adds the feed with the given title" do
|
16
|
+
add_feed.run(title: "Hello World!")
|
17
|
+
|
18
|
+
expect(feed_repository).to have_received.add(Feed.new(title: "Hello World!", description: "some description"))
|
19
|
+
end
|
20
|
+
|
21
|
+
it "generates an RSS file for the created feed" do
|
22
|
+
add_feed.run(title: "Hello World!")
|
23
|
+
|
24
|
+
expect(rss_generator).to have_received.generate(feed)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe ArgumentsParser do
|
3
|
+
let(:parser) { isolate(ArgumentsParser) }
|
4
|
+
|
5
|
+
context "with a simple one-argument specification" do
|
6
|
+
let(:specification) {
|
7
|
+
ArgumentsSpecification.specify do |s|
|
8
|
+
s.argument :project_name, required: true, description: "Name of the directory to create the project in"
|
9
|
+
end
|
10
|
+
}
|
11
|
+
|
12
|
+
it "parses a single-argument list into arguments" do
|
13
|
+
arguments = parser.parse(specification, ["foo-bar"])
|
14
|
+
|
15
|
+
expect(arguments.to_hash).to eq({project_name: "foo-bar"})
|
16
|
+
end
|
17
|
+
|
18
|
+
it "fails when there are no arguments" do
|
19
|
+
expect {
|
20
|
+
parser.parse(specification, [])
|
21
|
+
}.to raise_error(InvalidArguments)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "fails when there are two or more arguments" do
|
25
|
+
expect {
|
26
|
+
parser.parse(specification, ["foo", "bar"])
|
27
|
+
}.to raise_error(InvalidArguments)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "with varargs" do
|
32
|
+
let(:specification) {
|
33
|
+
ArgumentsSpecification.specify do |s|
|
34
|
+
s.varargs :files, minimum: 1, description: "Files to add."
|
35
|
+
end
|
36
|
+
}
|
37
|
+
|
38
|
+
it "parses a single-argument list into arguments" do
|
39
|
+
arguments = parser.parse(specification, ["foo-bar"])
|
40
|
+
|
41
|
+
expect(arguments.to_hash).to eq({files: ["foo-bar"]})
|
42
|
+
end
|
43
|
+
|
44
|
+
it "parses a multi-argument list into arguments" do
|
45
|
+
arguments = parser.parse(specification, ["foo", "bar", "baz"])
|
46
|
+
|
47
|
+
expect(arguments.to_hash).to eq({files: ["foo", "bar", "baz"]})
|
48
|
+
end
|
49
|
+
|
50
|
+
it "fails when there are no arguments" do
|
51
|
+
expect {
|
52
|
+
parser.parse(specification, [])
|
53
|
+
}.to raise_error(InvalidArguments)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with optional arguments" do
|
58
|
+
let(:specification) {
|
59
|
+
ArgumentsSpecification.specify do |s|
|
60
|
+
s.argument :author_name, required: false, default: "Anonymous", description: "Author name"
|
61
|
+
s.argument :project_name, required: true, description: "Name of the directory to create the project in"
|
62
|
+
end
|
63
|
+
}
|
64
|
+
|
65
|
+
it "parses a single-argument list into required arguments" do
|
66
|
+
arguments = parser.parse(specification, ["foo-bar"])
|
67
|
+
|
68
|
+
expect(arguments.to_hash[:project_name]).to eq("foo-bar")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "parses a two-argument list into required and optional arguments" do
|
72
|
+
arguments = parser.parse(specification, ["foo", "bar"])
|
73
|
+
|
74
|
+
expect(arguments.to_hash[:project_name]).to eq("foo")
|
75
|
+
expect(arguments.to_hash[:author_name]).to eq("bar")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "raises an error when given more arguments than supported" do
|
79
|
+
expect {
|
80
|
+
parser.parse(specification, ["foo", "bar", "baz"])
|
81
|
+
}.to raise_error(InvalidArguments)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe ArgumentsSpecification do
|
3
|
+
describe "#usage_line" do
|
4
|
+
it "returns the command name" do
|
5
|
+
specification = ArgumentsSpecification.specify do |s|
|
6
|
+
s.name "foo"
|
7
|
+
end
|
8
|
+
|
9
|
+
expect(specification.usage_line).to eq("foo")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns the command name and required arguments" do
|
13
|
+
specification = ArgumentsSpecification.specify do |s|
|
14
|
+
s.name "foo"
|
15
|
+
s.argument :some_arg, required: true
|
16
|
+
end
|
17
|
+
|
18
|
+
expect(specification.usage_line).to eq("foo <SOME_ARG>")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns the command name and optional arguments" do
|
22
|
+
specification = ArgumentsSpecification.specify do |s|
|
23
|
+
s.name "foo"
|
24
|
+
s.argument :some_arg, required: false
|
25
|
+
end
|
26
|
+
|
27
|
+
expect(specification.usage_line).to eq("foo [SOME_ARG]")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns the command name and varargs" do
|
31
|
+
specification = ArgumentsSpecification.specify do |s|
|
32
|
+
s.name "foo"
|
33
|
+
s.varargs :songs
|
34
|
+
end
|
35
|
+
|
36
|
+
expect(specification.usage_line).to eq("foo [SONGS...]")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns the command name and a combination of optional, required arguments and varargs" do
|
40
|
+
specification = ArgumentsSpecification.specify do |s|
|
41
|
+
s.name "foo"
|
42
|
+
s.argument :first_arg, required: true
|
43
|
+
s.argument :second_arg, required: false
|
44
|
+
s.varargs :rest
|
45
|
+
end
|
46
|
+
|
47
|
+
expect(specification.usage_line).to eq("foo <FIRST_ARG> [SECOND_ARG] [REST...]")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe CommandsList do
|
3
|
+
fake(:initialize_project)
|
4
|
+
fake(:add_feed)
|
5
|
+
fake(:list_feeds)
|
6
|
+
fake(:add_audio_file)
|
7
|
+
fake(:show_feed)
|
8
|
+
fake(:get_feed_url)
|
9
|
+
fake(:update_feed_rss)
|
10
|
+
fake(:publish)
|
11
|
+
fake(:console)
|
12
|
+
|
13
|
+
let(:commands_list) { isolate(CommandsList) }
|
14
|
+
|
15
|
+
it "returns the initialize_project command for 'init'" do
|
16
|
+
command, opts = commands_list.get(["init", "foo"])
|
17
|
+
|
18
|
+
expect(command).to be(initialize_project)
|
19
|
+
expect(opts).to eq(["foo"])
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns help when called with no arguments" do
|
23
|
+
command, opts = commands_list.get([])
|
24
|
+
|
25
|
+
expect(command).to be(commands_list)
|
26
|
+
expect(opts).to eq([])
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns help when called with 'help'" do
|
30
|
+
command, opts = commands_list.get(["help"])
|
31
|
+
|
32
|
+
expect(command).to be(commands_list)
|
33
|
+
expect(opts).to eq([])
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns add_feed command for 'feeds add'" do
|
37
|
+
command, opts = commands_list.get(["feeds", "add", "foo"])
|
38
|
+
|
39
|
+
expect(command).to be(add_feed)
|
40
|
+
expect(opts).to eq(["foo"])
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns show_feed for 'feeds show'" do
|
44
|
+
command, opts = commands_list.get(["feeds", "show", "feeds/hello"])
|
45
|
+
|
46
|
+
expect(command).to be(show_feed)
|
47
|
+
expect(opts).to eq(["feeds/hello"])
|
48
|
+
end
|
49
|
+
|
50
|
+
it "returns get_feed_url for 'feeds get-url'" do
|
51
|
+
command, opts = commands_list.get(["feeds", "get-url", "feeds/hello"])
|
52
|
+
|
53
|
+
expect(command).to be(get_feed_url)
|
54
|
+
expect(opts).to eq(["feeds/hello"])
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns update_feed_rss for 'feeds update-rss'" do
|
58
|
+
command, opts = commands_list.get(["feeds", "update-rss", "feeds/hello"])
|
59
|
+
|
60
|
+
expect(command).to be(update_feed_rss)
|
61
|
+
expect(opts).to eq(["feeds/hello"])
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns add_audio_file for 'audio add'" do
|
65
|
+
command, opts = commands_list.get(["audio", "add", "feeds/hello", "/some/file.mp3"])
|
66
|
+
|
67
|
+
expect(command).to be(add_audio_file)
|
68
|
+
expect(opts).to eq(["feeds/hello", "/some/file.mp3"])
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns list_feeds command for 'feeds list'" do
|
72
|
+
command, opts = commands_list.get(["feeds", "list"])
|
73
|
+
|
74
|
+
expect(command).to be(list_feeds)
|
75
|
+
expect(opts).to eq([])
|
76
|
+
end
|
77
|
+
|
78
|
+
it "returns publish command for 'publish'" do
|
79
|
+
command, opts = commands_list.get(["publish"])
|
80
|
+
|
81
|
+
expect(command).to be(publish)
|
82
|
+
expect(opts).to eq([])
|
83
|
+
end
|
84
|
+
|
85
|
+
it "raises an UnknownCommand error for other commands" do
|
86
|
+
expect {
|
87
|
+
commands_list.get("asdf")
|
88
|
+
}.to raise_error(UnknownCommand)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe GetFeedUrl do
|
3
|
+
fake(:feed_repository)
|
4
|
+
let(:console) { FakeConsole.new }
|
5
|
+
fake(:url_maker, feed_url: "http://example.com/feed")
|
6
|
+
|
7
|
+
let(:get_feed_url) { isolate(GetFeedUrl) }
|
8
|
+
|
9
|
+
it "prints the feed url" do
|
10
|
+
feed = build_feed
|
11
|
+
stub(feed_repository).fetch("feeds/foo") { feed }
|
12
|
+
|
13
|
+
get_feed_url.run(feed: "feeds/foo")
|
14
|
+
|
15
|
+
expect(console.out).to eq("http://example.com/feed\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns a friendly message when feed not found" do
|
19
|
+
stub(feed_repository).fetch("feeds/foo") { raise FeedNotFound.for_id("feeds/foo") }
|
20
|
+
|
21
|
+
get_feed_url.run(feed: "feeds/foo")
|
22
|
+
|
23
|
+
expect(console.out).to include("not found")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe InitializeProject do
|
3
|
+
fake(:console)
|
4
|
+
fake(:config_repository)
|
5
|
+
let(:directory) { Pathname.new("/tmp") }
|
6
|
+
let(:audio_files_prefix) { "audio_files" }
|
7
|
+
let(:rss_files_prefix) { "rss" }
|
8
|
+
let(:feeds_prefix) { "feeds" }
|
9
|
+
let(:data_files_prefix) { "data" }
|
10
|
+
let(:items_prefix) { "items" }
|
11
|
+
let(:initialize_project) { isolate(InitializeProject) }
|
12
|
+
|
13
|
+
before do
|
14
|
+
FileUtils.rm_rf("/tmp/foo")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "creates the project directory" do
|
18
|
+
initialize_project.run(project_dir: "foo")
|
19
|
+
|
20
|
+
expect(File.exists?("/tmp/foo")).to be(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "creates a directory for the feeds" do
|
24
|
+
initialize_project.run(project_dir: "foo")
|
25
|
+
|
26
|
+
expect(File.exists?("/tmp/foo/feeds")).to be(true)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "creates a directory for the audio_files" do
|
30
|
+
initialize_project.run(project_dir: "foo")
|
31
|
+
|
32
|
+
expect(File.exists?("/tmp/foo/audio_files")).to be(true)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "creates a directory for rss files" do
|
36
|
+
initialize_project.run(project_dir: "foo")
|
37
|
+
|
38
|
+
expect(File.exists?("/tmp/foo/rss")).to be(true)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "creates a directory for data files" do
|
42
|
+
initialize_project.run(project_dir: "foo")
|
43
|
+
|
44
|
+
expect(File.exists?("/tmp/foo/data")).to be(true)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe ListFeeds do
|
3
|
+
fake(:feed_repository)
|
4
|
+
let(:console) { FakeConsole.new }
|
5
|
+
|
6
|
+
let(:list_feeds) { isolate(ListFeeds) }
|
7
|
+
|
8
|
+
it "returns a formatted list of feeds" do
|
9
|
+
feeds = [Feed.new(id: "feeds/hello", title: "Hello!"),
|
10
|
+
Feed.new(id: "feeds/foo-bar", title: "Foo Bar")]
|
11
|
+
stub(feed_repository).list { feeds }
|
12
|
+
|
13
|
+
list_feeds.run
|
14
|
+
|
15
|
+
expect(console.out).to (include("1.\tfeeds/hello\tHello!"))
|
16
|
+
expect(console.out).to (include("2.\tfeeds/foo-bar\tFoo Bar"))
|
17
|
+
end
|
18
|
+
|
19
|
+
it "prints a helpful message when no feeds exist" do
|
20
|
+
stub(feed_repository).list { [] }
|
21
|
+
|
22
|
+
list_feeds.run
|
23
|
+
|
24
|
+
expect(console.out).to (include("No feeds yet."))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe ShowFeed do
|
3
|
+
let(:feed) { Feed.new(id: "feeds/hello", title: "Hello!") }
|
4
|
+
fake(:feed_repository)
|
5
|
+
fake(:feed_items_repository, list: [])
|
6
|
+
fake(:url_maker, feed_url: "http://example.com/feeds/abc.xml")
|
7
|
+
let(:console) { FakeConsole.new }
|
8
|
+
|
9
|
+
let(:show_feed) { isolate(ShowFeed) }
|
10
|
+
|
11
|
+
it "returns detailes information about the feed" do
|
12
|
+
stub(feed_repository).fetch("feeds/foo") { feed }
|
13
|
+
audio_file = AudioFile.new(id: "audio_files/bar", title: "Some audio file")
|
14
|
+
stub(feed_items_repository).list(feed) { [audio_file] }
|
15
|
+
|
16
|
+
show_feed.run(feed: "feeds/foo")
|
17
|
+
|
18
|
+
expect(console.out).to (include("Hello!"))
|
19
|
+
expect(console.out).to (include("http://example.com/feeds/abc.xml"))
|
20
|
+
expect(console.out).to (include("Some audio file"))
|
21
|
+
end
|
22
|
+
|
23
|
+
it "prints a helpful message when feed was not found" do
|
24
|
+
stub(feed_repository).fetch("feeds/foo") { raise FeedNotFound.for_id("feeds/foo") }
|
25
|
+
|
26
|
+
show_feed.run(feed: "feeds/foo")
|
27
|
+
|
28
|
+
expect(console.out).to (include("not found"))
|
29
|
+
end
|
30
|
+
|
31
|
+
it "prints a helpful message when there are no audio files" do
|
32
|
+
stub(feed_repository).fetch("feeds/foo") { feed }
|
33
|
+
stub(feed_items_repository).list(feed) { [] }
|
34
|
+
|
35
|
+
show_feed.run(feed: "feeds/foo")
|
36
|
+
|
37
|
+
expect(console.out).to (include("No audio files"))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|