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,26 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe UpdateFeedRss do
|
3
|
+
fake(:feed_repository)
|
4
|
+
fake(:rss_generator)
|
5
|
+
let(:console) { FakeConsole.new }
|
6
|
+
|
7
|
+
let(:update_feed_rss) { isolate(UpdateFeedRss) }
|
8
|
+
|
9
|
+
it "generates the feed RSS" do
|
10
|
+
feed = build_feed
|
11
|
+
stub(feed_repository).fetch("feeds/foo") { feed }
|
12
|
+
|
13
|
+
update_feed_rss.run(feed: "feeds/foo")
|
14
|
+
|
15
|
+
expect(rss_generator).to have_received.generate(feed)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "prints an error message when feed not found" do
|
19
|
+
stub(feed_repository).fetch("feeds/foo") { raise FeedNotFound.for_id("feeds/foo") }
|
20
|
+
|
21
|
+
update_feed_rss.run(feed: "feeds/foo")
|
22
|
+
|
23
|
+
expect(console.out).to include("not found")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe CLI do
|
3
|
+
fake(:command, arguments: ArgumentsSpecification.new, name: "init") { InitializeProject }
|
4
|
+
fake(:commands_list)
|
5
|
+
fake(:arguments_parser)
|
6
|
+
fake(:help)
|
7
|
+
fake(:console)
|
8
|
+
let(:arguments) { Arguments.from_hash(project_dir: "my-project-name") }
|
9
|
+
|
10
|
+
let(:cli) { isolate(CLI) }
|
11
|
+
|
12
|
+
it "runs the specified command" do
|
13
|
+
stub(commands_list).get(["init", "my-project-name"]) { [command, ["my-project-name"]]}
|
14
|
+
stub(arguments_parser).parse(command.arguments, ["my-project-name"]) { arguments }
|
15
|
+
|
16
|
+
cli.run(["init", "my-project-name"])
|
17
|
+
|
18
|
+
expect(command).to have_received.run(project_dir: "my-project-name")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "prints command usage if command arguments are invalid and stops the application" do
|
22
|
+
stub(commands_list).get(["init"]) { [command, []]}
|
23
|
+
stub(arguments_parser).parse(command.arguments, []) { raise InvalidArguments }
|
24
|
+
|
25
|
+
expect {
|
26
|
+
cli.run(["init"])
|
27
|
+
}.to raise_error(StopApplication)
|
28
|
+
|
29
|
+
expect(help).to have_received.print_command_usage("init")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "prints usage if command is invalid and stops the application" do
|
33
|
+
stub(commands_list).get(["foo"]) { raise UnknownCommand }
|
34
|
+
|
35
|
+
expect {
|
36
|
+
cli.run(["foo"])
|
37
|
+
}.to raise_error(StopApplication)
|
38
|
+
|
39
|
+
expect(help).to have_received.print_usage
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe DirectoryLister do
|
3
|
+
let(:directory_lister) { isolate(DirectoryLister) }
|
4
|
+
|
5
|
+
it "returns an empty array for non-existent directories" do
|
6
|
+
files = directory_lister.list("/tmp/asdfasdfasdfasdfasdfasdf")
|
7
|
+
|
8
|
+
expect(files).to eq([])
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns a list of all the files in a given directory, sorted by name" do
|
12
|
+
FileUtils.rm_rf("/tmp/foobar")
|
13
|
+
FileUtils.mkdir_p("/tmp/foobar")
|
14
|
+
FileUtils.touch("/tmp/foobar/foo.txt")
|
15
|
+
FileUtils.touch("/tmp/foobar/bar.txt")
|
16
|
+
FileUtils.touch("/tmp/foobar/baz.txt")
|
17
|
+
|
18
|
+
files = directory_lister.list("/tmp/foobar")
|
19
|
+
|
20
|
+
expect(files).to eq(["bar.txt", "baz.txt", "foo.txt"])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe FeedItemsRepository do
|
3
|
+
let(:items_directory) { Pathname.new("/tmp/foo") }
|
4
|
+
let(:feed_items_repository) { isolate(FeedItemsRepository) }
|
5
|
+
fake(:audio_file_repository)
|
6
|
+
|
7
|
+
before do
|
8
|
+
FileUtils.rm_rf(items_directory)
|
9
|
+
FileUtils.mkdir_p(items_directory)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns an empty array for a feed with no items" do
|
13
|
+
feed = build_feed
|
14
|
+
|
15
|
+
expect(feed_items_repository.list(feed)).to eq([])
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns a list of audio files added for a feed, latest first" do
|
19
|
+
feed = build_feed(id: "feeds/abc")
|
20
|
+
other_feed = build_feed(id: "feeds/def")
|
21
|
+
foo = AudioFile.new(id: "audio_files/foo")
|
22
|
+
bar = AudioFile.new(id: "audio_files/bar")
|
23
|
+
baz = AudioFile.new(id: "audio_files/baz")
|
24
|
+
stub(audio_file_repository).fetch("audio_files/foo") { foo }
|
25
|
+
stub(audio_file_repository).fetch("audio_files/bar") { bar }
|
26
|
+
stub(audio_file_repository).fetch("audio_files/baz") { baz }
|
27
|
+
feed_items_repository.add(feed, foo)
|
28
|
+
feed_items_repository.add(feed, bar)
|
29
|
+
feed_items_repository.add(other_feed, baz)
|
30
|
+
|
31
|
+
expect(feed_items_repository.list(feed)).to eq([bar, foo])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module AudioFeedManager
|
4
|
+
describe FeedRepository do
|
5
|
+
let(:feed_repository) { isolate(FeedRepository) }
|
6
|
+
let(:feeds_directory) { Pathname.new("/tmp/foo/feeds") }
|
7
|
+
let(:feeds_prefix) { "feeds" }
|
8
|
+
fake(:new_model_creator)
|
9
|
+
fake(:storage)
|
10
|
+
fake(:directory_lister)
|
11
|
+
|
12
|
+
it "stores new feeds" do
|
13
|
+
saved_feed = Feed.new(id: "feeds/foo")
|
14
|
+
feed = Feed.new(title: "Hello World!")
|
15
|
+
mock(new_model_creator).create(feed, directory: feeds_directory,
|
16
|
+
prefix: feeds_prefix) { saved_feed }
|
17
|
+
|
18
|
+
feed = feed_repository.add(feed)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "fetches the stored feeds" do
|
22
|
+
stub(storage).read("feeds/hello-world") { {id: "feeds/hello-world", title: "Hello World"} }
|
23
|
+
|
24
|
+
expect(feed_repository.fetch("feeds/hello-world")).to eq(Feed.new(id: "feeds/hello-world", title: "Hello World"))
|
25
|
+
end
|
26
|
+
|
27
|
+
it "raises FeedNotFound when a feed by given id does not exist" do
|
28
|
+
stub(storage).read("feeds/hello-world") { raise FileNotFound }
|
29
|
+
|
30
|
+
expect{feed_repository.fetch("feeds/hello-world")}.to raise_error(FeedNotFound)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "lists the feeds" do
|
34
|
+
stub(directory_lister).list(feeds_directory) { ["hello-world"] }
|
35
|
+
stub(storage).read("feeds/hello-world") { {id: "feeds/hello-world", title: "Hello World"} }
|
36
|
+
|
37
|
+
expect(feed_repository.list).to include(Feed.new(id: "feeds/hello-world", title: "Hello World"))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe FileStorage do
|
3
|
+
let(:directory) { Pathname.new("/tmp/foo") }
|
4
|
+
|
5
|
+
let(:storage) { isolate(FileStorage) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
FileUtils.rm_rf(directory)
|
9
|
+
FileUtils.mkdir_p(directory.join("feeds"))
|
10
|
+
end
|
11
|
+
|
12
|
+
it "stores the contents in a specified file" do
|
13
|
+
storage.store("feeds/hello", {id: 1, title: "hello!"})
|
14
|
+
|
15
|
+
expect(storage.read("feeds/hello")).to eq(id: 1, title: "hello!")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "raises an error, when the given file does not exist" do
|
19
|
+
expect{ storage.read("feeds/hello") }.to raise_error(FileNotFound)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe Id3Tags do
|
3
|
+
let(:id3tags) { isolate(Id3Tags) }
|
4
|
+
|
5
|
+
it "reads ID3 tags from an mp3 file" do
|
6
|
+
tags = id3tags.read(fixture_file("test.mp3"))
|
7
|
+
|
8
|
+
expect(tags.title).to eq("My first audio file")
|
9
|
+
expect(tags.artist).to eq("Adam Pohorecki")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns empty tags for a file that does not exist" do
|
13
|
+
tags = id3tags.read(Pathname.new("/tmp/file-which-does-not-exist"))
|
14
|
+
|
15
|
+
expect(tags.title).to eq(nil)
|
16
|
+
expect(tags.artist).to eq(nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns empty tags for a file that is not an mp3 file" do
|
20
|
+
tags = id3tags.read(fixture_file("test.txt"))
|
21
|
+
|
22
|
+
expect(tags.title).to eq(nil)
|
23
|
+
expect(tags.artist).to eq(nil)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe NewModelCreator do
|
3
|
+
class SampleModel < Struct.new(:id, :title, :secret_token, :foo)
|
4
|
+
include HashConstructor
|
5
|
+
end
|
6
|
+
|
7
|
+
let(:new_model_creator) { isolate(NewModelCreator) }
|
8
|
+
let(:directory) { Pathname.new("/tmp/foo/feeds") }
|
9
|
+
let(:prefix) { "feeds" }
|
10
|
+
fake(:unique_id_generator, generate: "hello-world")
|
11
|
+
fake(:secret_token_generator, generate: "secret-token")
|
12
|
+
fake(:storage)
|
13
|
+
|
14
|
+
it "sets the id for the added model" do
|
15
|
+
stub(unique_id_generator).generate("Hello World!", directory) { "hello-world" }
|
16
|
+
model = SampleModel.new(title: "Hello World!")
|
17
|
+
|
18
|
+
new_model_creator.create(model, prefix: prefix, directory: directory)
|
19
|
+
|
20
|
+
expect(model.id).to eq("feeds/hello-world")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "stores the added model" do
|
24
|
+
model = SampleModel.new(title: "Hello World!", foo: "hello there")
|
25
|
+
|
26
|
+
new_model_creator.create(model, prefix: prefix, directory: directory)
|
27
|
+
|
28
|
+
expect(storage).to have_received.store(
|
29
|
+
"feeds/hello-world",
|
30
|
+
id: "feeds/hello-world",
|
31
|
+
title: "Hello World!",
|
32
|
+
secret_token: "secret-token",
|
33
|
+
foo: "hello there",
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "assigns a secret token to the created model" do
|
38
|
+
model = new_model_creator.create(SampleModel.new(title: "Hello World!"), prefix: prefix, directory: directory)
|
39
|
+
|
40
|
+
expect(model.secret_token).to eq("secret-token")
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe RSSRepository do
|
3
|
+
fake(:url_maker, feed_url: "http://example.com/feed.xml", audio_file_url: "http://example.com/audio/foo.mp3")
|
4
|
+
let(:rss_files_directory) { Pathname.new("/tmp/my-project/rss") }
|
5
|
+
|
6
|
+
before do
|
7
|
+
FileUtils.rm_rf(rss_files_directory)
|
8
|
+
FileUtils.mkdir_p(rss_files_directory)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "stores an RSS feed under rss/:secret_token.xml" do
|
12
|
+
feed = build_feed(id: "feeds/hello",
|
13
|
+
title: "My First Feed",
|
14
|
+
description: "some description",
|
15
|
+
secret_token: "abcdefgh")
|
16
|
+
audio_file = build_audio_file(secret_token: "foobar",
|
17
|
+
extension: ".mp3",
|
18
|
+
title: "Some audio file",
|
19
|
+
author: "Audio file author")
|
20
|
+
rss_repository = isolate(RSSRepository)
|
21
|
+
|
22
|
+
rss_repository.store(feed, [audio_file])
|
23
|
+
|
24
|
+
feed_content = File.read("/tmp/my-project/rss/abcdefgh.xml")
|
25
|
+
expect(feed_content).to include("<?xml")
|
26
|
+
expect(feed_content).to include("My First Feed")
|
27
|
+
expect(feed_content).to include("some description")
|
28
|
+
expect(feed_content).not_to include("feeds/hello")
|
29
|
+
expect(feed_content).to include("Some audio file")
|
30
|
+
expect(feed_content).to include("Audio file author")
|
31
|
+
expect(feed_content).to include("http://example.com/audio/foo.mp3")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module AudioFeedManager
|
4
|
+
describe S3Gateway, :slow do
|
5
|
+
let(:config) { Config.new(s3_bucket: s3_config["bucket"],
|
6
|
+
s3_access_key: s3_config["access_key"],
|
7
|
+
s3_secret: s3_config["secret_key"],
|
8
|
+
s3_region: s3_config["region"]) }
|
9
|
+
|
10
|
+
let(:s3_gateway) { isolate(S3Gateway) }
|
11
|
+
|
12
|
+
it "syncs files to S3" do
|
13
|
+
unique_key = "test/#{SecureRandom.hex}"
|
14
|
+
file_name = :not_called
|
15
|
+
|
16
|
+
s3_gateway.sync(unique_key, fixture_file("test.mp3")) { |f| file_name = f }
|
17
|
+
|
18
|
+
expect(file_name).to eq(unique_key)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "does not sync the same file twice" do
|
22
|
+
unique_key = "test/#{SecureRandom.hex}"
|
23
|
+
file_name = :not_called
|
24
|
+
|
25
|
+
s3_gateway.sync(unique_key, fixture_file("test.mp3"))
|
26
|
+
s3_gateway.sync(unique_key, fixture_file("test.mp3")) { |f| file_name = f }
|
27
|
+
|
28
|
+
expect(file_name).to eq(:not_called)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "syncs the same file twice if the contents change" do
|
32
|
+
unique_key = "test/#{SecureRandom.hex}"
|
33
|
+
file_name = :not_called
|
34
|
+
|
35
|
+
s3_gateway.sync(unique_key, fixture_file("test.mp3"))
|
36
|
+
s3_gateway.sync(unique_key, fixture_file("test.txt")) { |f| file_name = f }
|
37
|
+
|
38
|
+
expect(file_name).to eq(unique_key)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "makes the file publicly accessible" do
|
42
|
+
unique_key = "test/#{SecureRandom.hex}"
|
43
|
+
|
44
|
+
s3_gateway.sync(unique_key, fixture_file("test.txt"))
|
45
|
+
|
46
|
+
url = URI.parse(s3_gateway.url(unique_key))
|
47
|
+
content = File.read(fixture_file("test.txt"))
|
48
|
+
expect(Net::HTTP.get(url)).to eq(content)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe SecretTokenGenerator do
|
3
|
+
let(:generator) { isolate(SecretTokenGenerator) }
|
4
|
+
|
5
|
+
it "generates 16-character strings" do
|
6
|
+
expect(generator.generate.size).to eq(16)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "generates unique strings" do
|
10
|
+
expect(generator.generate).not_to eq(generator.generate)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe GetterSetterMethod do
|
3
|
+
context "without a default value" do
|
4
|
+
klass = Class.new do
|
5
|
+
extend GetterSetterMethod
|
6
|
+
|
7
|
+
get_set :foo
|
8
|
+
get_set :bar
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns nil by default" do
|
12
|
+
instance = klass.new
|
13
|
+
|
14
|
+
expect(instance.foo).to be_nil
|
15
|
+
expect(instance.bar).to be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "sets the value when value given" do
|
19
|
+
instance = klass.new
|
20
|
+
|
21
|
+
instance.foo "bar"
|
22
|
+
|
23
|
+
expect(instance.foo).to eq("bar")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "does not overwrite other values when setting one property" do
|
27
|
+
instance = klass.new
|
28
|
+
|
29
|
+
instance.foo "bar"
|
30
|
+
|
31
|
+
expect(instance.bar).to be_nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "with a default value" do
|
36
|
+
klass = Class.new do
|
37
|
+
extend GetterSetterMethod
|
38
|
+
|
39
|
+
get_set(:foo) { bar }
|
40
|
+
get_set :bar
|
41
|
+
get_set(:baz) { "hello" }
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns the default value" do
|
45
|
+
instance = klass.new
|
46
|
+
|
47
|
+
expect(instance.baz).to eq("hello")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "overwrites the value when value given" do
|
51
|
+
instance = klass.new
|
52
|
+
|
53
|
+
instance.baz "aaa"
|
54
|
+
|
55
|
+
expect(instance.baz).to eq("aaa")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "evaluates the default block lazily" do
|
59
|
+
instance = klass.new
|
60
|
+
|
61
|
+
instance.bar "aaa"
|
62
|
+
|
63
|
+
expect(instance.foo).to eq("aaa")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "caches the value once set" do
|
67
|
+
instance = klass.new
|
68
|
+
|
69
|
+
instance.bar "aaa"
|
70
|
+
instance.foo
|
71
|
+
instance.bar "bbb"
|
72
|
+
|
73
|
+
expect(instance.foo).to eq("aaa")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module AudioFeedManager
|
2
|
+
describe UniqueIdGenerator do
|
3
|
+
fake(:directory_lister)
|
4
|
+
|
5
|
+
let(:generator) { isolate(UniqueIdGenerator) }
|
6
|
+
|
7
|
+
it "generates ids based on the given name" do
|
8
|
+
stub(directory_lister).list("/foo") { [] }
|
9
|
+
|
10
|
+
id = generator.generate("Hello World!", "/foo")
|
11
|
+
|
12
|
+
expect(id).to eq("hello-world")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "suffixes the id with a number if the name is not unique" do
|
16
|
+
stub(directory_lister).list("/foo") { ["hello-world", "foo-bar"] }
|
17
|
+
|
18
|
+
id = generator.generate("Hello World!", "/foo")
|
19
|
+
|
20
|
+
expect(id).to eq("hello-world-1")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello!
|
data/spec/help_spec.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
describe "help commands" do
|
4
|
+
let(:stdin) { StringIO.new }
|
5
|
+
let(:stderr) { StringIO.new }
|
6
|
+
|
7
|
+
it "prints help when no arguments given" do
|
8
|
+
AudioFeedManager.run(
|
9
|
+
argv: [],
|
10
|
+
stdin: stdin,
|
11
|
+
stderr: stderr,
|
12
|
+
)
|
13
|
+
|
14
|
+
expect(stderr.string).to include("Usage:")
|
15
|
+
expect(stderr.string).to include("init")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "prints help with the help command" do
|
19
|
+
AudioFeedManager.run(
|
20
|
+
argv: ["help"],
|
21
|
+
stdin: stdin,
|
22
|
+
stderr: stderr,
|
23
|
+
)
|
24
|
+
|
25
|
+
expect(stderr.string).to include("Usage:")
|
26
|
+
expect(stderr.string).to include("init")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "prints help with an unknown command" do
|
30
|
+
AudioFeedManager.run(
|
31
|
+
argv: ["asdfasdfa"],
|
32
|
+
stdin: stdin,
|
33
|
+
stderr: stderr,
|
34
|
+
exit: ->(out) {}
|
35
|
+
)
|
36
|
+
|
37
|
+
expect(stderr.string).to include("Usage:")
|
38
|
+
expect(stderr.string).to include("init")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "prints help for specific commands" do
|
42
|
+
AudioFeedManager.run(
|
43
|
+
argv: ["help", "init"],
|
44
|
+
stdin: stdin,
|
45
|
+
stderr: stderr,
|
46
|
+
)
|
47
|
+
|
48
|
+
expect(stderr.string).to include("Usage:")
|
49
|
+
expect(stderr.string).to include("init")
|
50
|
+
expect(stderr.string).to include("<PROJECT_DIR>")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "prints help for multi-word commands" do
|
54
|
+
AudioFeedManager.run(
|
55
|
+
argv: ["help", "feeds", "add"],
|
56
|
+
stdin: stdin,
|
57
|
+
stderr: stderr,
|
58
|
+
)
|
59
|
+
|
60
|
+
expect(stderr.string).to include("Usage:")
|
61
|
+
expect(stderr.string).to include("feeds add")
|
62
|
+
expect(stderr.string).to include("<TITLE>")
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
describe "Initializing project" do
|
2
|
+
it "creates the project directory and some support files/directories" do
|
3
|
+
FileUtils.rm_rf("/tmp/my-test-project")
|
4
|
+
|
5
|
+
init_project("/tmp/my-test-project")
|
6
|
+
|
7
|
+
expect(File.exists?("/tmp/my-test-project")).to be(true)
|
8
|
+
expect(File.exists?("/tmp/my-test-project/feeds")).to be(true)
|
9
|
+
expect(File.exists?("/tmp/my-test-project/audio_files")).to be(true)
|
10
|
+
expect(File.exists?("/tmp/my-test-project/config.yml")).to be(true)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
describe "Managing audio files" do
|
2
|
+
it "adds audio files to feeds" do
|
3
|
+
dir = init_project
|
4
|
+
feed = add_feed(dir)
|
5
|
+
|
6
|
+
AudioFeedManager.run(
|
7
|
+
pwd: dir,
|
8
|
+
stdout: StringIO.new,
|
9
|
+
argv: ["audio", "add", feed.id, fixture_file("test.mp3")]
|
10
|
+
)
|
11
|
+
|
12
|
+
out = StringIO.new
|
13
|
+
AudioFeedManager.run(
|
14
|
+
pwd: dir,
|
15
|
+
stdout: out,
|
16
|
+
argv: ["feeds", "show", feed.id]
|
17
|
+
)
|
18
|
+
|
19
|
+
expect(out.string).to include("My first audio file")
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
describe "Managing Feeds" do
|
2
|
+
it "adds feeds using afm feeds add" do
|
3
|
+
dir = init_project
|
4
|
+
|
5
|
+
AudioFeedManager.run(
|
6
|
+
pwd: dir,
|
7
|
+
stdin: StringIO.new("some description"),
|
8
|
+
stdout: StringIO.new,
|
9
|
+
argv: ["feeds", "add", "Hello World!"]
|
10
|
+
)
|
11
|
+
|
12
|
+
stdout = StringIO.new
|
13
|
+
AudioFeedManager.run(
|
14
|
+
pwd: dir,
|
15
|
+
argv: ["feeds", "list"],
|
16
|
+
stdout: stdout,
|
17
|
+
)
|
18
|
+
|
19
|
+
expect(stdout.string).to include("Hello World!")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "allows getting the feed url" do
|
23
|
+
dir = init_project
|
24
|
+
feed = add_feed(dir)
|
25
|
+
|
26
|
+
out = StringIO.new
|
27
|
+
AudioFeedManager.run(
|
28
|
+
pwd: dir,
|
29
|
+
stdout: out,
|
30
|
+
argv: ["feeds", "get-url", feed.id]
|
31
|
+
)
|
32
|
+
|
33
|
+
expect(out.string).to include("http")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "allows regenerating feed rss" do
|
37
|
+
dir = init_project
|
38
|
+
feed = add_feed(dir)
|
39
|
+
|
40
|
+
rss_files = File.join(dir, "rss/*.xml")
|
41
|
+
Dir[rss_files].each{|f| FileUtils.rm_rf(f)}
|
42
|
+
|
43
|
+
AudioFeedManager.run(
|
44
|
+
pwd: dir,
|
45
|
+
stdout: StringIO.new,
|
46
|
+
argv: ["feeds", "update-rss", feed.id]
|
47
|
+
)
|
48
|
+
|
49
|
+
expect(Dir[rss_files]).not_to eq([])
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
describe "Publishing content to S3", :slow do
|
4
|
+
it "publishes the RSS and data files" do
|
5
|
+
dir = init_project
|
6
|
+
feed = add_feed(dir)
|
7
|
+
add_audio_file(dir, feed)
|
8
|
+
|
9
|
+
AudioFeedManager.run(
|
10
|
+
pwd: dir,
|
11
|
+
stdout: StringIO.new,
|
12
|
+
argv: ["publish"]
|
13
|
+
)
|
14
|
+
|
15
|
+
AudioFeedManager.run(
|
16
|
+
pwd: dir,
|
17
|
+
stdout: out = StringIO.new,
|
18
|
+
argv: ["feeds", "get-url", feed.id]
|
19
|
+
)
|
20
|
+
feed_url = out.string.chomp
|
21
|
+
|
22
|
+
expect(Net::HTTP.get(URI.parse(feed_url))).to include("Hello World!")
|
23
|
+
end
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'audio-feed-manager'
|
2
|
+
require 'bogus/rspec'
|
3
|
+
require 'dependor/rspec'
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
Dir[File.expand_path("../support/**/*.rb", __FILE__)].each do |file|
|
7
|
+
require file
|
8
|
+
end
|
9
|
+
|
10
|
+
Bogus.configure do |config|
|
11
|
+
config.search_modules = [AudioFeedManager]
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec.configure do |config|
|
15
|
+
config.include IntegrationHelpers
|
16
|
+
config.include Builders
|
17
|
+
end
|