popcap 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 06018b8dc59e4e1f5e4a71499b2761a66263fcb3
4
- data.tar.gz: 75e7e1d1d0d817d2d53bebdf7be0ffba63f2cd54
3
+ metadata.gz: fe1804b885ed55227148832677e5697bd95d8ca8
4
+ data.tar.gz: f0d5ac62e3690a6aaaca546a7abc86a218268366
5
5
  SHA512:
6
- metadata.gz: fd92273467cde9d7ebc21c8717034bfa54ed26aeebb56b07374ca77917f248d14c0d76fb3e8e3c6fe70980754f60d06d4149a471e0cb77904c5583e39e2aa77c
7
- data.tar.gz: 343bf09d55d5e5f913a5cfc4b0e2d53ee88b039b7229a0c0889ee725396251952c66b4d3fbd5e3307240bc81e51407c18751e2eef7c4eff66f4f074f5a907a33
6
+ metadata.gz: 6c0bd62beca21f4fe86bee66638c69a594deb3418e1b9b12e6c5072dac4930482bc953c4f7404ab71e3fc3fefeb641b906e67d32fb7fa7debffa8d90df35992e
7
+ data.tar.gz: 7d11a95c9bc6829996d744764006ab049fbc5ac3b67eada66ae779aeb96475df35b71bfdcc07eda01cf9b73796556345258733abfbd4a543132f7ccf1775923e
data/README.md CHANGED
@@ -22,40 +22,71 @@ Read the metadata tags from an audio file.
22
22
  ```
23
23
  audio_file = PopCap::AudioFile.new('sample.flac')
24
24
 
25
- audio_file.raw_tags => Returns JSON for the raw output from running ffprobe -show_format.
26
-
27
- audio_file.unformatted => Returns a Ruby hash after sanitizing the raw output of #raw_tags.
28
- { filename: 'sample.flac',
29
- format_name: 'flac',
30
- format_long_name: 'raw FLAC',
31
- nb_streams: '1',
32
- duration: '1.000000',
33
- filesize: '18291',
34
- bit_rate: '146328',
35
- start_time: 'N/A',
36
- genre: 'Sample Genre',
37
- track: '01',
38
- album: 'Sample Album',
39
- date: '2012',
40
- title: 'Sample Title',
41
- artist: 'Sample Artist' }
42
-
43
- audio_file.formatted => Returns a Ruby hash after sanitizing the raw output of #raw_tags. It also applies internal formatters to make fields such as duration, bit_rate, filesize, & date human readable.
44
-
45
- { filename: 'sample.flac',
46
- format_name: 'flac',
47
- format_long_name: 'raw FLAC',
48
- nb_streams: '1',
49
- duration: '1.000000',
50
- filesize: '18291',
51
- bit_rate: '146328',
52
- start_time: 'N/A',
53
- genre: 'Sample Genre',
54
- track: '01',
55
- album: 'Sample Album',
56
- date: '2012',
57
- title: 'Sample Title',
58
- artist: 'Sample Artist' }
25
+ audio_file.raw_output => Returns JSON for the raw output from
26
+ running "ffprobe -show_format -print_format json."
27
+
28
+ {
29
+ "format":
30
+ {
31
+ "filename":"spec/fixtures/sample.flac",
32
+ "nb_streams":1,
33
+ "format_name":"flac",
34
+ "format_long_name":"raw FLAC",
35
+ "duration":"1.000000",
36
+ "size":"18291",
37
+ "bit_rate":"146328",
38
+
39
+ "tags":
40
+ {
41
+ "GENRE":"Sample Genre",
42
+ "track":"01",
43
+ "ALBUM":"Sample Album",
44
+ "DATE":"2012",
45
+ "TITLE":"Sample Title",
46
+ "ARTIST":"Sample Artist"
47
+ }
48
+ }
49
+ }
50
+
51
+ audio_file.unformatted => Returns a Ruby hash after sanitizing
52
+ the raw output of #raw_output.
53
+
54
+ {
55
+ filename: '$HOME/spec/fixtures/sample.flac',
56
+ nb_streams: 1,
57
+ format_name: 'flac',
58
+ format_long_name: 'raw FLAC',
59
+ duration: '1.000000',
60
+ filesize: '18291',
61
+ bit_rate: '146328',
62
+ genre: 'Sample Genre',
63
+ track: '01',
64
+ album: 'Sample Album',
65
+ date: '2012',
66
+ title: 'Sample Title',
67
+ artist: 'Sample Artist'
68
+ }
69
+
70
+ audio_file.formatted => Returns a Ruby hash after sanitizing
71
+ the raw output of #raw_output. It also applies internal formatters
72
+ on fields such as duration, bit_rate, filesize, & date,
73
+ returning human readable output.
74
+
75
+ {
76
+ filename: '$HOME/spec/fixtures/sample.flac',
77
+ nb_streams: 1,
78
+ format_name: 'flac',
79
+ format_long_name: 'raw FLAC',
80
+ duration: '1',
81
+ filesize: '17.9K',
82
+ bit_rate: '146 kb/s',
83
+ genre: 'Sample Genre',
84
+ track: '01',
85
+ album: 'Sample Album',
86
+ date: 2012,
87
+ title: 'Sample Title',
88
+ artist: 'Sample Artist'
89
+ }
59
90
 
60
91
  audio_file.tags => Returns a tag structure using the #formatted values.
61
92
 
@@ -64,38 +95,43 @@ audio_file.tags => Returns a tag structure using the #formatted values.
64
95
  .bit_rate => '146 kb/s'
65
96
  .date => 2012
66
97
  .duration => '1'
67
- .filename => 'spec/fixtures/sample.flac'
98
+ .filename => ''$HOME/spec/fixtures/sample.flac'
68
99
  .filesize => '17.9K'
69
100
  .format_long_name => 'raw FLAC'
70
101
  .format_name => 'flac'
71
102
  .genre => 'Sample Genre'
72
- .nb_streams => '1'
103
+ .nb_streams => 1
73
104
  .start_time => 'N/A'
74
105
  .title => 'Sample Title'
75
106
  .track => '01'
76
107
 
77
- audio_file.reload! => Reload an instance of itself, useful when updating tags. This behavior is built in, but will need to be called manually in certain situations (such as moving a file on the file system, deleting a file, etc.)
108
+ audio_file.reload! => Reload an instance of itself,
109
+ useful when updating tags. This behavior is built in,
110
+ but will need to be called manually in certain situations;
111
+ (such as moving a file on the file system, deleting a file, etc.)
78
112
  ```
