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.
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
+