popcap 0.7.2 → 0.8.0

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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +0 -1
  3. data/Gemfile.lock +23 -32
  4. data/README.md +27 -24
  5. data/lib/pop_cap/audio_file.rb +13 -11
  6. data/lib/pop_cap/class_support.rb +73 -0
  7. data/lib/pop_cap/{commander.rb → ffmpeg/commander.rb} +8 -2
  8. data/lib/pop_cap/ffmpeg/converter.rb +57 -0
  9. data/lib/pop_cap/ffmpeg/ffmpeg.rb +45 -0
  10. data/lib/pop_cap/ffmpeg/tag_reader.rb +45 -0
  11. data/lib/pop_cap/ffmpeg/tag_writer.rb +44 -0
  12. data/lib/pop_cap/formatter.rb +62 -0
  13. data/lib/pop_cap/formatters/bit_rate.rb +5 -7
  14. data/lib/pop_cap/formatters/date.rb +12 -10
  15. data/lib/pop_cap/formatters/duration.rb +10 -12
  16. data/lib/pop_cap/formatters/filesize.rb +6 -8
  17. data/lib/pop_cap/tag/formatted_tag.rb +31 -0
  18. data/lib/pop_cap/tag/tag_hash.rb +55 -0
  19. data/lib/pop_cap/{tag_struct.rb → tag/tag_struct.rb} +2 -0
  20. data/lib/pop_cap/taggable.rb +50 -30
  21. data/lib/pop_cap/version.rb +1 -1
  22. data/popcap.gemspec +1 -2
  23. data/spec/integration/convert_audio_file_spec.rb +2 -2
  24. data/spec/integration/read_metatags_spec.rb +1 -1
  25. data/spec/integration/update_metatags_spec.rb +1 -1
  26. data/spec/lib/pop_cap/audio_file_spec.rb +3 -9
  27. data/spec/lib/pop_cap/class_support_spec.rb +59 -0
  28. data/spec/lib/pop_cap/{commander_spec.rb → ffmpeg/commander_spec.rb} +1 -1
  29. data/spec/lib/pop_cap/ffmpeg/converter_spec.rb +92 -0
  30. data/spec/lib/pop_cap/ffmpeg/ffmpeg_spec.rb +37 -0
  31. data/spec/lib/pop_cap/ffmpeg/tag_reader_spec.rb +67 -0
  32. data/spec/lib/pop_cap/ffmpeg/tag_writer_spec.rb +60 -0
  33. data/spec/lib/pop_cap/fileable_spec.rb +5 -5
  34. data/spec/lib/pop_cap/formatter_spec.rb +71 -0
  35. data/spec/lib/pop_cap/formatters/bit_rate_spec.rb +8 -0
  36. data/spec/lib/pop_cap/formatters/date_spec.rb +8 -0
  37. data/spec/lib/pop_cap/formatters/duration_spec.rb +8 -0
  38. data/spec/lib/pop_cap/formatters/filesize_spec.rb +8 -0
  39. data/spec/lib/pop_cap/tag/formatted_tag_spec.rb +29 -0
  40. data/spec/lib/pop_cap/tag/tag_hash_spec.rb +35 -0
  41. data/spec/lib/pop_cap/{tag_struct_spec.rb → tag/tag_struct_spec.rb} +5 -1
  42. data/spec/lib/pop_cap/taggable_spec.rb +24 -10
  43. data/spec/spec_helper.rb +0 -3
  44. data/spec/support/popcap_spec_helper.rb +50 -33
  45. metadata +40 -56
  46. data/lib/pop_cap/converter.rb +0 -40
  47. data/lib/pop_cap/ffmpeg.rb +0 -130
  48. data/lib/pop_cap/formatters.rb +0 -33
  49. data/lib/pop_cap/helper.rb +0 -53
  50. data/lib/pop_cap/tag_key.rb +0 -32
  51. data/lib/pop_cap/tag_line.rb +0 -36
  52. data/spec/lib/pop_cap/converter_spec.rb +0 -67
  53. data/spec/lib/pop_cap/ffmpeg_spec.rb +0 -96
  54. data/spec/lib/pop_cap/formatters_spec.rb +0 -36
  55. data/spec/lib/pop_cap/helper_spec.rb +0 -42
  56. data/spec/lib/pop_cap/tag_key_spec.rb +0 -48
  57. data/spec/lib/pop_cap/tag_line_spec.rb +0 -26
  58. /data/spec/{support → fixtures}/sample.flac +0 -0