79
113
 
80
114
  Update Tags
81
115
  -----------
82
116
 
83
- This will update the metadata tags for an audio file. It will also dynamically add any newly provided tags. It takes a hash of attributes.
117
+ This will update the metadata tags for an audio file.
118
+ It will also dynamically add any newly provided tags.
119
+ It takes a hash of attributes.
84
120
 
85
121
  ```
86
122
  audio_file = PopCap::AudioFile.new('sample.flac')
87
- audio_file.update_tags(artist: 'David Bowie'})
123
+ audio_file.update(artist: 'David Bowie')
88
124
 
89
- audio_file.update_tags(fancy_new_tag: 'Custom Tag Input')
125
+ audio_file.update(fancy_new_tag: 'Custom Tag Input')
90
126
  ```
91
127
 
92
128
  Convert
93
129
  -------
94
130
 
95
- This will convert between audio file formats. It is restricted to basic audio formats. It also takes an optional bitrate for mp3 formats. The original file is preserved during the conversion.
96
-
97
- Supported formats: aac, flac, m4a, mp3, ogg, wav
98
- Supported mp3 bitrates: 64, 128, 160, 192, 256, 320
131
+ This will convert between audio file formats.
132
+ It is restricted to basic audio formats.
133
+ It also takes an optional bitrate for mp3 formats.
134
+ The original file is preserved during the conversion.
99
135
 
100
136
  ```
101
137
  audio_file = PopCap::AudioFile.new('sample.flac')
@@ -128,7 +164,8 @@ audio_file.move('destination') # = > moves file to destination
128
164
 
129
165
  audio_file.rename('new_name.flac') # => renames file
130
166
 
131
- audio_file.restore # => restores file from backup_path, takes an optional path as well
167
+ audio_file.restore # => restores file from backup_path;
168
+ takes an optional path
132
169
 
133
170
  audio_file.tmppath # => returns the temporary path, e.g. '/tmp/sample.flac'
134
171
  ```
@@ -1,8 +1,10 @@
1
1
  require 'pop_cap/ffmpeg/converter'
2
2
  require 'pop_cap/ffmpeg/tag_reader'
3
3
  require 'pop_cap/ffmpeg/tag_writer'
4
+ require 'pop_cap/unformatted_hash'
5
+ require 'pop_cap/formatted_hash'
6
+ require 'pop_cap/tag_struct'
4
7
  require 'pop_cap/fileable'
5
- require 'pop_cap/taggable'
6
8
 
7
9
  module PopCap
8
10
  FileNotFound = Class.new(StandardError)
@@ -17,10 +19,10 @@ module PopCap
17
19
  #
18
20
  #
19
21
  class AudioFile
22
+ include Fileable
20
23
  attr_accessor :filepath
21
24
 
22
- include Fileable
23
- include Taggable
25
+ ::MEMOIZABLES = %w(@raw @unformatted_hash @formatted_hash @tag_struct)
24
26
 
25
27
  # Public: Initialize
26
28
  #
@@ -43,8 +45,8 @@ module PopCap
43
45
  # audio_file.convert('mp3', 128)
44
46
  # # => 'spec/fixtures/sample.mp3'
45
47
  #
46
- def convert(format, bitrate=192)
47
- Converter.convert(filepath, {format: format, bitrate: bitrate})
48
+ def convert(format, bitrate=192, converter: Converter)
49
+ converter.convert(filepath, {format: format, bitrate: bitrate})
48
50
  end
49
51
 
50
52
  # Public: raw_tags
@@ -54,25 +56,96 @@ module PopCap
54
56
  # audio_file = AudioFile.new('spec/fixtures/sample.flac')
55
57
  # audio_file.raw_tags
56
58
  # # =>
