audio-feed-manager 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|