@@ -1,13 +1,11 @@
1
+ require 'pop_cap/formatter'
2
+
1
3
  module PopCap
2
4
  module Formatters
3
5
  # Public: This will format a duration tag as strftime.
4
6
  #
5
7
  # time - Provide a string, float, or integer.
6
- class Duration
7
- def initialize(time)
8
- @time = time
9
- end
10
-
8
+ class Duration < Formatter
11
9
  # Public: This will format a duration tag as strftime.
12
10
  # It will raise a warning if the time is greater than 24 hours.
13
11
  # Leading zeroes & colons are removed.
@@ -18,22 +16,22 @@ module PopCap
18
16
  # # => '7:00'
19
17
  #
20
18
  def format
21
- return unless @time.to_i > 0
19
+ return unless value.to_i > 0
22
20
  return warning_message if over_twenty_four_hours?
23
- remove_leading_zeroes(to_strftime)
21
+ human_readable_time
24
22
  end
25
23
 
26
24
  private
27
- def to_strftime
28
- @strftime = Time.at(@time.to_f).gmtime.strftime('%H:%M:%S')
25
+ def human_readable_time
26
+ to_strftime.sub(/^(0+|:)+/,'')
29
27
  end
30
28
 
31
- def remove_leading_zeroes(strftime)
32
- @strftime.sub(/^(0+|:)+/,'')
29
+ def to_strftime
30
+ Time.at(value.to_f).gmtime.strftime('%H:%M:%S')
33
31
  end
34
32
 
35
33
  def over_twenty_four_hours?
36
- @time.to_i > 86399
34
+ value.to_i > 86399
37
35
  end
38
36
 
39
37
  def warning_message
@@ -1,3 +1,5 @@
1
+ require 'pop_cap/formatter'
2
+
1
3
  module PopCap
2
4
  module Formatters
3
5
  # Public: This class formats a filesize as human readable,
@@ -5,14 +7,10 @@ module PopCap
5
7
  #
6
8
  # filesize - Provide a filesize as string, integer, or float.
7
9
  #
8
- class Filesize
10
+ class Filesize < Formatter
9
11
  ::BASE = 1024
10
12
  ::UNITS = %W{B K M G T}
11
13
 
12
- def initialize(filesize)
13
- @filesize = filesize
14
- end
15
-
16
14
  # Public: This method will format the filesize.
17
15
  # It raises a warning message if size is greater than 999 terabytes.
18
16
  #
@@ -22,7 +20,7 @@ module PopCap
22
20
  # # => '11.8M'
23
21
  #
24
22
  def format
25
- return if @filesize.to_i == 0
23
+ return if value.to_i == 0
26
24
  return warning_message if too_large?
27
25
  converted_filesize.to_s + measurement_character
28
26
  end
@@ -42,7 +40,7 @@ module PopCap
42
40
  end
43
41
 
44
42
  def float
45
- Float(@filesize)
43
+ Float(value)
46
44
  end
47
45
 
48
46
  def is_zero_decimal?
@@ -58,7 +56,7 @@ module PopCap
58
56
  end
59
57
 
60
58
  def too_large?
61
- @filesize.to_i > 1099400000000000
59
+ value.to_i > 1099400000000000
62
60
  end
63
61
 
64
62
  def warning_message