57
- # [FORMAT]
58
- # filename=spec/fixtures/sample.flac
59
- # nb_streams=1
60
- # format_name=flac
61
- # format_long_name=raw FLAC
62
- # start_time=N/A
63
- # duration=1.000000
64
- # size=18291
65
- # bit_rate=146328
66
- # TAG:GENRE=Sample Genre
67
- # TAG:track=01
68
- # TAG:ALBUM=Sample Album
69
- # TAG:DATE=2012
70
- # TAG:TITLE=Sample Title
71
- # TAG:ARTIST=Sample Artist
72
- # [/FORMAT]
73
- #
74
- def raw_tags
75
- @raw ||= TagReader.read(filepath)
59
+ #
60
+ # {
61
+ # "format":
62
+ # {
63
+ # "filename":"spec/fixtures/sample.flac",
64
+ # "nb_streams":1,
65
+ # "format_name":"flac",
66
+ # "format_long_name":"raw FLAC",
67
+ # "duration":"1.000000",
68
+ # "size":"18291",
69
+ # "bit_rate":"146328",
70
+ # "tags":
71
+ # {
72
+ # "GENRE":"Sample Genre",
73
+ # "track":"01",
74
+ # "ALBUM":"Sample Album",
75
+ # "DATE":"2012",
76
+ # "TITLE":"Sample Title",
77
+ # "ARTIST":"Sample Artist"
78
+ # }
79
+ # }
80
+ # }
81
+ #
82
+ def raw_output(tag_reader: TagReader)
83
+ @raw ||= tag_reader.read(filepath)
84
+ end
85
+
86
+ # Public: This method returns a sanitized version of #raw_tags.
87
+ #
88
+ # {
89
+ # filename: '$HOME/spec/fixtures/sample.flac',
90
+ # nb_streams: 1,
91
+ # format_name: 'flac',
92
+ # format_long_name: 'raw FLAC',
93
+ # duration: '1.000000',
94
+ # filesize: '18291',
95
+ # bit_rate: '146328',
96
+ # genre: 'Sample Genre',
97
+ # track: '01',
98
+ # album: 'Sample Album',
99
+ # date: '2012',
100
+ # title: 'Sample Title',
101
+ # artist: 'Sample Artist'
102
+ # }
103
+ #
104
+ def unformatted(unformatted_hash: UnformattedHash)
105
+ @unformatted_hash ||= unformatted_hash.hash(raw_output)
106
+ end
107
+
108
+ # Public: This method returns #unformatted tags with
109
+ # any available Formatters automatically applied.
110
+ #
111
+ # {
112
+ # filename: '$HOME/spec/fixtures/sample.flac',
113
+ # nb_streams: 1,
114
+ # format_name: 'flac',
115
+ # format_long_name: 'raw FLAC',
116
+ # duration: '1',
117
+ # filesize: '17.9K',
118
+ # bit_rate: '146 kb/s',
119
+ # genre: 'Sample Genre',
120
+ # track: '01',
121
+ # album: 'Sample Album',
122
+ # date: 2012,
123
+ # title: 'Sample Title',
124
+ # artist: 'Sample Artist'
125
+ # }
126
+ def formatted(formatted_hash: FormattedHash)
127
+ @formatted_hash ||= formatted_hash.formatted(unformatted)
128
+ end
129
+
130
+ # Public: This method builds a tag structure from #formatted.
131
+ #
132
+ # .album => 'Sample Album'
133
+ # .artist => 'Sample Artist'
134
+ # .bit_rate => '146 kb/s'
135
+ # .date => 2012
136
+ # .duration => '1'
137
+ # .filename => 'spec/fixtures/sample.flac'
138
+ # .filesize => '17.9K'
139
+ # .format_long_name => 'raw FLAC'
140
+ # .format_name => 'flac'
141
+ # .genre => 'Sample Genre'
142
+ # .nb_streams => '1'
143
+ # .start_time => 'N/A'
144
+ # .title => 'Sample Title'
145
+ # .track => '01'
146
+ #
147
+ def tags(tag_struct: TagStruct)
148
+ @tag_struct ||= tag_struct.new(formatted)
76
149
  end
77
150
 
78
151
  # Public: This method reloads the current instance.
@@ -81,20 +154,19 @@ module PopCap
81
154
  # audio_file.reload!
82
155
  #
83
156
  def reload!
84
- @raw = nil
85
- super
157
+ ::MEMOIZABLES.each { |var| self.instance_variable_set(var, nil) }
86
158
  end
87
159
 
88
- # Public: update_tags(updates)
160
+ # Public: update(updates)
89
161
  # Updates existing tags, adds a tag if it does not exist.
90
162
  #
91
- # updates - This takes a hash of keys matching a tag name with a value.
163
+ # updates - This takes a hash of tags.
92
164
  #
93
165
  # Examples
94
166
  #
95
- # audio_file.update_tags({artist: 'New Artist', album: 'New Album'})
167
+ # audio_file.update(artist: 'New Artist', album: 'New Album')
96
168
  #
97
- def update_tags(updates)
169
+ def update(updates={})
98
170
  TagWriter.write(filepath, updates)
99
171
  self.reload!
100
172
  end
@@ -0,0 +1,40 @@
1
+ require 'pop_cap/class_support'
2
+ require 'pop_cap/formatter'
3
+
4
+ module PopCap
5
+ # Public: This class will apply all Formatters to
6
+ # the supplied hash.
7
+ #
8
+ # new - Supply an unformatted hash.
9
+ #
10
+ class FormattedHash
11
+ def initialize(unformatted)
12
+ @unformatted = unformatted
13
+ end
14
+
15
+ # Public: This class will apply all Formatters to
16
+ # the supplied hash.
17
+ #
18
+ def formatted
19
+ @unformatted.merge(formatted_hash)
20
+ end
21
+
22
+ # Public: This wraps #new & #formatted.
23
+ #
24
+ def self.formatted(unformatted)
25
+ new(unformatted).formatted
26
+ end
27
+
28
+ private
29
+ def formatted_hash(formatters: Formatters::Formatter, support: ClassSupport)
30
+ formatters.subclasses.inject({}) do |formatted, formatter|
31
+ attribute = support.new(formatter).symbolize
32
+ formatted.merge(formatted_attribute(formatter, attribute))
33
+ end.reject { |_,val| val.nil? }
34
+ end
35
+
36
+ def formatted_attribute(formatter, attribute)
37
+ {attribute => formatter.format(@unformatted[attribute])}
38
+ end
39
+ end
40
+ end
@@ -16,6 +16,7 @@ module PopCap
16
16
  def initialize(hash)
17
17
  raise(ArgumentError, argument_error_message) unless hash.kind_of?(Hash)
18
18
  @hash = hash
19
+ @tags = {}
19
20
  define_instance_methods
20
21
  end
21
22
 
@@ -31,6 +32,14 @@ module PopCap
31
32
  "#<#{self.class.name} " + methods + '>'
32
33
  end
33
34
 
35
+ # Public: This method is a custom each iterator for tags.
36
+ #
37
+ def each(&block)
38
+ @tags.each do |tag|
39
+ block_given? ? block.call(tag) : tag
40
+ end
41
+ end
42
+
34
43
  private
35
44
  def argument_error_message
36
45
  'Initialize with a hash.'
@@ -40,6 +49,7 @@ module PopCap
40
49
  @hash.each do |key, val|
