From 5e45aad95a2a3c54a6d4ee6a767209a1a0986bcd Mon Sep 17 00:00:00 2001 From: Lee Machin Date: Wed, 11 Dec 2013 00:42:09 +0000 Subject: [PATCH 1/9] WIP: Refactor and Gemify --- .gitignore | 18 +++++ Gemfile | 5 +- Gemfile.lock | 14 ++-- bin/mpd_client | 134 ++++++++++++++++++++++++++++++++ config.ru | 6 -- lib/mpd_client.rb | 43 ++++++++++ lib/mpd_client/album.rb | 48 ++++++++++++ lib/mpd_client/artist.rb | 12 +++ lib/mpd_client/class_to_proc.rb | 11 +++ lib/mpd_client/connection.rb | 16 ++++ lib/mpd_client/control.rb | 35 +++++++++ lib/mpd_client/server.rb | 0 lib/mpd_client/song.rb | 59 ++++++++++++++ lib/mpd_client/version.rb | 3 + models/album.rb | 24 ------ models/artist.rb | 7 -- models/control.rb | 33 -------- models/mpd_connection.rb | 11 --- models/song.rb | 36 --------- mpd_client.gemspec | 32 ++++++++ mpd_client.rb | 113 --------------------------- 21 files changed, 424 insertions(+), 236 deletions(-) create mode 100644 .gitignore create mode 100755 bin/mpd_client delete mode 100644 config.ru create mode 100644 lib/mpd_client.rb create mode 100644 lib/mpd_client/album.rb create mode 100644 lib/mpd_client/artist.rb create mode 100644 lib/mpd_client/class_to_proc.rb create mode 100644 lib/mpd_client/connection.rb create mode 100644 lib/mpd_client/control.rb create mode 100644 lib/mpd_client/server.rb create mode 100644 lib/mpd_client/song.rb create mode 100644 lib/mpd_client/version.rb delete mode 100644 models/album.rb delete mode 100644 models/artist.rb delete mode 100644 models/control.rb delete mode 100644 models/mpd_connection.rb delete mode 100644 models/song.rb create mode 100644 mpd_client.gemspec delete mode 100644 mpd_client.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f433b9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +*.gem +*.rbc +.bundle +.config +.yardoc +Gemfile.lock +InstalledFiles +_yardoc +coverage +doc/ +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp +.sass-cache diff --git a/Gemfile b/Gemfile index 3740c46..b74cc2c 100644 --- a/Gemfile +++ b/Gemfile @@ -2,12 +2,15 @@ source 'https://rubygems.org' ruby '2.0.0' +# todo: get everything working before going whole hog with the gem +# gemspec + gem 'sinatra' gem 'sinatra-contrib' gem 'sinatra-asset-pipeline' gem 'foreman' - gem 'ruby-mpd', git: 'git@github.com:archSeer/ruby-mpd.git' +gem 'active_support', require: false group :development, :test do gem 'pry' diff --git a/Gemfile.lock b/Gemfile.lock index 2fc0d2f..028acc2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,6 +7,9 @@ GIT GEM remote: https://rubygems.org/ specs: + active_support (3.0.0) + activesupport (= 3.0.0) + activesupport (3.0.0) backports (3.3.5) coderay (1.0.9) coffee-script (2.2.0) @@ -29,7 +32,7 @@ GEM method_source (~> 0.8) slop (~> 3.4) rack (1.5.2) - rack-protection (1.5.0) + rack-protection (1.5.1) rack rack-test (0.6.2) rack (>= 1.0) @@ -45,11 +48,11 @@ GEM sass (3.2.12) shotgun (0.9) rack (>= 1.0) - sinatra (1.4.3) + sinatra (1.4.4) rack (~> 1.4) rack-protection (~> 1.4) tilt (~> 1.3, >= 1.3.4) - sinatra-asset-pipeline (0.2.1) + sinatra-asset-pipeline (0.3.3) coffee-script rake sass @@ -65,12 +68,12 @@ GEM sinatra (~> 1.4.0) tilt (~> 1.3) slop (3.4.6) - sprockets (2.10.0) + sprockets (2.10.1) hike (~> 1.2) multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) - sprockets-helpers (1.0.1) + sprockets-helpers (1.1.0) sprockets (~> 2.0) sprockets-sass (1.0.2) sprockets (~> 2.0) @@ -86,6 +89,7 @@ PLATFORMS ruby DEPENDENCIES + active_support foreman pry rspec diff --git a/bin/mpd_client b/bin/mpd_client new file mode 100755 index 0000000..4b2bc0c --- /dev/null +++ b/bin/mpd_client @@ -0,0 +1,134 @@ +#!/usr/bin/env ruby + +ENV['RACK_ENV'] ||= 'development' + +require 'bundler' + +Bundler.setup +Bundler.require(:default, ENV['RACK_ENV']) + +require 'sinatra' +require 'sinatra/asset_pipeline' + +require 'sass' +require 'json' +require 'cgi' + +require 'active_support/core_ext/hash/slice' + +require File.expand_path('../lib/mpd_client', __dir__) + +module MPDClient + class Application < Sinatra::Base + + set server: 'thin' + + set :root, File.expand_path('../', __dir__).to_s + + set :assets_precompile, %w(app.js app.css *.png *.jpg *.svg *.eot *.ttf *.woff) + set :assets_prefix, ['assets'] + + register Sinatra::AssetPipeline + register Sinatra::Namespace + + MPDClient.connect! + + # TODO: Figure out why failing to supplying args breaks stuff + MPDClient.listen do + on :song do + each_conn do |conn| + json = { type: 'status', data: status }.to_json + conn << "data: #{json}\n\n" + end + end + + on :state do + each_conn do |conn| + json = { type: 'status', data: status }.to_json + conn << "data: #{json}\n\n" + end + end + + on :playlist do + each_conn do |conn| + json = { type: 'queue', data: Song.queue.map(&:to_h) }.to_json + conn << "data: #{json}\n\n" + end + end + + on :time do |elapsed, total| + each_conn do |conn| + json = { type: 'time', data: [elapsed, total] }.to_json + conn << "data: #{json}\n\n" + end + end + end + + get '/' do + erb :index + end + + namespace '/api' do + + get '/status' do + MPDClient.status.to_json + end + + get '/stream', provides: 'text/event-stream' do + stream :keep_open do |conn| + MPDClient.connect_user(conn) + conn.callback { MPDClient.disconnect_user(conn) } + end + end + + get '/albums' do + content_type 'application/json' + if params[:artist] + Album.by_artist(params[:artist]).sort.map(&:to_h).to_json + else + Album.all.to_json + end + end + + get '/artists' do + content_type 'application/json' + Artist.all.map(&:to_h).to_json + end + + get '/songs' do + content_type 'application/json' + if query = params.slice(:artist, :album) and !query.empty? + Song.by(**query).map(&:to_h).to_json + else + Song.all.sort.map(&:to_h).to_json + end + end + + get '/queue' do + content_type 'application/json' + { data: Song.queue.map(&:to_h) }.to_json + end + + put '/control/play' do + Control.play(params[:pos]) + end + + put '/control/:action' do + if Control.controls.include?(params[:action].to_sym) + Control.send(params[:action]) + else + not_found + end + end + + put '/control/volume/:value' do + content_type 'application/json' + Control.volume(params[:value]) + end + + end + + end +end + +MPDClient::Application.run! diff --git a/config.ru b/config.ru deleted file mode 100644 index 4d5bb55..0000000 --- a/config.ru +++ /dev/null @@ -1,6 +0,0 @@ -require 'bundler' - -Bundler.setup -require './mpd_client' - -run MPDClient diff --git a/lib/mpd_client.rb b/lib/mpd_client.rb new file mode 100644 index 0000000..92e486e --- /dev/null +++ b/lib/mpd_client.rb @@ -0,0 +1,43 @@ +require 'forwardable' +require 'ruby-mpd' +require 'set' + +require File.expand_path('mpd_client/class_to_proc', __dir__) + +module MPDClient + + autoload :Connection, File.expand_path('mpd_client/connection.rb', __dir__) + autoload :Song, File.expand_path('mpd_client/song.rb', __dir__) + autoload :Album, File.expand_path('mpd_client/album.rb', __dir__) + autoload :Artist, File.expand_path('mpd_client/artist.rb', __dir__) + autoload :Control, File.expand_path('mpd_client/control.rb', __dir__) + + MPD_HOST = ENV.fetch('MPD_HOST', 'localhost') + MPD_PORT = ENV.fetch('MPD_PORT', 6600) + + def self.connect! + @conn ||= Connection.new(MPD_HOST, MPD_PORT) + @conn.connect unless @conn.connected? + @conn + end + + def self.conn + @conn + end + + def self.status + self.conn.status + end + + def self.listen(&block) + self.conn.instance_eval(&block) + end + + def self.connect_user(conn) + self.conn.connected_users << conn + end + + def self.disconnect_user(conn) + self.conn.connected_users.delete(conn) + end +end diff --git a/lib/mpd_client/album.rb b/lib/mpd_client/album.rb new file mode 100644 index 0000000..676af23 --- /dev/null +++ b/lib/mpd_client/album.rb @@ -0,0 +1,48 @@ +module MPDClient + class Album + + include ClassToProc + include Enumerable + extend Forwardable + + delegate %i(artist genre) => :@first_song + + def initialize(album) + @songs = MPDClient::Song.by(album: album) + @first_song = @songs.first + end + + def each(&block) + @songs.each(&block) + end + + def title + @first_song.album + end + + def year + @first_song.year + end + + def to_h + { + title: title, + artist: artist, + genre: genre, + year: year, + songs: self.map(&:to_h) + } + end + + class << self + def all + MPDClient.conn.albums.sort.map(&self) + end + + def by_artist(artist) + MPDClient.conn.albums(artist).map(&self) + end + end + + end +end diff --git a/lib/mpd_client/artist.rb b/lib/mpd_client/artist.rb new file mode 100644 index 0000000..c75e500 --- /dev/null +++ b/lib/mpd_client/artist.rb @@ -0,0 +1,12 @@ +module MPDClient + class Artist + + include ClassToProc + + class << self + def all + MPDClient.conn.artists.sort.map(&self) + end + end + end +end diff --git a/lib/mpd_client/class_to_proc.rb b/lib/mpd_client/class_to_proc.rb new file mode 100644 index 0000000..8c4a2f2 --- /dev/null +++ b/lib/mpd_client/class_to_proc.rb @@ -0,0 +1,11 @@ +module MPDClient + module ClassToProc + + def self.included(receiver) + receiver.define_singleton_method :to_proc do + proc { |*args| new(*args) } + end + end + + end +end diff --git a/lib/mpd_client/connection.rb b/lib/mpd_client/connection.rb new file mode 100644 index 0000000..1a939e5 --- /dev/null +++ b/lib/mpd_client/connection.rb @@ -0,0 +1,16 @@ +module MPDClient + class Connection < MPD + + attr_accessor :connected_users + + def initialize(host, port, opts = {}) + @connected_users = Set.new + super host, port, opts.merge(callbacks: true) + end + + def each_conn(&block) + connected_users.each(&block) + end + + end +end diff --git a/lib/mpd_client/control.rb b/lib/mpd_client/control.rb new file mode 100644 index 0000000..f3259d3 --- /dev/null +++ b/lib/mpd_client/control.rb @@ -0,0 +1,35 @@ +module MPDClient + class Control + + class << self + def controls + %i(play stop next previous pause) + end + + def play(pos) + MPDClient.conn.play(pos) + end + + def stop + MPDClient.conn.stop + end + + def next + MPDClient.conn.next + end + + def previous + MPDClient.conn.previous + end + + def pause + MPDClient.conn.pause = !MPDClient.conn.paused? + end + + def volume(value) + MPDClient.conn.volume = value + end + end + + end +end diff --git a/lib/mpd_client/server.rb b/lib/mpd_client/server.rb new file mode 100644 index 0000000..e69de29 diff --git a/lib/mpd_client/song.rb b/lib/mpd_client/song.rb new file mode 100644 index 0000000..3e1e89a --- /dev/null +++ b/lib/mpd_client/song.rb @@ -0,0 +1,59 @@ +module MPDClient + class Song + + include ClassToProc + include Comparable + extend Forwardable + + delegate %i(id track artist album title time pos) => :@song + + def initialize(song, pos: nil) + @song = song + end + + def playing? + self == self.class.current_song + end + + def length + time + end + + def <=>(other) + [artist, album, title] == [other.artist, other.album, other.title] + end + + def to_h + { + id: id, + track: track, + artist: artist, + album: album, + title: title, + length: length, + pos: pos, + playing: playing? + } + end + + class << self + def by(**params) + params.delete_if {|_, v| v.nil? } + MPDClient.conn.where(params).map(&self) + end + + def all + MPDClient.conn.songs.map(&self) + end + + def queue + MPDClient.conn.queue.map(&self) + end + + def current_song + new(MPDClient.conn.current_song) + end + end + + end +end diff --git a/lib/mpd_client/version.rb b/lib/mpd_client/version.rb new file mode 100644 index 0000000..bde2900 --- /dev/null +++ b/lib/mpd_client/version.rb @@ -0,0 +1,3 @@ +module MPDClient + VERSION = "0.0.1" +end diff --git a/models/album.rb b/models/album.rb deleted file mode 100644 index 1897c23..0000000 --- a/models/album.rb +++ /dev/null @@ -1,24 +0,0 @@ -require './models/mpd_connection' - -class Album < Struct.new(:title, :artist, :genre, :year) - - def initialize(album) - first_song = MPDConnection.mpd.where(album: album).first - self.title = first_song.album - self.artist = first_song.artist - self.genre = first_song.genre - self.year = first_song.date - end - - def <=>(album) - year <=> album.year - end - - def self.all - MPDConnection.mpd.albums.sort.map { |album| self.new(album) } - end - - def self.by_artist(artist) - MPDConnection.mpd.albums(artist).map { |album| self.new(album) } - end -end diff --git a/models/artist.rb b/models/artist.rb deleted file mode 100644 index 0a365d4..0000000 --- a/models/artist.rb +++ /dev/null @@ -1,7 +0,0 @@ -require './models/mpd_connection' - -class Artist < Struct.new(:name) - def self.all - MPDConnection.mpd.artists.sort.map { |artist| self.new(artist) } - end -end diff --git a/models/control.rb b/models/control.rb deleted file mode 100644 index b313af2..0000000 --- a/models/control.rb +++ /dev/null @@ -1,33 +0,0 @@ -require './models/mpd_connection' - -class Control - class << self - def controls - [:play, :stop, :next, :previous, :pause] - end - - def play(pos = nil) - MPDConnection.mpd.play(pos) - end - - def stop - MPDConnection.mpd.stop - end - - def next - MPDConnection.mpd.next - end - - def previous - MPDConnection.mpd.previous - end - - def pause - MPDConnection.mpd.pause = !MPDConnection.mpd.paused? - end - - def volume(value) - MPDConnection.mpd.volume = value - end - end -end diff --git a/models/mpd_connection.rb b/models/mpd_connection.rb deleted file mode 100644 index b1f37fb..0000000 --- a/models/mpd_connection.rb +++ /dev/null @@ -1,11 +0,0 @@ -class MPDConnection - def self.mpd - @mpd ||= MPD.new('localhost', 6600, { callbacks: true }) - @mpd.connect unless @mpd.connected? - @mpd - end - - def self.status - self.mpd.status - end -end diff --git a/models/song.rb b/models/song.rb deleted file mode 100644 index 508334d..0000000 --- a/models/song.rb +++ /dev/null @@ -1,36 +0,0 @@ -require './models/mpd_connection' - -class Song < Struct.new(:id, :track, :artist, :album, :title, :length, :pos, :playing) - - def initialize(song, pos: nil, playing: false) - self.id = song.id - self.track = song.track - self.artist = song.artist - self.album = song.album - self.title = song.title - self.length = song.time - self.pos = pos - self.playing = playing - end - - def <=>(song) - title <=> song.title - end - - def self.queue - current_song = MPDConnection.mpd.status[:songid] - MPDConnection.mpd.queue.map { |song| self.new(song, playing: (song.id == current_song), pos: song.pos) } - end - - def self.all - MPDConnection.mpd.songs.map { |album| self.new(album) } - end - - def self.by_artist(artist) - MPDConnection.mpd.where(artist: artist).map { |song| self.new(song) } - end - - def self.by_album(artist, album) - MPDConnection.mpd.where(artist: artist, album: album).map { |song| self.new(song) } - end -end diff --git a/mpd_client.gemspec b/mpd_client.gemspec new file mode 100644 index 0000000..8bd4c84 --- /dev/null +++ b/mpd_client.gemspec @@ -0,0 +1,32 @@ +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'mpd_client/version' + +Gem::Specification.new do |spec| + spec.name = "mpd_client" + spec.version = MPDClient::VERSION + spec.authors = ["Dan Barber", "Lee Machin"] + spec.email = ["dan@new-bamboo.co.uk", "lee@new-bamboo.co.uk"] + spec.description = %q{Tasty web interface for MPD} + spec.summary = %q{Tasty web interface for MPD} + spec.homepage = "" + + spec.files = `git ls-files`.split($/) + spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.require_paths = ["lib"] + + spec.add_development_dependency "bundler", "~> 1.3" + spec.add_development_dependency "rake" + spec.add_development_dependency "rspec" + spec.add_development_dependency "rspec-mocks" + spec.add_development_dependency "pry" + + spec.add_dependency "thin" + spec.add_dependency "sinatra" + spec.add_dependency "sinatra-contrib" + spec.add_dependency "sinatra-asset-pipeline" + spec.add_dependency "ruby-mpd" + spec.add_dependency "active_support" +end diff --git a/mpd_client.rb b/mpd_client.rb deleted file mode 100644 index 7d5a46e..0000000 --- a/mpd_client.rb +++ /dev/null @@ -1,113 +0,0 @@ -require 'bundler' -ENV['RACK_ENV'] ||= 'development' -Bundler.require(:default, ENV['RACK_ENV']) - -require 'sinatra/asset_pipeline' - -require 'sass' -require 'json' -require 'cgi' - -require './models/mpd_connection' -require './models/control' -require './models/album' -require './models/artist' -require './models/song' - -class MPDClient < Sinatra::Base - - set server: 'thin', connections: [] - - set :assets_precompile, %w(app.js app.css *.png *.jpg *.svg *.eot *.ttf *.woff) - set :assets_prefix, 'assets' - register Sinatra::AssetPipeline - - register Sinatra::Namespace - - get '/' do - erb :index - end - - def self.send_status - response = JSON({ type: 'status', data: MPDConnection.status }) - settings.connections.each { |out| out << "data: #{response}\n\n" } - end - - def self.send_queue - response = JSON({ type: 'queue', data: Song.queue.map(&:to_h) }) - settings.connections.each { |out| out << "data: #{response}\n\n" } - end - - def self.send_time(elapsed, total) - response = JSON({ type: 'time', data: [elapsed, total] }) - settings.connections.each { |out| out << "data: #{response}\n\n" } - end - - MPDConnection.mpd.on(:song) { |song| send_status } - MPDConnection.mpd.on(:state) { |state| send_status } - MPDConnection.mpd.on(:playlist) { |playlist| send_queue } - MPDConnection.mpd.on(:time) { |elapsed, total| send_time(elapsed, total) } - - namespace '/api' do - - get '/status' do - JSON MPDConnection.status - end - - get '/stream', provides: 'text/event-stream' do - stream :keep_open do |out| - settings.connections << out - out.callback { settings.connections.delete(out) } - end - end - - get '/albums' do - content_type 'application/json' - if params[:artist] - JSON Album.by_artist(CGI.unescape(params[:artist])).sort.map(&:to_h) - else - JSON Album.all.map(&:to_h) - end - end - - get '/artists' do - content_type 'application/json' - JSON Artist.all.map(&:to_h) - end - - get '/songs' do - content_type 'application/json' - if params[:artist] && params[:album] - JSON Song.by_album(CGI.unescape(params[:artist]), CGI.unescape(params[:album])).map(&:to_h) - elsif params[:artist] - JSON Song.by_artist(CGI.unescape(params[:artist])).map(&:to_h) - else - JSON Song.all.sort.map(&:to_h) - end - end - - get '/queue' do - content_type 'application/json' - JSON({ data: Song.queue.map(&:to_h) }) - end - - put '/control/play' do - Control.play(params[:pos]) - end - - put '/control/:action' do - if Control.controls.include?(params[:action].to_sym) - Control.send(params[:action]) - else - not_found - end - end - - put '/control/volume/:value' do - content_type 'application/json' - Control.volume(params[:value]) - end - - end - -end From 494c1795f44cf6d0cc8a69f8eaa3cfbb04ed0300 Mon Sep 17 00:00:00 2001 From: Lee Machin Date: Wed, 11 Dec 2013 11:37:32 +0000 Subject: [PATCH 2/9] Make all the tests work --- lib/mpd_client/album.rb | 6 ++++- lib/mpd_client/artist.rb | 6 +++++ lib/mpd_client/song.rb | 2 +- spec/{models => lib/mpd_client}/album_spec.rb | 20 +++++++++------- spec/lib/mpd_client/artist_spec.rb | 23 +++++++++++++++++++ spec/lib/mpd_client/connection_spec.rb | 23 +++++++++++++++++++ spec/lib/mpd_client/control_spec.rb | 4 ++++ spec/{models => lib/mpd_client}/song_spec.rb | 8 ++++--- spec/lib/mpd_client_spec.rb | 23 +++++++++++++++++++ spec/models/artist_spec.rb | 18 --------------- spec/models/control_spec.rb | 4 ---- spec/mpd_client_spec.rb | 8 ------- spec/spec_helper.rb | 22 ++++++++---------- 13 files changed, 111 insertions(+), 56 deletions(-) rename spec/{models => lib/mpd_client}/album_spec.rb (53%) create mode 100644 spec/lib/mpd_client/artist_spec.rb create mode 100644 spec/lib/mpd_client/connection_spec.rb create mode 100644 spec/lib/mpd_client/control_spec.rb rename spec/{models => lib/mpd_client}/song_spec.rb (71%) create mode 100644 spec/lib/mpd_client_spec.rb delete mode 100644 spec/models/artist_spec.rb delete mode 100644 spec/models/control_spec.rb delete mode 100644 spec/mpd_client_spec.rb diff --git a/lib/mpd_client/album.rb b/lib/mpd_client/album.rb index 676af23..eedf71b 100644 --- a/lib/mpd_client/album.rb +++ b/lib/mpd_client/album.rb @@ -21,7 +21,11 @@ module MPDClient end def year - @first_song.year + @first_song.date + end + + def <=>(other) + year <=> other.year end def to_h diff --git a/lib/mpd_client/artist.rb b/lib/mpd_client/artist.rb index c75e500..8b0bb3f 100644 --- a/lib/mpd_client/artist.rb +++ b/lib/mpd_client/artist.rb @@ -3,6 +3,12 @@ module MPDClient include ClassToProc + attr :name + + def initialize(name) + @name = name + end + class << self def all MPDClient.conn.artists.sort.map(&self) diff --git a/lib/mpd_client/song.rb b/lib/mpd_client/song.rb index 3e1e89a..260287a 100644 --- a/lib/mpd_client/song.rb +++ b/lib/mpd_client/song.rb @@ -5,7 +5,7 @@ module MPDClient include Comparable extend Forwardable - delegate %i(id track artist album title time pos) => :@song + delegate %i(id track artist album title genre date time pos) => :@song def initialize(song, pos: nil) @song = song diff --git a/spec/models/album_spec.rb b/spec/lib/mpd_client/album_spec.rb similarity index 53% rename from spec/models/album_spec.rb rename to spec/lib/mpd_client/album_spec.rb index 1bd4669..0abf21f 100644 --- a/spec/models/album_spec.rb +++ b/spec/lib/mpd_client/album_spec.rb @@ -1,30 +1,34 @@ require 'spec_helper' -describe Album do +describe MPDClient::Album do + + subject { MPDClient::Album } let(:song1) { MPD::Song.new({ album: 'Back in Black', genre: 'Rock', date: '1980' }) } let(:song2) { MPD::Song.new({ album: 'Highway to Hell', genre: 'Rock', date: '1979' }) } before do - MPDConnection.mpd.stub(:albums).and_return([song1.album, song2.album]) - MPDConnection.mpd.stub(:search).and_return([song1, song2]) - MPDConnection.mpd.stub(:search).with(:album, song1.album).and_return([song1]) - MPDConnection.mpd.stub(:search).with(:album, song2.album).and_return([song2]) + MPDClient.conn.tap do |mpd| + mpd.stub(:albums).and_return([song1.album, song2.album]) + mpd.stub(:where).and_return([song1, song2]) + mpd.stub(:where).with(album: song1.album).and_return([song1]) + mpd.stub(:where).with(album: song2.album).and_return([song2]) + end end it 'has attributes based on first song' do - album = Album.new(song1.album) + album = subject.new(song1.album) expect(album.title).to eq(song1.album) expect(album.genre).to eq(song1.genre) expect(album.year).to eq(song1.date) end it 'should return a list of albums' do - expect(Album.by_artist('AC/DC')).to have(2).items + expect(subject.by_artist('AC/DC')).to have(2).items end it 'should sort the albums by year' do - albums = Album.by_artist('AC/DC') + albums = subject.by_artist('AC/DC') expect(albums.sort.map(&:year)).to eq(['1979', '1980']) end diff --git a/spec/lib/mpd_client/artist_spec.rb b/spec/lib/mpd_client/artist_spec.rb new file mode 100644 index 0000000..5032b2c --- /dev/null +++ b/spec/lib/mpd_client/artist_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe MPDClient::Artist do + + subject { MPDClient::Artist } + + let(:artist) { subject.new('Alice Cooper') } + let(:artists) { ['Alice Cooper', 'Jimmy Eat World', 'Dream Theater'] } + + before do + MPDClient.conn.stub(:artists).and_return(artists) + end + + it 'has attributes' do + expect(artist.name).to eq('Alice Cooper') + end + + it 'returns all artists' do + expect(subject.all).to have(3).items + expect(subject.all.map(&:name)).to eq(artists.sort) + end + +end diff --git a/spec/lib/mpd_client/connection_spec.rb b/spec/lib/mpd_client/connection_spec.rb new file mode 100644 index 0000000..f61b7c1 --- /dev/null +++ b/spec/lib/mpd_client/connection_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe MPDClient::Connection do + + subject { MPDClient::Connection } + + let(:conn) { subject.new('localhost', 6600) } + + describe "#each_conn" do + let(:fake_users) { [1, 2, 3] } + it "enumerates the connected users" do + fake_users.each {|n| conn.connected_users << n } + conn.each_conn.to_a.should eq(fake_users) + end + end + + describe "#connected_users" do + it "doesn't allow duplicate connections" do + 3.times { conn.connected_users << "user" } + conn.connected_users.should have(1).item + end + end +end diff --git a/spec/lib/mpd_client/control_spec.rb b/spec/lib/mpd_client/control_spec.rb new file mode 100644 index 0000000..9e84b27 --- /dev/null +++ b/spec/lib/mpd_client/control_spec.rb @@ -0,0 +1,4 @@ +require 'spec_helper' + +describe MPDClient::Control do +end diff --git a/spec/models/song_spec.rb b/spec/lib/mpd_client/song_spec.rb similarity index 71% rename from spec/models/song_spec.rb rename to spec/lib/mpd_client/song_spec.rb index 93f3430..d19ccfb 100644 --- a/spec/models/song_spec.rb +++ b/spec/lib/mpd_client/song_spec.rb @@ -1,16 +1,18 @@ require 'spec_helper' -describe Song do +describe MPDClient::Song do + + subject { MPDClient::Song } let(:song1) { MPD::Song.new({ title: 'Back in Black', album: 'Back in Black', genre: 'Rock', date: '1980' }) } let(:song2) { MPD::Song.new({ title: 'Highway to Hell', album: 'Highway to Hell', genre: 'Rock', date: '1979' }) } before do - MPDConnection.mpd.stub(:queue).and_return([song1, song2]) + MPDClient.conn.stub(:queue).and_return([song1, song2]) end it 'returns the queue of songs' do - queue = Song.queue + queue = subject.queue expect(queue).to have(2).items end end diff --git a/spec/lib/mpd_client_spec.rb b/spec/lib/mpd_client_spec.rb new file mode 100644 index 0000000..dde8037 --- /dev/null +++ b/spec/lib/mpd_client_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe MPDClient do + + subject { MPDClient } + + before do + subject.connect! + end + + describe "#listen" do + it "exposes `Connection#on` for easy event listening" do + subject.conn.should_receive(:on).exactly(3).times + + subject.listen do + on(:first) { "something" } + on(:second) { "something" } + on(:third) { "something" } + end + end + end + +end diff --git a/spec/models/artist_spec.rb b/spec/models/artist_spec.rb deleted file mode 100644 index ac7559c..0000000 --- a/spec/models/artist_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'spec_helper' - -describe Artist do - - let(:artist) { Artist.new('Alice Cooper') } - let(:artists) { ['Alice Cooper', 'Jimmy Eat World', 'Dream Theater'] } - - it 'has attributes' do - expect(artist.name).to eq('Alice Cooper') - end - - it 'returns all artists' do - MPDConnection.mpd.stub(:artists).and_return(artists) - expect(Artist.all).to have(3).items - expect(Artist.all.map(&:name)).to eq(artists.sort) - end - -end diff --git a/spec/models/control_spec.rb b/spec/models/control_spec.rb deleted file mode 100644 index 39f0c42..0000000 --- a/spec/models/control_spec.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'spec_helper' - -describe Control do -end diff --git a/spec/mpd_client_spec.rb b/spec/mpd_client_spec.rb deleted file mode 100644 index 7c600f1..0000000 --- a/spec/mpd_client_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'spec_helper' - -describe MPDClient do - it 'should respond to GET' do - get '/' - expect(last_response.status).to eq(404) - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ea68e56..120b0b4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,20 +1,16 @@ ENV['RACK_ENV'] = 'test' -require File.join(File.dirname(__FILE__), '..', 'mpd_client.rb') - -require 'sinatra' +require File.expand_path('../lib/mpd_client', __dir__) +require 'rspec' +require 'rspec/mocks' require 'rack/test' -# setup test environment -set :environment, :test -set :run, false -set :raise_errors, true -set :logging, false - -def app - MPDClient -end - RSpec.configure do |config| config.include Rack::Test::Methods + + config.before(:each) do + allow_message_expectations_on_nil + MPDClient::Connection.any_instance.stub(:connected?).and_return(true) + end + end From 183c6279cd5187e6f2b3de1ae6e945b69ed462fa Mon Sep 17 00:00:00 2001 From: Lee Machin Date: Wed, 11 Dec 2013 12:45:23 +0000 Subject: [PATCH 3/9] Fix implementation of playing? method and test it --- lib/mpd_client/song.rb | 10 +++++++--- spec/lib/mpd_client/song_spec.rb | 25 ++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/mpd_client/song.rb b/lib/mpd_client/song.rb index 260287a..cf96a93 100644 --- a/lib/mpd_client/song.rb +++ b/lib/mpd_client/song.rb @@ -12,7 +12,9 @@ module MPDClient end def playing? - self == self.class.current_song + if current = self.class.current_song + [artist, album, title] == [current.artist, current.album, current.title] + end end def length @@ -20,7 +22,7 @@ module MPDClient end def <=>(other) - [artist, album, title] == [other.artist, other.album, other.title] + [artist, album, title] <=> [other.artist, other.album, other.title] end def to_h @@ -51,7 +53,9 @@ module MPDClient end def current_song - new(MPDClient.conn.current_song) + if song = MPDClient.conn.current_song + new(song) + end end end diff --git a/spec/lib/mpd_client/song_spec.rb b/spec/lib/mpd_client/song_spec.rb index d19ccfb..569d5d1 100644 --- a/spec/lib/mpd_client/song_spec.rb +++ b/spec/lib/mpd_client/song_spec.rb @@ -11,8 +11,27 @@ describe MPDClient::Song do MPDClient.conn.stub(:queue).and_return([song1, song2]) end - it 'returns the queue of songs' do - queue = subject.queue - expect(queue).to have(2).items + describe "#queue" do + it "returns the list of songs" do + queue = subject.queue + expect(queue).to have(2).items + end + end + + describe "#playing?" do + let(:playing_song) { subject.new(song1) } + let(:not_playing_song) { subject.new(song2) } + + before do + MPDClient.conn.stub(:current_song).and_return(song1) + end + + it "should be true when the song is playing" do + playing_song.playing?.should eq(true) + end + + it "should be false when the song is not playing" do + not_playing_song.playing?.should eq(false) + end end end From 83a7e0eac9126d992523de374149db5e554c27d3 Mon Sep 17 00:00:00 2001 From: Lee Machin Date: Wed, 11 Dec 2013 12:54:55 +0000 Subject: [PATCH 4/9] Return unprocessable entity when trying to change volume wrongly --- bin/mpd_client | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/mpd_client b/bin/mpd_client index 4b2bc0c..da9e406 100755 --- a/bin/mpd_client +++ b/bin/mpd_client @@ -123,7 +123,9 @@ module MPDClient put '/control/volume/:value' do content_type 'application/json' - Control.volume(params[:value]) + unless Control.volume(params[:value].to_i) + status 422 + end end end From c3f6aadd0ecbc9adb525750e2f136a5660d9fb65 Mon Sep 17 00:00:00 2001 From: Lee Machin Date: Wed, 11 Dec 2013 13:23:22 +0000 Subject: [PATCH 5/9] Add Jsonable mixin to enable recursive generation --- bin/mpd_client | 15 +++++++-------- lib/mpd_client.rb | 5 +++-- lib/mpd_client/album.rb | 2 ++ lib/mpd_client/artist.rb | 7 +++++++ lib/mpd_client/jsonable.rb | 15 +++++++++++++++ lib/mpd_client/song.rb | 2 ++ 6 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 lib/mpd_client/jsonable.rb diff --git a/bin/mpd_client b/bin/mpd_client index da9e406..d0d1ffd 100755 --- a/bin/mpd_client +++ b/bin/mpd_client @@ -23,7 +23,7 @@ module MPDClient set server: 'thin' - set :root, File.expand_path('../', __dir__).to_s + set :root, File.expand_path('../', __dir__) set :assets_precompile, %w(app.js app.css *.png *.jpg *.svg *.eot *.ttf *.woff) set :assets_prefix, ['assets'] @@ -33,7 +33,6 @@ module MPDClient MPDClient.connect! - # TODO: Figure out why failing to supplying args breaks stuff MPDClient.listen do on :song do each_conn do |conn| @@ -51,7 +50,7 @@ module MPDClient on :playlist do each_conn do |conn| - json = { type: 'queue', data: Song.queue.map(&:to_h) }.to_json + json = { type: 'queue', data: Song.queue }.to_json conn << "data: #{json}\n\n" end end @@ -84,7 +83,7 @@ module MPDClient get '/albums' do content_type 'application/json' if params[:artist] - Album.by_artist(params[:artist]).sort.map(&:to_h).to_json + Album.by_artist(params[:artist]).sort.to_json else Album.all.to_json end @@ -92,21 +91,21 @@ module MPDClient get '/artists' do content_type 'application/json' - Artist.all.map(&:to_h).to_json + Artist.all.to_json end get '/songs' do content_type 'application/json' if query = params.slice(:artist, :album) and !query.empty? - Song.by(**query).map(&:to_h).to_json + Song.by(**query).to_json else - Song.all.sort.map(&:to_h).to_json + Song.all.sort.to_json end end get '/queue' do content_type 'application/json' - { data: Song.queue.map(&:to_h) }.to_json + { data: Song.queue }.to_json end put '/control/play' do diff --git a/lib/mpd_client.rb b/lib/mpd_client.rb index 92e486e..3a07830 100644 --- a/lib/mpd_client.rb +++ b/lib/mpd_client.rb @@ -2,10 +2,11 @@ require 'forwardable' require 'ruby-mpd' require 'set' -require File.expand_path('mpd_client/class_to_proc', __dir__) - module MPDClient + autoload :Jsonable, File.expand_path('mpd_client/jsonable.rb', __dir__) + autoload :ClassToProc, File.expand_path('mpd_client/class_to_proc.rb', __dir__) + autoload :Connection, File.expand_path('mpd_client/connection.rb', __dir__) autoload :Song, File.expand_path('mpd_client/song.rb', __dir__) autoload :Album, File.expand_path('mpd_client/album.rb', __dir__) diff --git a/lib/mpd_client/album.rb b/lib/mpd_client/album.rb index eedf71b..92d019e 100644 --- a/lib/mpd_client/album.rb +++ b/lib/mpd_client/album.rb @@ -3,6 +3,8 @@ module MPDClient include ClassToProc include Enumerable + include Jsonable + extend Forwardable delegate %i(artist genre) => :@first_song diff --git a/lib/mpd_client/artist.rb b/lib/mpd_client/artist.rb index 8b0bb3f..b4d5975 100644 --- a/lib/mpd_client/artist.rb +++ b/lib/mpd_client/artist.rb @@ -2,6 +2,7 @@ module MPDClient class Artist include ClassToProc + include Jsonable attr :name @@ -9,6 +10,12 @@ module MPDClient @name = name end + def to_h + { + name: name + } + end + class << self def all MPDClient.conn.artists.sort.map(&self) diff --git a/lib/mpd_client/jsonable.rb b/lib/mpd_client/jsonable.rb new file mode 100644 index 0000000..9502041 --- /dev/null +++ b/lib/mpd_client/jsonable.rb @@ -0,0 +1,15 @@ +module MPDClient + module Jsonable + + def self.included(receiver) + receiver.send(:include, InstanceMethods) + end + + module InstanceMethods + def to_json(*args) + to_h.to_json(*args) + end + end + + end +end diff --git a/lib/mpd_client/song.rb b/lib/mpd_client/song.rb index cf96a93..41079bf 100644 --- a/lib/mpd_client/song.rb +++ b/lib/mpd_client/song.rb @@ -3,6 +3,8 @@ module MPDClient include ClassToProc include Comparable + include Jsonable + extend Forwardable delegate %i(id track artist album title genre date time pos) => :@song From 7cd737d1ce060b28fccfbf4ef5a82b862d5d23c9 Mon Sep 17 00:00:00 2001 From: Lee Machin Date: Wed, 11 Dec 2013 13:51:32 +0000 Subject: [PATCH 6/9] Extract the queue into its own class --- bin/mpd_client | 4 ++-- lib/mpd_client.rb | 1 + lib/mpd_client/queue.rb | 28 ++++++++++++++++++++++++++++ lib/mpd_client/song.rb | 4 ---- spec/lib/mpd_client/queue_spec.rb | 17 +++++++++++++++++ spec/lib/mpd_client/song_spec.rb | 7 ------- 6 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 lib/mpd_client/queue.rb create mode 100644 spec/lib/mpd_client/queue_spec.rb diff --git a/bin/mpd_client b/bin/mpd_client index d0d1ffd..864007b 100755 --- a/bin/mpd_client +++ b/bin/mpd_client @@ -50,7 +50,7 @@ module MPDClient on :playlist do each_conn do |conn| - json = { type: 'queue', data: Song.queue }.to_json + json = { type: 'queue', data: Queue.new }.to_json conn << "data: #{json}\n\n" end end @@ -105,7 +105,7 @@ module MPDClient get '/queue' do content_type 'application/json' - { data: Song.queue }.to_json + { data: Queue.new }.to_json end put '/control/play' do diff --git a/lib/mpd_client.rb b/lib/mpd_client.rb index 3a07830..7d9bfd4 100644 --- a/lib/mpd_client.rb +++ b/lib/mpd_client.rb @@ -12,6 +12,7 @@ module MPDClient autoload :Album, File.expand_path('mpd_client/album.rb', __dir__) autoload :Artist, File.expand_path('mpd_client/artist.rb', __dir__) autoload :Control, File.expand_path('mpd_client/control.rb', __dir__) + autoload :Queue, File.expand_path('mpd_client/queue.rb', __dir__) MPD_HOST = ENV.fetch('MPD_HOST', 'localhost') MPD_PORT = ENV.fetch('MPD_PORT', 6600) diff --git a/lib/mpd_client/queue.rb b/lib/mpd_client/queue.rb new file mode 100644 index 0000000..326ee0d --- /dev/null +++ b/lib/mpd_client/queue.rb @@ -0,0 +1,28 @@ +module MPDClient + class Queue + + include Enumerable + include Jsonable + + attr :songs + + def initialize + @songs = fetch_songs + end + + def each(&block) + songs.each(&block) + end + + def to_h + map(&:to_h) + end + + private + + def fetch_songs + MPDClient.conn.queue.map(&Song) + end + + end +end diff --git a/lib/mpd_client/song.rb b/lib/mpd_client/song.rb index 41079bf..d50c8df 100644 --- a/lib/mpd_client/song.rb +++ b/lib/mpd_client/song.rb @@ -50,10 +50,6 @@ module MPDClient MPDClient.conn.songs.map(&self) end - def queue - MPDClient.conn.queue.map(&self) - end - def current_song if song = MPDClient.conn.current_song new(song) diff --git a/spec/lib/mpd_client/queue_spec.rb b/spec/lib/mpd_client/queue_spec.rb new file mode 100644 index 0000000..1e6a9d0 --- /dev/null +++ b/spec/lib/mpd_client/queue_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe MPDClient::Queue do + + subject { MPDClient::Queue.new } + + let(:song1) { MPD::Song.new({ title: 'Back in Black', album: 'Back in Black', genre: 'Rock', date: '1980' }) } + + let(:song2) { MPD::Song.new({ title: 'Highway to Hell', album: 'Highway to Hell', genre: 'Rock', date: '1979' }) } + + before do + MPDClient.conn.stub(:queue).and_return([song1, song2]) + end + + its(:songs) { should have(2).items } + +end diff --git a/spec/lib/mpd_client/song_spec.rb b/spec/lib/mpd_client/song_spec.rb index 569d5d1..5bc6dd7 100644 --- a/spec/lib/mpd_client/song_spec.rb +++ b/spec/lib/mpd_client/song_spec.rb @@ -11,13 +11,6 @@ describe MPDClient::Song do MPDClient.conn.stub(:queue).and_return([song1, song2]) end - describe "#queue" do - it "returns the list of songs" do - queue = subject.queue - expect(queue).to have(2).items - end - end - describe "#playing?" do let(:playing_song) { subject.new(song1) } let(:not_playing_song) { subject.new(song2) } From 16573133e6731d087b0f56dbc62a180411845904 Mon Sep 17 00:00:00 2001 From: Lee Machin Date: Wed, 11 Dec 2013 15:21:55 +0000 Subject: [PATCH 7/9] Don't like the executable - use config.ru again for now --- config.ru | 10 ++++++++++ lib/mpd_client.rb | 4 ++++ bin/mpd_client => lib/mpd_client/webserver.rb | 20 ++----------------- spec/spec_helper.rb | 5 ++++- 4 files changed, 20 insertions(+), 19 deletions(-) create mode 100644 config.ru rename bin/mpd_client => lib/mpd_client/webserver.rb (88%) diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..fdf0aaa --- /dev/null +++ b/config.ru @@ -0,0 +1,10 @@ +ENV['RACK_ENV'] ||= 'development' + +require 'bundler' + +Bundler.setup +Bundler.require(:default, ENV['RACK_ENV']) + +require File.expand_path('lib/mpd_client', __dir__) + +run MPDClient::Webserver diff --git a/lib/mpd_client.rb b/lib/mpd_client.rb index 7d9bfd4..3ce89b0 100644 --- a/lib/mpd_client.rb +++ b/lib/mpd_client.rb @@ -1,6 +1,7 @@ require 'forwardable' require 'ruby-mpd' require 'set' +require 'json' module MPDClient @@ -14,6 +15,9 @@ module MPDClient autoload :Control, File.expand_path('mpd_client/control.rb', __dir__) autoload :Queue, File.expand_path('mpd_client/queue.rb', __dir__) + # Don't want to automatically require this thing + autoload :Webserver, File.expand_path('mpd_client/webserver.rb', __dir__) + MPD_HOST = ENV.fetch('MPD_HOST', 'localhost') MPD_PORT = ENV.fetch('MPD_PORT', 6600) diff --git a/bin/mpd_client b/lib/mpd_client/webserver.rb similarity index 88% rename from bin/mpd_client rename to lib/mpd_client/webserver.rb index 864007b..db6cc7b 100755 --- a/bin/mpd_client +++ b/lib/mpd_client/webserver.rb @@ -1,29 +1,15 @@ -#!/usr/bin/env ruby - -ENV['RACK_ENV'] ||= 'development' - -require 'bundler' - -Bundler.setup -Bundler.require(:default, ENV['RACK_ENV']) - require 'sinatra' require 'sinatra/asset_pipeline' - require 'sass' -require 'json' require 'cgi' - require 'active_support/core_ext/hash/slice' -require File.expand_path('../lib/mpd_client', __dir__) - module MPDClient - class Application < Sinatra::Base + class Webserver < Sinatra::Base set server: 'thin' - set :root, File.expand_path('../', __dir__) + set :root, File.expand_path('../../', __dir__) set :assets_precompile, %w(app.js app.css *.png *.jpg *.svg *.eot *.ttf *.woff) set :assets_prefix, ['assets'] @@ -131,5 +117,3 @@ module MPDClient end end - -MPDClient::Application.run! diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 120b0b4..268d212 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,12 +1,15 @@ ENV['RACK_ENV'] = 'test' +require 'bundler' +Bundler.setup +Bundler.require(:default, ENV['RACK_ENV']) + require File.expand_path('../lib/mpd_client', __dir__) require 'rspec' require 'rspec/mocks' require 'rack/test' RSpec.configure do |config| - config.include Rack::Test::Methods config.before(:each) do allow_message_expectations_on_nil From 0bf3a50cb5b30d045a555379d9c7ea3baae14345 Mon Sep 17 00:00:00 2001 From: Lee Machin Date: Wed, 11 Dec 2013 15:37:35 +0000 Subject: [PATCH 8/9] Leave the gemspec out of it for now too --- mpd_client.gemspec | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 mpd_client.gemspec diff --git a/mpd_client.gemspec b/mpd_client.gemspec deleted file mode 100644 index 8bd4c84..0000000 --- a/mpd_client.gemspec +++ /dev/null @@ -1,32 +0,0 @@ -# coding: utf-8 -lib = File.expand_path('../lib', __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'mpd_client/version' - -Gem::Specification.new do |spec| - spec.name = "mpd_client" - spec.version = MPDClient::VERSION - spec.authors = ["Dan Barber", "Lee Machin"] - spec.email = ["dan@new-bamboo.co.uk", "lee@new-bamboo.co.uk"] - spec.description = %q{Tasty web interface for MPD} - spec.summary = %q{Tasty web interface for MPD} - spec.homepage = "" - - spec.files = `git ls-files`.split($/) - spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } - spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) - spec.require_paths = ["lib"] - - spec.add_development_dependency "bundler", "~> 1.3" - spec.add_development_dependency "rake" - spec.add_development_dependency "rspec" - spec.add_development_dependency "rspec-mocks" - spec.add_development_dependency "pry" - - spec.add_dependency "thin" - spec.add_dependency "sinatra" - spec.add_dependency "sinatra-contrib" - spec.add_dependency "sinatra-asset-pipeline" - spec.add_dependency "ruby-mpd" - spec.add_dependency "active_support" -end From 717b2d1fb3c7d0e7d8457928c7bbc9d2ba7ed55c Mon Sep 17 00:00:00 2001 From: Lee Machin Date: Thu, 12 Dec 2013 11:50:12 +0000 Subject: [PATCH 9/9] Remove fake association style stuff --- lib/mpd_client/album.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/mpd_client/album.rb b/lib/mpd_client/album.rb index 92d019e..3011339 100644 --- a/lib/mpd_client/album.rb +++ b/lib/mpd_client/album.rb @@ -2,7 +2,6 @@ module MPDClient class Album include ClassToProc - include Enumerable include Jsonable extend Forwardable @@ -10,12 +9,7 @@ module MPDClient delegate %i(artist genre) => :@first_song def initialize(album) - @songs = MPDClient::Song.by(album: album) - @first_song = @songs.first - end - - def each(&block) - @songs.each(&block) + @first_song = MPDClient::Song.by(album: album).first end def title @@ -35,8 +29,7 @@ module MPDClient title: title, artist: artist, genre: genre, - year: year, - songs: self.map(&:to_h) + year: year } end