@@ -0,0 +1,31 @@
1
+ module PopCap
2
+ # Public: This class will apply a provided Formatter to
3
+ # the supplied value.
4
+ #
5
+ class FormattedTag
6
+ attr_reader :formatter, :value
7
+
8
+ # Public: To construct an instance, provide a Formatter
9
+ # and the value to format.
10
+ #
11
+ # formatter - A class of type Formatters::Formatter.
12
+ # value - The value to format.
13
+ #
14
+ def initialize(formatter, value)
15
+ @formatter, @value = formatter, value
16
+ end
17
+
18
+ # Public: This returns the formatted value.
19
+ #
20
+ def format
21
+ formatter.format(value)
22
+ end
23
+
24
+ # Public: A class level method that initializes the class
25
+ # and formats the value.
26
+ #
27
+ def self.format(formatter, value)
28
+ new(formatter, value).format
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,55 @@
1
+ require 'json'
2
+
3
+ module PopCap
4
+ # Public: This class formats the JSON output of TagReader.
5
+ #
6
+ class TagHash
7
+ attr_reader :json
8
+
9
+ def initialize(json)
10
+ @json = json
11
+ end
12
+
13
+ # Public: This method returns a Ruby hash.
14
+ # The keys have been converted to symbols.
15
+ #
16
+ def hash
17
+ renamed_hash.reject { |key,_| key == :size }
18
+ end
19
+
20
+ # Public: This method wraps #new & #hash.
21
+ #
22
+ def self.hash(json)
23
+ new(json).hash
24
+ end
25
+
26
+ private
27
+ def renamed_hash
28
+ symbolized_hash.merge({filesize: size_element})
29
+ end
30
+
31
+ def symbolized_hash
32
+ Hash[merged_hashes.map { |key,val| [key.downcase.to_sym, val] }]
33
+ end
34
+
35
+ def merged_hashes
36
+ format_hash.merge(tags_hash)
37
+ end
38
+
39
+ def size_element
40
+ format_hash['size']
41
+ end
42
+
43
+ def format_hash
44
+ @format ||= parsed_json.reject { |key,_| key == 'tags' }
45
+ end
46
+
47
+ def tags_hash
48
+ parsed_json['tags']
49
+ end
50
+
51
+ def parsed_json
52
+ @parsed ||= JSON.parse(json)['format']
53
+ end
54
+ end
55
+ end
@@ -11,6 +11,8 @@ module PopCap
11
11
  # ts.date => 1984
12
12
  #
13
13
  class TagStruct
14
+ include Enumerable
15
+
14
16
  def initialize(hash)
15
17
  raise(ArgumentError, argument_error_message) unless hash.kind_of?(Hash)
16
18
  @hash = hash
@@ -1,21 +1,48 @@
1
- require 'pop_cap/helper'
2
- require 'pop_cap/formatters'
3
- require 'pop_cap/tag_line'
4
- require 'pop_cap/tag_struct'
1
+ require 'pop_cap/class_support'
2
+ require 'pop_cap/formatter'
3
+ require 'pop_cap/tag/formatted_tag'
4
+ require 'pop_cap/tag/tag_hash'
5
+ require 'pop_cap/tag/tag_struct'
5
6
 
6
7
  module PopCap
7
- # Internal: This module is included in anything with a #raw_tags
8
+ # Public: This module is included in anything with a #raw_tags
8
9
  # attribute. It is used to parse and build tags from FFmpeg raw output.
9
10
  #
10
11
  module Taggable
11
- include Formatters
12
-
13
- # Internal: This method reloads memoized tags.
12
+ # Public: This method reloads memoized tags.
13
+ #
14
14
  def reload!
15
- @lined, @tags, @hash = nil, nil, nil
15
+ @unformatted_hash, @formatted_hash, @tag_struct = nil, nil, nil
16
+ end
17
+
18
+ # Public: This method builds an unformatted hash of tags.
19
+ #
20
+ # Examples
21
+ # class SomeClass
22
+ # def raw_tags
23
+ # end
24
+ # end
25
+ #
26
+ # klass = SomeClass.new
27
+ # klass.unformatted
28
+ # # =>
29
+ # { filename: 'spec/fixtures/sample.flac',
30
+ # format_name: 'flac',
31
+ # duration: '1.000000',
32
+ # filesize: '18291',
33
+ # bit_rate: '146328',
34
+ # genre: 'Sample Genre',
35
+ # track: '01',
36
+ # album: 'Sample Album',
37
+ # date: '2012',
38
+ # title: 'Sample Title',
39
+ # artist: 'Sample Artist' }
40
+ #
41
+ def unformatted(tag_hash: TagHash)
42
+ @unformatted_hash ||= tag_hash.hash(self.raw_tags)
16
43
  end
17
44
 