41
50
  unless self.class.respond_to? key
42
51
  define_singleton_method(key) { val }
52
+ @tags[key] = val
43
53
  end
44
54
  end
45
55
  end
@@ -3,7 +3,7 @@ require 'json'
3
3
  module PopCap
4
4
  # Public: This class formats the JSON output of TagReader.
5
5
  #
6
- class TagHash
6
+ class UnformattedHash
7
7
  attr_reader :json
8
8
 
9
9
  def initialize(json)
@@ -14,7 +14,7 @@ module PopCap
14
14
  # The keys have been converted to symbols.
15
15
  #
16
16
  def hash
17
- renamed_hash.reject { |key,_| key == :size }
17
+ renamed_hash
18
18
  end
19
19
 
20
20
  # Public: This method wraps #new & #hash.
@@ -25,7 +25,9 @@ module PopCap
25
25
 
26
26
  private
27
27
  def renamed_hash
28
- symbolized_hash.merge({filesize: size_element})
28
+ symbolized_hash.
29
+ merge({filesize: size_element}).
30
+ reject { |key,_| key == :size }
29
31
  end
30
32
 
31
33
  def symbolized_hash
@@ -1,3 +1,3 @@
1
1
  module PopCap
2
- VERSION = '0.8.0'
2
+ VERSION = '0.9.0'
3
3
  end
@@ -1,11 +1,11 @@
1
- require 'pop_cap/audio_file'
2
1
  require 'spec_helper'
3
2
  require 'support/popcap_spec_helper'
3
+ require 'pop_cap/audio_file'
4
4
 
5
5
  module PopCap
6
6
  describe AudioFile do
7
7
  let(:audio_file) { AudioFile.new(filepath) }
8
- let(:filepath) { PopCapSpecHelper::SAMPLE_FILE }
8
+ let(:filepath) { File.realpath(PopCapSpecHelper::SAMPLE_FILE) }
9
9
  let(:included_modules) { AudioFile.included_modules }
10
10
 
11
11
  before { PopCapSpecHelper.setup }
@@ -13,8 +13,8 @@ module PopCap
13
13
 
14
14
  subject { audio_file }
15
15
 
16
- context '#filepath' do
17
- its(:filepath) { should eq File.realpath(filepath) }
16
+ describe '#filepath' do
17
+ its(:filepath) { should eq File.realpath(PopCapSpecHelper::SAMPLE_FILE) }
18
18
 
19
19
  it 'raises an error if file does not exist' do
20
20
  expect do
@@ -23,43 +23,93 @@ module PopCap
23
23
  end
24
24
  end
25
25
 
26
- context 'ffmpeg methods' do
27
- it { expect(audio_file).to respond_to(:convert) }
28
- it { expect(audio_file).to respond_to(:raw_tags) }
29
- it { expect(audio_file).to respond_to(:update_tags) }
30
- end
31
-
32
26
  context 'included modules' do
33
27
  it 'includes Fileable' do
34
28
  expect(included_modules).to include Fileable
35
29
  end
30
+ end
31
+
32
+ describe '#raw_output' do
33
+ it 'is memoized' do
34
+ audio_file.raw_output
35
+ TagReader.should_not_receive(:read).with(filepath)
36
+ audio_file.raw_output
37
+ end
38
+
39
+ it { expect(audio_file.raw_output).to eq(PopCapSpecHelper.raw_output) }
40
+ end
41
+
42
+ describe '#unformatted' do
43
+ it 'is memoized' do
44
+ audio_file.unformatted
45
+ UnformattedHash.should_not_receive(:hash).with(audio_file.raw_output)
46
+ audio_file.unformatted
47
+ end
48
+
49
+ it do
50
+ expect(audio_file.unformatted).to eq PopCapSpecHelper.unformatted_hash
51
+ end
52
+ end
36
53
 
37
- it 'includes Taggable' do
38
- expect(included_modules).to include Taggable
54
+ describe '#formatted' do
55
+ it 'is memoized' do
56
+ audio_file.formatted
57
+ FormattedHash.should_not_receive(:formatted).
58
+ with(audio_file.unformatted)
59
+ audio_file.formatted
39
60
  end
61
+
62
+ it { expect(audio_file.formatted).to eq(PopCapSpecHelper.formatted_hash) }
40
63
  end
41
64
 
42
- context '#raw_tags' do
65
+ describe '#tags' do
43
66
  it 'is memoized' do
44
- audio_file.raw_tags
45
- expect(audio_file.instance_variable_get('@raw')).
46
- to eq PopCapSpecHelper.raw_tags
67
+ audio_file.tags
68
+ TagStruct.should_not_receive(:new).with(audio_file.formatted)
69
+ audio_file.tags
70
+ end
71
+
72
+ it 'includes all tags for the sample file' do
73
+ PopCapSpecHelper.formatted_hash.each do |key,val|
74
+ expect(audio_file.tags.send(key)).to eq val
75
+ end
76
+ end
77
+
78
+ it 'is a TagStruct' do
79
+ expect(audio_file.tags).to be_a TagStruct
47
80
  end
48
81
  end
49
82
 
50
- context '#reload!' do
51
- it 'reloads raw tags' do
52
- audio_file.raw_tags
53
- expect(audio_file.instance_variable_get('@raw')).not_to be_nil
83
+ describe '#reload!' do
84
+ it 'resets all MEMOIZABLES' do
85
+ audio_file.tags
54
86
  audio_file.reload!
55
- expect(audio_file.instance_variable_get('@raw')).to be_nil
87
+ ::MEMOIZABLES.each do |var|
88
+ expect(audio_file.instance_variable_get(var)).to be_nil
89
+ end
56
90
  end
57
91
  end
58
92
 
59
- context '#update_tags' do
93
+ describe '#update' do
60
94
  it 'reloads after tags updated' do
