audio-feed-manager 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +17 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +86 -0
  8. data/Rakefile +2 -0
  9. data/audio-feed-manager.gemspec +32 -0
  10. data/bin/afm +5 -0
  11. data/lib/audio-feed-manager.rb +1 -0
  12. data/lib/audio_feed_manager/application.rb +39 -0
  13. data/lib/audio_feed_manager/audio_file.rb +9 -0
  14. data/lib/audio_feed_manager/audio_file_adder.rb +14 -0
  15. data/lib/audio_feed_manager/audio_file_repository.rb +42 -0
  16. data/lib/audio_feed_manager/cli/add_audio_file.rb +39 -0
  17. data/lib/audio_feed_manager/cli/add_feed.rb +20 -0
  18. data/lib/audio_feed_manager/cli/arguments.rb +27 -0
  19. data/lib/audio_feed_manager/cli/arguments_parser.rb +67 -0
  20. data/lib/audio_feed_manager/cli/arguments_specification.rb +103 -0
  21. data/lib/audio_feed_manager/cli/command.rb +23 -0
  22. data/lib/audio_feed_manager/cli/commands_list.rb +120 -0
  23. data/lib/audio_feed_manager/cli/get_feed_url.rb +20 -0
  24. data/lib/audio_feed_manager/cli/initialize_project.rb +44 -0
  25. data/lib/audio_feed_manager/cli/list_feeds.rb +38 -0
  26. data/lib/audio_feed_manager/cli/publish.rb +21 -0
  27. data/lib/audio_feed_manager/cli/show_feed.rb +44 -0
  28. data/lib/audio_feed_manager/cli/update_feed_rss.rb +19 -0
  29. data/lib/audio_feed_manager/cli.rb +19 -0
  30. data/lib/audio_feed_manager/config.rb +5 -0
  31. data/lib/audio_feed_manager/config_repository.rb +14 -0
  32. data/lib/audio_feed_manager/console.rb +28 -0
  33. data/lib/audio_feed_manager/directory_lister.rb +9 -0
  34. data/lib/audio_feed_manager/error.rb +4 -0
  35. data/lib/audio_feed_manager/feed.rb +9 -0
  36. data/lib/audio_feed_manager/feed_items_repository.rb +30 -0
  37. data/lib/audio_feed_manager/feed_repository.rb +32 -0
  38. data/lib/audio_feed_manager/feed_syncer.rb +20 -0
  39. data/lib/audio_feed_manager/file_storage.rb +20 -0
  40. data/lib/audio_feed_manager/id3_tags.rb +14 -0
  41. data/lib/audio_feed_manager/new_model_creator.rb +15 -0
  42. data/lib/audio_feed_manager/rss_generator.rb +10 -0
  43. data/lib/audio_feed_manager/rss_repository.rb +36 -0
  44. data/lib/audio_feed_manager/s3_gateway.rb +39 -0
  45. data/lib/audio_feed_manager/secret_token_generator.rb +9 -0
  46. data/lib/audio_feed_manager/stop_application.rb +4 -0
  47. data/lib/audio_feed_manager/support/getter_setter_method.rb +18 -0
  48. data/lib/audio_feed_manager/support/hash_constructor.rb +9 -0
  49. data/lib/audio_feed_manager/tags.rb +9 -0
  50. data/lib/audio_feed_manager/unique_id_generator.rb +19 -0
  51. data/lib/audio_feed_manager/url_maker.rb +13 -0
  52. data/lib/audio_feed_manager/version.rb +3 -0
  53. data/lib/audio_feed_manager.rb +57 -0
  54. data/spec/audio_feed_manager/audio_file_adder_spec.rb +49 -0
  55. data/spec/audio_feed_manager/audio_file_repository_spec.rb +58 -0
  56. data/spec/audio_feed_manager/cli/add_audio_file_spec.rb +44 -0
  57. data/spec/audio_feed_manager/cli/add_feed_spec.rb +27 -0
  58. data/spec/audio_feed_manager/cli/arguments_parser_spec.rb +85 -0
  59. data/spec/audio_feed_manager/cli/arguments_specification_spec.rb +51 -0
  60. data/spec/audio_feed_manager/cli/commands_list_spec.rb +91 -0
  61. data/spec/audio_feed_manager/cli/get_feed_url_spec.rb +26 -0
  62. data/spec/audio_feed_manager/cli/initialize_project_spec.rb +47 -0
  63. data/spec/audio_feed_manager/cli/list_feeds_spec.rb +27 -0
  64. data/spec/audio_feed_manager/cli/show_feed_spec.rb +41 -0
  65. data/spec/audio_feed_manager/cli/update_feed_rss_spec.rb +26 -0
  66. data/spec/audio_feed_manager/cli_spec.rb +42 -0
  67. data/spec/audio_feed_manager/directory_lister_spec.rb +23 -0
  68. data/spec/audio_feed_manager/feed_items_repository_spec.rb +34 -0
  69. data/spec/audio_feed_manager/feeds_repository_spec.rb +40 -0
  70. data/spec/audio_feed_manager/file_storage_spec.rb +22 -0
  71. data/spec/audio_feed_manager/id3_tags_spec.rb +26 -0
  72. data/spec/audio_feed_manager/new_model_creator_spec.rb +44 -0
  73. data/spec/audio_feed_manager/rss_repository_spec.rb +34 -0
  74. data/spec/audio_feed_manager/s3_gateway_spec.rb +51 -0
  75. data/spec/audio_feed_manager/secret_token_generator_spec.rb +13 -0
  76. data/spec/audio_feed_manager/support/getter_setter_method_spec.rb +77 -0
  77. data/spec/audio_feed_manager/unique_id_generator_spec.rb +23 -0
  78. data/spec/fixtures/test.mp3 +0 -0
  79. data/spec/fixtures/test.txt +1 -0
  80. data/spec/help_spec.rb +64 -0
  81. data/spec/initializing_spec.rb +12 -0
  82. data/spec/managing_audio_files_spec.rb +21 -0
  83. data/spec/managing_feeds_spec.rb +51 -0
  84. data/spec/publishing_spec.rb +24 -0
  85. data/spec/s3_credentials.yml.sample +5 -0
  86. data/spec/spec_helper.rb +17 -0
  87. data/spec/support/builders.rb +26 -0
  88. data/spec/support/fake_console.rb +13 -0
  89. data/spec/support/fakes.rb +5 -0
  90. data/spec/support/integration_helpers.rb +38 -0
  91. metadata +297 -0
@@ -0,0 +1,9 @@
1
+ module AudioFeedManager
2
+ class Tags < Struct.new(:title, :artist)
3
+ include HashConstructor
4
+
5
+ def self.blank
6
+ new
7
+ end
8
+ end
9
+ end
@@ -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,3 @@
1
+ module AudioFeedManager
2
+ VERSION = "0.0.1"
3
+ 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
+