18
- # Internal: This method builds a sanitized hash from #raw_tags.
45
+ # Public: This method builds an unformatted hash of tags.
19
46
  #
20
47
  # Examples
21
48
  # class SomeClass
@@ -24,9 +51,9 @@ module PopCap
24
51
  # end
25
52
  #
26
53
  # klass = SomeClass.new
27
- # klass.to_hash
54
+ # klass.unformatted
28
55
  # # =>
29
- # { filename: 'spec/support/sample.flac',
56
+ # { filename: 'spec/fixtures/sample.flac',
30
57
  # format_name: 'flac',
31
58
  # duration: '1.000000',
32
59
  # filesize: '18291',
@@ -38,8 +65,8 @@ module PopCap
38
65
  # title: 'Sample Title',
39
66
  # artist: 'Sample Artist' }
40
67
  #
41
- def to_hash
42
- @hash ||= lined_hash.merge(formatted_hash)
68
+ def formatted
69
+ @formatted_hash ||= unformatted.merge(formatted_tags)
43
70
  end
44
71
 
45
72
  # Public: This method builds an tag structure from #to_hash. Also,
@@ -60,7 +87,7 @@ module PopCap
60
87
  # .bit_rate => '146 kb/s'
61
88
  # .date => 2012
62
89
  # .duration => '1'
63
- # .filename => 'spec/support/sample.flac'
90
+ # .filename => 'spec/fixtures/sample.flac'
64
91
  # .filesize => '17.9K'
65
92
  # .format_long_name => 'raw FLAC'
66
93
  # .format_name => 'flac'
@@ -71,30 +98,23 @@ module PopCap
71
98
  # .track => '01'
72
99
  #
73
100
  def tags
74
- @tags ||= build_tag_struct(to_hash)
101
+ @tag_struct ||= build_tag_struct(formatted)
75
102
  end
76
103
 
77
104
  private
78
- def lines
79
- self.raw_tags.split("\n")
80
- end
81
-
82
105
  def build_tag_struct(hash)
83
106
  TagStruct.new(hash)
84
107
  end
85
108
 
86
- def lined_hash
87
- @lined ||=
88
- lines.inject({}) { |hsh,line| hsh.merge(TagLine.new(line)).to_hash }
109
+ def formatted_tags(support: ClassSupport)
110
+ Formatters::Formatter.subclasses.inject({}) do |formatted, formatter|
111
+ attribute = support.new(formatter).symbolize
112
+ formatted.merge({attribute => format(formatter, attribute)})
113
+ end
89
114
  end
90
115
 
91
- def formatted_hash
92
- ::INCLUDED_FORMATTERS.inject({}) do |formatted, formatter|
93
- key, value = formatter
94
- helper = Helper.new(value)
95
- klass = helper.constantize
96
- formatted.merge({key => klass.new(lined_hash[key]).format})
97
- end
116
+ def format(formatter, attribute, tag: FormattedTag)
117
+ tag.format(formatter, unformatted[attribute])
98
118
  end
99
119
  end
100
120
  end
@@ -1,3 +1,3 @@
1
1
  module PopCap
2
- VERSION = '0.7.2'
2
+ VERSION = '0.8.0'
3
3
  end
data/popcap.gemspec CHANGED
@@ -13,12 +13,11 @@ Gem::Specification.new do |s|
13
13
  s.summary = %q{A library work with audio files on the filesystem .}
14
14
  s.description = %q{Read & write metadata tags, convert audio files to alternate formats, manage files on the filesystem.}
15
15
 
16
- s.required_ruby_version = '>= 1.9.3'
16
+ s.required_ruby_version = '>= 2.0.0'
17
17
  s.required_rubygems_version = '>= 1.3.6'
18
18
 
19
19
  s.add_development_dependency 'reek', '~> 1.2'
20
20
  s.add_development_dependency 'rspec', '~> 2.11'
21
- s.add_development_dependency 'simplecov', '~> 0.7'
22
21
 
23
22
  git_files = `git ls-files -z`.split("\0") rescue ''
24
23
  s.files = git_files
@@ -7,9 +7,9 @@ module PopCap
7
7
  after { PopCapSpecHelper.remove_converted }
8
8
 