61
95
  audio_file.should_receive(:reload!)
62
- audio_file.update_tags({foo: 'foo'})
96
+ audio_file.update({foo: 'foo'})
97
+ end
98
+
99
+ it 'updates tags for file' do
100
+ expect(audio_file.tags.artist).to eq 'Sample Artist'
101
+ updates = {artist: 'New Artist'}
102
+ audio_file.update(updates)
103
+ expect(audio_file.tags.artist).to eq 'New Artist'
104
+ end
105
+ end
106
+
107
+ describe '#convert' do
108
+ after { PopCapSpecHelper.remove_converted }
109
+
110
+ it 'creates a new audio file with the specified format & bitrate' do
111
+ audio_file.convert(:mp3, 128)
112
+ expect(File.exists?('spec/fixtures/sample.mp3')).to be_true
63
113
  end
64
114
  end
65
115
  end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'pop_cap/formatted_hash'
3
+
4
+ module PopCap
5
+ describe FormattedHash do
6
+ describe '.formatted' do
7
+ it 'wraps #new & #formatted' do
8
+ instance = double('FormattedHash')
9
+ FormattedHash.should_receive(:new).with('foo') { instance }
10
+ instance.should_receive(:formatted)
11
+ FormattedHash.formatted('foo')
12
+ end
13
+ end
14
+
15
+ describe '#formatted' do
16
+ it 'does not return the formatter element, if not supplied' do
17
+ hash = FormattedHash.new(filesize: 123456)
18
+ expect(hash.formatted).not_to have_key(:date)
19
+ end
20
+
21
+ it 'applies a formatter if it is in the supplied hash' do
22
+ hash = FormattedHash.new(filesize: 123456)
23
+ expect(hash.formatted).to eq(filesize: '120.6K')
24
+ end
25
+
26
+ it 'merges in non-formattable attributes' do
27
+ hash = FormattedHash.new({filesize: 123456, artist: 'foo'})
28
+ expect(hash.formatted).to eq({filesize: '120.6K', artist: 'foo'})
29
+ end
30
+ end
31
+ end
32
+ end
@@ -4,15 +4,15 @@ require 'pop_cap/formatter'
4
4
  module PopCap
5
5
  module Formatters
6
6
  describe Formatter do
7
- class TagClass < Formatter
7
+ class Filesize < Formatter
8
8
  def format; 'baz'; end
9
9
  end
10
10
 
11
11
  describe '.format' do
12
- let(:taggy) { Formatters::TagClass.new('foo', {option: 'bar'}) }
12
+ let(:taggy) { Formatters::Filesize.new('foo', {option: 'bar'}) }
13
13
 
14
14
  it 'wraps #format in a class method' do
15
- klass = Formatters::TagClass.format('foo', {option: 'bar'})
15
+ klass = Formatters::Filesize.format('foo', {option: 'bar'})
16
16
  instance = taggy.format
17
17
  expect(klass).to eq instance
18
18
  end
@@ -20,12 +20,12 @@ module PopCap
20
20
 
21
21
  describe '.subclasses' do
22
22
  it 'returns a list of all subclasses in the ObjectSpace' do
23
- expect(Formatter.subclasses).to include(PopCap::Formatters::TagClass)
23
+ expect(Formatter.subclasses).to include(PopCap::Formatters::Filesize)
24
24
  end
25
25
 
26
26
  it 'includes the subclass only once' do
27
27
  unique = Formatter.subclasses.select do |cls|
28
- cls == PopCap::Formatters::TagClass
28
+ cls == PopCap::Formatters::Filesize
29
29
  end
30
30
  expect(unique.size).to eq 1
31
31
  end
@@ -45,19 +45,20 @@ module PopCap
45
45
 
46
46
  describe '.subclasses_demodulized' do
47
47
  it 'returns of the subclasses with their names demodulized' do
48
- expect(Formatter.subclasses_demodulized).to include('TagClass')
48
+ expect(Formatter.subclasses_demodulized).
49
+ to include('Filesize')
49
50
  end
50
51
  end
51
52
  end
52
53
 
53
54
  describe '#format' do
54
- let(:taggy) { Formatters::TagClass.new('foo', {option: 'bar'}) }
55
+ let(:taggy) { Formatters::Filesize.new('foo', {option: 'bar'}) }
55
56
 
56
57
  it { expect(taggy).to respond_to(:format) }
57
58
  end
58
59
 
59
60
  describe '#new' do
60
- let(:taggy) { Formatters::TagClass.new('foo', {option: 'bar'}) }
61
+ let(:taggy) { Formatters::Filesize.new('foo', {option: 'bar'}) }
61
62
 
62
63
  it 'has a getter for value' do
63
64
  expect(taggy.value).to eq 'foo'
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
- require 'pop_cap/tag/tag_struct'
2
+ require 'pop_cap/tag_struct'
3
3
 
4
4
  module PopCap
5
5
  describe TagStruct do
@@ -36,8 +36,21 @@ module PopCap
36
36
  end
37
37
  end
38
38
 
39
- it 'has a custom #to_s method' do
40
- expect(ts.to_s).to eq "#<PopCap::TagStruct artist: Artist, date: 1984>"
39
+ describe '#to_s' do
40
+ it 'has a custom #to_s method' do
41
+ expect(ts.to_s).to eq "#<PopCap::TagStruct artist: Artist, date: 1984>"
42
+ end
43
+ end
44
+
45
+ describe '#each' do
46
+ let(:tags) { {foo: 'foo', bar: 'bar', baz: 'baz'} }
47
+ let(:tag_struct) { TagStruct.new tags }
48
+
49
+ it 'has a custom #each method for all defined methods' do
50
+ tag_struct.each do |key,val|
51
+ expect(tags[key]).to eq val
52
+ end
53
+ end
41
54
  end
42
55
 
