diff --git a/lib/ruby-mpd/parser.rb b/lib/ruby-mpd/parser.rb index 8992970..15afedf 100644 --- a/lib/ruby-mpd/parser.rb +++ b/lib/ruby-mpd/parser.rb @@ -62,7 +62,7 @@ def quotable_param(value) :decoders, :listplaylistinfo, :playlistinfo] # Parses key-value pairs into correct class. - def parse_key(key, value) + def parse_key(command, key, value) if INT_KEYS.include? key value.to_i elsif FLOAT_KEYS.include? key @@ -71,9 +71,7 @@ def parse_key(key, value) value != '0' elsif SYM_KEYS.include? key value.to_sym - elsif key == :playlist && !value.to_i.zero? - # doc states it's an unsigned int, meaning if we get 0, - # then it's a name string. + elsif key == :playlist && command != :listplaylists value.to_i elsif key == :db_update Time.at(value.to_i) @@ -93,21 +91,21 @@ def parse_key(key, value) end # Parses a single response line into a key-object (value) pair. - def parse_line(line) + def parse_line(command, line) key, value = line.split(/:\s?/, 2) key = key.downcase.to_sym - return key, parse_key(key, value.chomp) + return key, parse_key(command, key, value.chomp) end # This builds a hash out of lines returned from the server, # elements parsed into the correct type. # # The end result is a hash containing the proper key/value pairs - def build_hash(string) + def build_hash(command, string) return {} if string.nil? string.lines.each_with_object({}) do |line, hash| - key, object = parse_line(line) + key, object = parse_line(command, line) # if val appears more than once, make an array of vals. if hash.include? key @@ -137,7 +135,7 @@ def make_chunks(string) # @return [Array, Array, String, Integer] Parsed response. def parse_response(command, string) if command == :listall # Explicitly handle :listall (#files) -> always return a Hash - return build_hash(string) + return build_hash(command, string) elsif command == :listallinfo # We do not care about directories or playlists, # and leaving them in breaks the heuristic used by `make_chunks`. @@ -160,7 +158,13 @@ def build_response(command, string) is_hash = chunks.any? { |chunk| chunk.include? "\n" } list = chunks.inject([]) do |result, chunk| - result << (is_hash ? build_hash(chunk) : parse_line(chunk)[1]) # parse_line(chunk)[1] is object + result << begin + if is_hash + build_hash(command, chunk) + else + parse_line(command, chunk)[1] # object + end + end end # if list has only one element and not set to explicit array, return it, else return array diff --git a/spec/ruby-mpd/parser_spec.rb b/spec/ruby-mpd/parser_spec.rb index 095df17..891f321 100644 --- a/spec/ruby-mpd/parser_spec.rb +++ b/spec/ruby-mpd/parser_spec.rb @@ -69,58 +69,63 @@ describe "#parse_key" do context "with valid INT_KEYS" do MPD::Parser::INT_KEYS.each do |key| - it { expect(subject.send(:parse_key, key, '32')).to eql(32) } + it { expect(subject.send(:parse_key, :status, key, '32')).to eql(32) } end end context "with valid SYM_KEYS" do MPD::Parser::SYM_KEYS.each do |key| - it { expect(subject.send(:parse_key, key, 'value')).to eql(:value) } + it { expect(subject.send(:parse_key, :status, key, 'value')).to eql(:value) } end end context "with valid FLOAT_KEYS" do MPD::Parser::FLOAT_KEYS.each do |key| - it { expect(subject.send(:parse_key, key, 10)).to eql(10.0) } - it { expect(subject.send(:parse_key, key, 'nan')).to be(Float::NAN) } + it { expect(subject.send(:parse_key, :status, key, 10)).to eql(10.0) } + it { expect(subject.send(:parse_key, :status, key, 'nan')).to be(Float::NAN) } end end context "with valid BOOL_KEYS" do MPD::Parser::BOOL_KEYS.each do |key| - it { expect(subject.send(:parse_key, key, '1')).to be_truthy } - it { expect(subject.send(:parse_key, key, '0')).to be_falsey } + it { expect(subject.send(:parse_key, :status, key, '1')).to be_truthy } + it { expect(subject.send(:parse_key, :status, key, '0')).to be_falsey } end end context "with :playlist key" do - it { expect(subject.send(:parse_key, :playlist, '32')).to eql(32) } - it { expect(subject.send(:parse_key, :playlist, '0')).to eql('0') } + it { expect(subject.send(:parse_key, :status, :playlist, '32')).to eql(32) } + it { expect(subject.send(:parse_key, :status, :playlist, '0')).to eql(0) } + + context "for :listplaylists command" do + it { expect(subject.send(:parse_key, :listplaylists, :playlist, '0')).to eql('0') } + it { expect(subject.send(:parse_key, :listplaylists, :playlist, '70s')).to eql('70s') } + end end context "with :db_update key" do expected_time = Time.at(1434024873) - it { expect(subject.send(:parse_key, :db_update, '1434024873').utc) + it { expect(subject.send(:parse_key, :status, :db_update, '1434024873').utc) .to eql(expected_time.utc) } end context "with :'last-modified' key" do let(:time) { Time.parse("Thu Nov 29 14:33:20 GMT 2001") } - it { expect(subject.send(:parse_key, :"last-modified", time.utc.iso8601)) + it { expect(subject.send(:parse_key, :status, :"last-modified", time.utc.iso8601)) .to eql(time) } end context "with :time, :audio key" do - it { expect(subject.send(:parse_key, :time, '123')).to eql([nil, 123]) } - it { expect(subject.send(:parse_key, :time, '99:123')).to eql([99, 123]) } - it { expect(subject.send(:parse_key, :audio, '12:33')).to eql([12, 33]) } + it { expect(subject.send(:parse_key, :status, :time, '123')).to eql([nil, 123]) } + it { expect(subject.send(:parse_key, :status, :time, '99:123')).to eql([99, 123]) } + it { expect(subject.send(:parse_key, :status, :audio, '12:33')).to eql([12, 33]) } end end describe "#parse_line" do context "with a valid response line" do let(:response) { "UPTIME:32\n xxxx" } - it { expect(subject.send(:parse_line, response)).to eql([:uptime, 32]) } + it { expect(subject.send(:parse_line, :stats, response)).to eql([:uptime, 32]) } end end diff --git a/test/test_parser.rb b/test/test_parser.rb index 5152329..5797b41 100644 --- a/test/test_parser.rb +++ b/test/test_parser.rb @@ -42,11 +42,11 @@ def test_parse_empty_listall_command end def test_parse_playlist_uint - assert_equal @parser.parse_key(:playlist, '31'), 31 + assert_equal @parser.parse_key(:status, :playlist, '31'), 31 end def test_parse_playlist_name - assert_equal @parser.parse_key(:playlist, 'leftover/classics.m3u'), 'leftover/classics.m3u' + assert_equal @parser.parse_key(:listplaylists, :playlist, 'leftover/classics.m3u'), 'leftover/classics.m3u' end end \ No newline at end of file