9
9
  it 'creates a new audio file with the specified format & bitrate' do
10
- audio_file = AudioFile.new('spec/support/sample.flac')
10
+ audio_file = AudioFile.new(PopCapSpecHelper::SAMPLE_FILE)
11
11
  audio_file.convert(:mp3, 128)
12
- expect(File.exists?('spec/support/sample.mp3')).to be_true
12
+ expect(File.exists?('spec/fixtures/sample.mp3')).to be_true
13
13
  end
14
14
  end
15
15
  end
@@ -4,7 +4,7 @@ require 'support/popcap_spec_helper'
4
4
 
5
5
  describe PopCap do
6
6
  let(:audio_file) { PopCap::AudioFile.new(filepath) }
7
- let(:filepath) { 'spec/support/sample.flac' }
7
+ let(:filepath) { PopCapSpecHelper::SAMPLE_FILE }
8
8
 
9
9
  it '#raw_tags' do
10
10
  expect(audio_file.raw_tags).to eq PopCapSpecHelper.raw_tags
@@ -4,7 +4,7 @@ require 'support/popcap_spec_helper'
4
4
 
5
5
  describe PopCap do
6
6
  let(:audio_file) { PopCap::AudioFile.new(filepath) }
7
- let(:filepath) { 'spec/support/sample.flac' }
7
+ let(:filepath) { PopCapSpecHelper::SAMPLE_FILE }
8
8
 
9
9
  context '#update_tags' do
10
10
  before { PopCapSpecHelper.setup }
@@ -5,7 +5,7 @@ require 'support/popcap_spec_helper'
5
5
  module PopCap
6
6
  describe AudioFile do
7
7
  let(:audio_file) { AudioFile.new(filepath) }
8
- let(:filepath) { 'spec/support/sample.flac' }
8
+ let(:filepath) { PopCapSpecHelper::SAMPLE_FILE }
9
9
  let(:included_modules) { AudioFile.included_modules }
10
10
 
11
11
  before { PopCapSpecHelper.setup }
@@ -50,22 +50,16 @@ module PopCap
50
50
  context '#reload!' do
51
51
  it 'reloads raw tags' do
52
52
  audio_file.raw_tags
53
+ expect(audio_file.instance_variable_get('@raw')).not_to be_nil
53
54
  audio_file.reload!
54
55
  expect(audio_file.instance_variable_get('@raw')).to be_nil
55
56
  end
56
-
57
- it 'calls up to Taggable#reload!' do
58
- audio_file.raw_tags
59
- audio_file.reload!
60
- expect(audio_file.instance_variable_get('@tags')).to be_nil
61
- expect(audio_file.instance_variable_get('@to_hash')).to be_nil
62
- end
63
57
  end
64
58
 
65
59
  context '#update_tags' do
66
60
  it 'reloads after tags updated' do
67
61
  audio_file.should_receive(:reload!)
68
- expect(audio_file.update_tags({foo: 'foo'}))
62
+ audio_file.update_tags({foo: 'foo'})
69
63
  end
70
64
  end
71
65
  end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+ require 'pop_cap/class_support'
3
+
4
+ module PopCap
5
+ describe ClassSupport do
6
+ context '#camelize' do
7
+ it 'converts to CamelCase' do
8
+ maker = ClassSupport.new('one_two')
9
+ expect(maker.camelize).to eq('OneTwo')
10
+ end
11
+
12
+ it 'handles symbols' do
13
+ maker = ClassSupport.new(:one_two_three)
14
+ expect(maker.camelize).to eq('OneTwoThree')
15
+ end
16
+ end
17
+
18
+ context '#symbolize' do
19
+ it 'returns a symbol' do
20
+ maker = ClassSupport.new('One')
21
+ expect(maker.symbolize).to eq(:one)
22
+ end
23
+
24
+ it 'handles CamelCase' do
25
+ maker = ClassSupport.new('OneTwo')
26
+ expect(maker.symbolize).to eq(:one_two)
27
+ end
28
+
29
+ it 'demodulizes the symbol' do
30
+ maker = ClassSupport.new('One::Two::ThreeFour')
31
+ expect(maker.symbolize).to eq(:three_four)
32
+ end
33
+ end
34
+
35
+ context '#namespace' do
36
+ it 'accounts for namespacing with a forward slash' do
37
+ maker = ClassSupport.new('one/two/three_four')
38
+ expect(maker.namespace).to eq('One::Two::ThreeFour')
39
+ end
40
+
41
+ it 'accounts for mixed case in namespacing' do
42
+ maker = ClassSupport.new('One/Two/Three_Four')
43
+ expect(maker.namespace).to eq('One::Two::ThreeFour')
44
+ end
45
+ end
46
+
47
+ context '#constantize' do
48
+ it 'converts to a constant' do
49
+ maker = ClassSupport.new('array')
50
+ expect(maker.constantize).to eq(Array)
51
+ end
52
+
53
+ it 'handles module namespacing' do
54
+ maker = ClassSupport.new('file/stat')
55
+ expect(maker.constantize).to eq(File::Stat)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
- require 'pop_cap/commander'
2
+ require 'pop_cap/ffmpeg/commander'
3
3
 