43
56
  describe 'already defined methods' do
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'support/popcap_spec_helper'
3
+ require 'pop_cap/unformatted_hash'
4
+
5
+ module PopCap
6
+ describe UnformattedHash do
7
+ describe '#hash' do
8
+ let(:json) { '{"format":{"size":"10","tags":{"artist":"artist"}}}' }
9
+ let(:unformatted_hash) do
10
+ UnformattedHash.new(PopCapSpecHelper.raw_output)
11
+ end
12
+
13
+ it 'symbolizes all keys' do
14
+ unformatted_hash.hash.each_key do |key|
15
+ expect(key).to be_a Symbol
16
+ end
17
+ end
18
+
19
+ it 'renames filesize to size' do
20
+ expect(unformatted_hash.hash[:size]).to be_nil
21
+ expect(unformatted_hash.hash[:filesize]).not_to be_nil
22
+ end
23
+
24
+ it 'formats json output as a hash' do
25
+ expect(unformatted_hash.hash).to be_a Hash
26
+ end
27
+
28
+ it 'merges tags section with format section' do
29
+ unformatted = UnformattedHash.new(json)
30
+ expect(unformatted.hash).to eq({filesize: '10', artist: 'artist'})
31
+ end
32
+ end
33
+
34
+ describe '.hash' do
35
+ it 'wraps #new & #hash' do
36
+ instance = double('UnformattedHash')
37
+ UnformattedHash.should_receive(:new).with('foo') { instance }
38
+ instance.should_receive(:hash)
39
+ UnformattedHash.hash('foo')
40
+ end
41
+ end
42
+ end
43
+ end
@@ -6,7 +6,7 @@ module PopCapSpecHelper
6
6
  SAMPLE_FILE = 'spec/fixtures/sample.flac'
7
7
 
8
8
  class << self
9
- def raw_tags
9
+ def raw_output
10
10
  '{"format":{"filename":"/home/marsalis/.apps/popcap/spec/fixtures/'\
11
11
  'sample.flac","nb_streams":1,"format_name":"flac","format_long_name"'\
12
12
  ':"raw FLAC","duration":"1.000000","size":"18291","bit_rate":"146328"'\