4
4
  module PopCap
5
5
  describe Commander do
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+ require 'pop_cap/ffmpeg/converter'
3
+
4
+ module PopCap
5
+ describe Converter do
6
+ let(:bitrate) { %W{-ab 192k}}
7
+ let(:command) { input + bitrate + output_path }
8
+ let(:commander) { double('commander') }
9
+ let(:filepath) { 'path/to/file.flac' }
10
+ let(:input) { %W{ffmpeg -i #{filepath}} }
11
+ let(:instance) { double('converter_instance') }
12
+
13
+ def shared_expectation(command=command)
14
+ commander.should_receive(:new).with(*command) { instance }
15
+ instance.stub_chain(:execute, :success?) { true }
16
+ end
17
+
18
+ describe '.convert' do
19
+ let(:output_path) { %W{path/to/file.ogg} }
20
+
21
+ it 'has a class method for #convert' do
22
+ shared_expectation
23
+ Converter.convert(filepath, {format: 'ogg', commander: commander})
24
+ end
25
+ end
26
+
27
+ describe '#convert' do
28
+ let(:output_path) { %W{path/to/file.ogg} }
29
+
30
+ context 'format' do
31
+ it 'handles a string' do
32
+ shared_expectation
33
+ Converter.new(filepath, {format: 'ogg', commander: commander}).convert
34
+ end
35
+
36
+ it 'handles a symbol' do
37
+ shared_expectation
38
+ Converter.new(filepath, {format: :ogg, commander: commander}).convert
39
+ end
40
+
41
+ it 'is case insenstive' do
42
+ shared_expectation
43
+ Converter.new(filepath, {format: 'OGG', commander: commander}).convert
44
+ end
45
+ end
46
+
47
+ context 'bitrate' do
48
+ let(:output_path) { %W{path/to/file.mp3} }
49
+
50
+ it 'defaults to 192 kb/s' do
51
+ shared_expectation
52
+ Converter.new(filepath, {format: :mp3, commander: commander}).convert
53
+ end
54
+
55
+ it 'takes an optional bitrate' do
56
+ options = {format: :mp3, bitrate: 64, commander: commander}
57
+ bitrate_command = input + %W{-ab 64k} + output_path
58
+ shared_expectation(bitrate_command)
59
+ Converter.new(filepath, options).convert
60
+ end
61
+
62
+ it 'handles bitrate as string' do
63
+ options = {format: :mp3, bitrate: '128', commander: commander}
64
+ bitrate_command = input + %W{-ab 128k} + output_path
65
+ shared_expectation(bitrate_command)
66
+ Converter.new(filepath, options).convert
67
+ end
68
+ end
69
+
70
+ context 'm4a' do
71
+ let(:output_path) { %W{path/to/file.m4a} }
72
+
73
+ it 'uses strict mode' do
74
+ strict = input + %W{-strict -2} + bitrate + output_path
75
+ shared_expectation(strict)
76
+ Converter.new(filepath, {format: :m4a, commander: commander}).convert
77
+ end
78
+ end
79
+
80
+ context 'errors' do
81
+ it 'raises error if could not convert file' do
82
+ expect do
83
+ commander.should_receive(:new).with(*command) { instance }
84
+ instance.stub_chain(:execute, :success?) { false }
85
+ Converter.new(filepath, {format: :ogg,
86
+ commander: commander}).convert
87
+ end.to raise_error(FFmpegError, "Error converting #{filepath}.")
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'support/popcap_spec_helper'
3
+ require 'pop_cap/ffmpeg/ffmpeg'
4
+
5
+ module PopCap
6
+ describe FFmpeg do
7
+
8
+ let(:filepath) { File.realpath(PopCapSpecHelper::SAMPLE_FILE) }
9
+ let(:ffmpeg) { FFmpeg.new(filepath) }
10
+
11
+ it 'returns its filepath' do
12
+ expect(ffmpeg.filepath).to eq filepath
13
+ end
14
+
15
+ it 'sets default commander to Commander' do
16
+ expect(ffmpeg.commander).to eq Commander
17
+ end
18
+
19
+ it '#new takes an options hash' do
20
+ opts = {foo: 'foo'}
21
+ ffmpeg = FFmpeg.new(filepath, opts)
22
+ expect(ffmpeg.options).to eq({foo: 'foo'})
23
+ end
24
+
25
+ it 'has a custom error message' do
26
+ expect(ffmpeg.error_message('loving')).to eq "Error loving #{filepath}."
27
+ end
28
+
29
+ it 'raises error if FFmpeg not installed' do
30
+ error_message = 'No such file or directory - FFmpeg is not installed.'
31
+ expect do
32
+ Open3.stub(:capture3).with('ffmpeg').and_raise(Errno::ENOENT)
33
+ FFmpeg.new('filepath')
34
+ end.to raise_error(MissingDependency, error_message)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+ require 'pop_cap/ffmpeg/tag_reader'
3
+
4
+ module PopCap
5
+ describe TagReader do
6
+ let(:commander) { double('commander') }
7
+ let(:instance) { double('commander_instance') }
8
+ let(:file) { 'path/to/file.flac' }
9
+ let(:reader) { TagReader.new(file, {commander: commander}) }
10
+ let(:command) { %W{ffprobe -show_format -print_format json #{file}} }
11
+
12
+ let(:shared_example) do
13
+ commander.should_receive(:new).with(*command) { instance }
14
+ instance.stub_chain(:execute, :success?) { true }
15
+ instance.stub_chain(:execute, :stdout) { instance }
16
+ end
17
+
18
+ it 'test' do
19
+ puts JSON.parse(TagReader.read('spec/fixtures/sample.flac'))
20
+ end
21
+
22
+ describe '.read' do
23
+ before { shared_example }
24
+
25
+ it 'has a class method for #read' do
26
+ instance.stub(:valid_encoding?) { true }
27
+ JSON.stub(:load)
28
+ TagReader.read(file, {commander: commander})
29
+ end
30
+ end
31
+
32
+ describe '#read' do
33
+ before { shared_example }
34
+ after { reader.read }
35
+
36
+ it 'returns the output as JSON' do
37
+ instance.stub(:valid_encoding?) { true }
38
+ JSON.should_receive(:load).with(instance) { instance }
39
+ instance.should_receive(:to_json)
40
+ end
41
+
42
+ it 'does not encode valid byte strings' do
43
+ instance.stub(:valid_encoding?) { true }
44
+ JSON.stub(:load)
45
+ instance.should_not_receive(:encode!)
46
+ end
47
+
48
+ it 'encodes invalid byte strings as UTF-8' do
49
+ instance.stub(:valid_encoding?) { false }
50
+ instance.stub_chain(:encoding, :name) { 'UTF-8' }
51
+ instance.should_receive(:encode!).
52
+ with('UTF-16', 'UTF-8', undef: :replace, invalid: :replace)
53
+ instance.should_receive(:encode!).with('UTF-8')
54
+ end
55
+ end
56
+
57
+ context 'errors' do
58
+ it 'raises error if could not read tags' do
59
+ expect do
60
+ commander.should_receive(:new).with(*command) { instance }
61
+ instance.stub_chain(:execute, :success?) { false }
62
+ reader.read
63
+ end.to raise_error(FFmpegError, "Error reading #{file}.")
64
+ end
65
+ end
66
+ end
67
+ end