@@ -54,7 +54,7 @@ module PopCapSpecHelper
54
54
  OpenStruct.new(
55
55
  {
56
56
  filename: File.realpath(SAMPLE_FILE),
57
- nb_streams: '1',
57
+ nb_streams: 1,
58
58
  format_name: 'flac',
59
59
  format_long_name: 'raw FLAC',
60
60
  start_time: 'N/A',
@@ -81,23 +81,5 @@ module PopCapSpecHelper
81
81
  FileUtils.mv('spec/fixtures/backup.flac', SAMPLE_FILE)
82
82
  FileUtils.rm_f('spec/fixtures/sample.mp3')
83
83
  end
84
-
85
- def object_names(const)
86
- ObjectSpace.each_object(const).map { |cls| cls.name }
87
- end
88
-
89
- def all_names
90
- ObjectSpace.each_object(Object).map do |obj|
91
- obj.name if(obj.is_a?(Class) || obj.is_a?(Module))
92
- end.compact
93
- end
94
-
95
- def classes
96
- ObjectSpace.each_object(Class).map { |cls| cls }
97
- end
98
-
99
- def modules
100
- ObjectSpace.each_object(Module).map { |cls| cls }
101
- end
102
84
  end
103
85
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: popcap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Culley Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-03-03 00:00:00.000000000 Z
11
+ date: 2013-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: reek
@@ -60,22 +60,18 @@ files:
60
60
  - lib/pop_cap/ffmpeg/tag_reader.rb
61
61
  - lib/pop_cap/ffmpeg/tag_writer.rb
62
62
  - lib/pop_cap/fileable.rb
63
+ - lib/pop_cap/formatted_hash.rb
63
64
  - lib/pop_cap/formatter.rb
64
65
  - lib/pop_cap/formatters/bit_rate.rb
65
66
  - lib/pop_cap/formatters/date.rb
66
67
  - lib/pop_cap/formatters/duration.rb
67
68
  - lib/pop_cap/formatters/filesize.rb
68
- - lib/pop_cap/tag/formatted_tag.rb
69
- - lib/pop_cap/tag/tag_hash.rb
70
- - lib/pop_cap/tag/tag_struct.rb
71
- - lib/pop_cap/taggable.rb
69
+ - lib/pop_cap/tag_struct.rb
70
+ - lib/pop_cap/unformatted_hash.rb
72
71
  - lib/pop_cap/version.rb
73
72
  - lib/popcap.rb
74
73
  - popcap.gemspec
75
74
  - spec/fixtures/sample.flac
76
- - spec/integration/convert_audio_file_spec.rb
77
- - spec/integration/read_metatags_spec.rb
78
- - spec/integration/update_metatags_spec.rb
79
75
  - spec/lib/pop_cap/audio_file_spec.rb
80
76
  - spec/lib/pop_cap/class_support_spec.rb
81
77
  - spec/lib/pop_cap/ffmpeg/commander_spec.rb
@@ -84,15 +80,14 @@ files:
84
80
  - spec/lib/pop_cap/ffmpeg/tag_reader_spec.rb
85
81
  - spec/lib/pop_cap/ffmpeg/tag_writer_spec.rb
86
82
  - spec/lib/pop_cap/fileable_spec.rb
83
+ - spec/lib/pop_cap/formatted_hash_spec.rb
87
84
  - spec/lib/pop_cap/formatter_spec.rb
88
85
  - spec/lib/pop_cap/formatters/bit_rate_spec.rb
89
86
  - spec/lib/pop_cap/formatters/date_spec.rb
90
87
  - spec/lib/pop_cap/formatters/duration_spec.rb
91
88
  - spec/lib/pop_cap/formatters/filesize_spec.rb
92
- - spec/lib/pop_cap/tag/formatted_tag_spec.rb
93
- - spec/lib/pop_cap/tag/tag_hash_spec.rb
94
- - spec/lib/pop_cap/tag/tag_struct_spec.rb
95
- - spec/lib/pop_cap/taggable_spec.rb
89
+ - spec/lib/pop_cap/tag_struct_spec.rb
90
+ - spec/lib/pop_cap/unformatted_hash_spec.rb
96
91
  - spec/spec_helper.rb
97
92
  - spec/support/popcap_spec_helper.rb
98
93
  - spec/support/reek_spec.rb
@@ -121,9 +116,6 @@ specification_version: 4
121
116
  summary: A library work with audio files on the filesystem .
122
117
  test_files:
123
118
  - spec/fixtures/sample.flac
124
- - spec/integration/convert_audio_file_spec.rb
125
- - spec/integration/read_metatags_spec.rb
126
- - spec/integration/update_metatags_spec.rb
127
119
  - spec/lib/pop_cap/audio_file_spec.rb
128
120
  - spec/lib/pop_cap/class_support_spec.rb
129
121
  - spec/lib/pop_cap/ffmpeg/commander_spec.rb
@@ -132,15 +124,14 @@ test_files:
132
124
  - spec/lib/pop_cap/ffmpeg/tag_reader_spec.rb
133
125
  - spec/lib/pop_cap/ffmpeg/tag_writer_spec.rb
134
126
  - spec/lib/pop_cap/fileable_spec.rb
127
+ - spec/lib/pop_cap/formatted_hash_spec.rb
135
128
  - spec/lib/pop_cap/formatter_spec.rb
136
129
  - spec/lib/pop_cap/formatters/bit_rate_spec.rb
137
130
  - spec/lib/pop_cap/formatters/date_spec.rb
138
131
  - spec/lib/pop_cap/formatters/duration_spec.rb
139
132
  - spec/lib/pop_cap/formatters/filesize_spec.rb
140
- - spec/lib/pop_cap/tag/formatted_tag_spec.rb
141
- - spec/lib/pop_cap/tag/tag_hash_spec.rb
142
- - spec/lib/pop_cap/tag/tag_struct_spec.rb
143
- - spec/lib/pop_cap/taggable_spec.rb
133
+ - spec/lib/pop_cap/tag_struct_spec.rb
134
+ - spec/lib/pop_cap/unformatted_hash_spec.rb
144
135
  - spec/spec_helper.rb
145
136
  - spec/support/popcap_spec_helper.rb
146
137
  - spec/support/reek_spec.rb
@@ -1,31 +0,0 @@
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
@@ -1,120 +0,0 @@
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'
6
-
7
- module PopCap
8
- # Public: This module is included in anything with a #raw_tags
9
- # attribute. It is used to parse and build tags from FFmpeg raw output.
10
- #
11
- module Taggable
12
- # Public: This method reloads memoized tags.
13
- #
14
- def reload!
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)
43
- end
44
-
45
- # Public: This method builds an unformatted hash of tags.
46
- #
47
- # Examples
48
- # class SomeClass
49
- # def raw_tags
50
- # end
51
- # end
52
- #
53
- # klass = SomeClass.new
54
- # klass.unformatted
55
- # # =>
56
- # { filename: 'spec/fixtures/sample.flac',
57
- # format_name: 'flac',
58
- # duration: '1.000000',
59
- # filesize: '18291',
60
- # bit_rate: '146328',
61
- # genre: 'Sample Genre',
62
- # track: '01',
63
- # album: 'Sample Album',
64
- # date: '2012',
65
- # title: 'Sample Title',
66
- # artist: 'Sample Artist' }
67
- #
68
- def formatted
69
- @formatted_hash ||= unformatted.merge(formatted_tags)
70
- end
71
-
72
- # Public: This method builds an tag structure from #to_hash. Also,
73
- # TagFormatters are applied to any tag with a custom formatter.
74
- #
75
- # Examples
76
- # class SomeClass
77
- # def raw_tags
78
- # end
79
- # end
80
- #
81
- # klass = SomeClass.new
82
- # klass.tags
83
- #
84
- # # =>
85
- # .album => 'Sample Album'
86
- # .artist => 'Sample Artist'
87
- # .bit_rate => '146 kb/s'
88
- # .date => 2012
89
- # .duration => '1'
90
- # .filename => 'spec/fixtures/sample.flac'
91
- # .filesize => '17.9K'
92
- # .format_long_name => 'raw FLAC'
93
- # .format_name => 'flac'
94
- # .genre => 'Sample Genre'
95
- # .nb_streams => '1'
96
- # .start_time => 'N/A'
97
- # .title => 'Sample Title'
98
- # .track => '01'
99
- #
100
- def tags
101
- @tag_struct ||= build_tag_struct(formatted)
102
- end
103
-
104
- private
105
- def build_tag_struct(hash)
106
- TagStruct.new(hash)
107
- end
108
-
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
114
- end
115
-
116
- def format(formatter, attribute, tag: FormattedTag)
117
- tag.format(formatter, unformatted[attribute])
118
- end
119
- end
120
- end
@@ -1,15 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/popcap_spec_helper'
3
- require 'pop_cap/audio_file'
4
-
5
- module PopCap
6
- describe 'Convert Audio Files' do
7
- after { PopCapSpecHelper.remove_converted }
8
-
9
- it 'creates a new audio file with the specified format & bitrate' do
10
- audio_file = AudioFile.new(PopCapSpecHelper::SAMPLE_FILE)
11
- audio_file.convert(:mp3, 128)
12
- expect(File.exists?('spec/fixtures/sample.mp3')).to be_true
13
- end
14
- end
15
- end
@@ -1,12 +0,0 @@
1
- require 'popcap'
2
- require 'spec_helper'
3
- require 'support/popcap_spec_helper'
4
-
5
- describe PopCap do
6
- let(:audio_file) { PopCap::AudioFile.new(filepath) }
7
- let(:filepath) { PopCapSpecHelper::SAMPLE_FILE }
8
-
9
- it '#raw_tags' do
10
- expect(audio_file.raw_tags).to eq PopCapSpecHelper.raw_tags
11
- end
12
- end
@@ -1,20 +0,0 @@
1
- require 'popcap'
2
- require 'spec_helper'
3
- require 'support/popcap_spec_helper'
4
-
5
- describe PopCap do
6
- let(:audio_file) { PopCap::AudioFile.new(filepath) }
7
- let(:filepath) { PopCapSpecHelper::SAMPLE_FILE }
8
-
9
- context '#update_tags' do
10
- before { PopCapSpecHelper.setup }
11
- after { PopCapSpecHelper.teardown }
12
-
13
- it 'updates tags for file' do
14
- expect(audio_file.tags.artist).to eq 'Sample Artist'
15
- updates = {artist: 'New Artist'}
16
- audio_file.update_tags(updates)
17
- expect(audio_file.tags.artist).to eq 'New Artist'
18
- end
19
- end
20
- end
@@ -1,29 +0,0 @@
1
- require 'spec_helper'
2
- require 'pop_cap/tag/formatted_tag'
3
-
4
- module PopCap
5
- describe FormattedTag do
6
- class FakeFormatter
7
- def self.format(value)
8
- value.to_i
9
- end
10
- end
11
-
12
- describe '#format' do
13
- it 'formats a value with the formatter' do
14
- tag = FormattedTag.new(FakeFormatter, '123')
15
- expect(tag.format).to eq 123
16
- end
17
- end
18
-
19
- describe '.format' do
20
- it 'wraps #new & #format' do
21
- instance = double('FormattedTagInstance')
22
- FormattedTag.should_receive(:new).with(FakeFormatter, '123').
23
- and_return(instance)
24
- instance.should_receive(:format)
25
- FormattedTag.format(FakeFormatter, '123')
26
- end
27
- end
28
- end
29
- end
@@ -1,35 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/popcap_spec_helper'
3
- require 'pop_cap/tag/tag_hash'
4
-
5
- module PopCap
6
- describe TagHash do
7
- describe '#hash' do
8
- let(:tag_hash) { TagHash.new(PopCapSpecHelper.raw_tags) }
9
-
10
- it 'symbolizes all keys' do
11
- tag_hash.hash.each_key do |key|
12
- expect(key).to be_a Symbol
13
- end
14
- end
15
-
16
- it 'renames filesize to size' do
17
- expect(tag_hash.hash[:size]).to be_nil
18
- expect(tag_hash.hash[:filesize]).not_to be_nil
19
- end
20
-
21
- it 'formats json output as a hash' do
22
- expect(tag_hash.hash).to eq(PopCapSpecHelper.unformatted_hash)
23
- end
24
- end
25
-
26
- describe '.hash' do
27
- it 'wraps #new & #hash' do
28
- instance = double('TagHash')
29
- TagHash.should_receive(:new).with('foo') { instance }
30
- instance.should_receive(:hash)
31
- TagHash.hash('foo')
32
- end
33
- end
34
- end
35
- end
@@ -1,76 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/popcap_spec_helper'
3
- require 'pop_cap/taggable'
4
-
5
- module PopCap
6
- describe Taggable do
7
- class SomeClass
8
- include Taggable
9
- def raw_tags
10
- PopCapSpecHelper.raw_tags
11
- end
12
- end
13
-
14
- let(:sc) { SomeClass.new }
15
-
16
- it 'has #raw_tags' do
17
- expect(sc).to respond_to(:raw_tags)
18
- end
19
-
20
- describe '#unformatted' do
21
- it 'returns TagHash#hash' do
22
- TagHash.should_receive(:hash).with(sc.raw_tags)
23
- sc.unformatted
24
- end
25
-
26
- it 'is memoized' do
27
- sc.unformatted
28
- TagHash.should_not_receive(:new)
29
- sc.unformatted
30
- end
31
- end
32
-
33
- describe '#formatted' do
34
- it 'builds a formatted hash' do
35
- expect(sc.formatted).to include(PopCapSpecHelper.formatted_hash)
36
- end
37
-
38
- it 'is memoized' do
39
- sc.formatted
40
- FormattedTag.should_not_receive(:new)
41
- sc.formatted
42
- end
43
- end
44
-
45
- describe '#tags' do
46
- it 'builds a tag structure from #formatted_hash' do
47
- expect(sc.tags.album).to eq PopCapSpecHelper.tags.album
48
- expect(sc.tags.artist).to eq PopCapSpecHelper.tags.artist
49
- expect(sc.tags.bit_rate).to eq PopCapSpecHelper.tags.bit_rate
50
- expect(sc.tags.date).to eq PopCapSpecHelper.tags.date
51
- expect(sc.tags.duration).to eq PopCapSpecHelper.tags.duration
52
- expect(sc.tags.filename).to eq PopCapSpecHelper.tags.filename
53
- expect(sc.tags.filesize).to eq PopCapSpecHelper.tags.filesize
54
- expect(sc.tags.format_name).to eq PopCapSpecHelper.tags.format_name
55
- expect(sc.tags.genre).to eq PopCapSpecHelper.tags.genre
56
- expect(sc.tags.title).to eq PopCapSpecHelper.tags.title
57
- expect(sc.tags.track).to eq PopCapSpecHelper.tags.track
58
- end
59
-
60
- it 'is memoized' do
61
- sc.tags
62
- TagStruct.should_not_receive(:new)
63
- sc.tags
64
- end
65
- end
66
-
67
- context '#reload!' do
68
- it 'sets instance variables to nil' do
69
- %w(@formatted_hash @unformatted_hash @tag_struct).each do |instance|
70
- sc.reload!
71
- expect(sc.instance_variable_get(instance)).to be_nil
72
- end
73
- end
74
- end
75
- end
76
- end