ruby-mpd-client 0.2.0 → 1.0.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
- SHA1:
3
- metadata.gz: 5d038318cf899183f6ed52cc1f3c13294b87d899
4
- data.tar.gz: 1c19d632d7c424d08ba14a5df9be67ca64217213
2
+ SHA256:
3
+ metadata.gz: 8ca78849c735d15541f0f0e04e83ac1af66d71c3c3202739a0718f7cfc7860e4
4
+ data.tar.gz: db532da5093220f87880cd0d47137866b089be98ba8d03a7aa89334869b6da9d
5
5
  SHA512:
6
- metadata.gz: 8ebe86c126933033f19be9e25b1c1e1a7e1c2b76856f1e65b60e16e0b685781d6c9f554688e3799a34221072b10b88495a3be94eb296d51f14d97b1092ba2e6b
7
- data.tar.gz: 93ae6e1f0904011acf8976c26bfc8616d64d7a3336bb382fd076b6e80747e464fbadab11af69a608a0822f84108ca0ba6922645298aacdf51890d820ddd5e95d
6
+ metadata.gz: 0d23063c2519c020bcf16009a1f6f1874b2d4f53ad41879fc023b5b460e9a531f13a5a665574399cef5836bd9fadbfd4213d2a64f8cef966fa2b8c2dd79194e4
7
+ data.tar.gz: 0423b775979eb61f9eff55fcfd05d29e6375a17df5e1caf2bb6b9828d7b2d3c32e84e10c792ade9ab004f0462a91292d225e0851f9164a417c6f55c1b698504d
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ script: rake spec
5
+ deploy:
6
+ provider: rubygems
7
+ api_key:
8
+ secure: CCtmgUnWoiG4tKRalp9kfEcaeDUfipES0mcWPV4K0D/K651nxZ0kHe+VV+3rpvV1KDs4i5W+TosVvpH5lDL7+oALLFTsYgo3iam+kzMLfoskkZUuizUDxYjXrWI0T+SM0gL3Ax1J9oJ0cd7j1sUGi5TZ/IHXrKknm1yqFIx83mgKCFxYKJUAwQuwpo924ukqyQ0IsJtYX7AJ31hQwFBZSscJbriaxsz3dN+ptmvYVt9/+oIowHrvZCFnlgejel/eZ9iKCMR8buxx1RF3Q3y7LZkpMb20UBfjMwUkz/XBXGFCFVUaCLEcdFnAuoRePJ8a+q3Qkd0wZp+5g2offguVycTWsPTGgSjSAXcPUK0fOnE6bsBZ9XnkAiwkPtxO3MeG7iBcGBX2XY/Tzl+8EW2FgGeIICBh5sg+UqmrGAuqzmtgrJJwOaBeyLEbAKemAdPRfN7M0Hq1DgbOHchttmiCAY1Ja/RBiYwbEkZsPn9VI2tH3CUvdqc0B4jPV05OKU1sv06hHKJTWoCjsmvd52Tr0Kbr5ofBvLMj+uHnyCx78SwfReVCPEb2PzK5GUBG6+Ufu8UOTFdlS8gDmSO09R/qd/kSILvxCLntNVQAn/aUlnZ0aBJURxhoTQkKRSBGcGrOUXhMKnj3jnwZw1othJ5xxiSXy6fM/8JrsxyPH7TalT8=
9
+ on:
10
+ branch: master
data/README.md CHANGED
@@ -18,13 +18,21 @@ It does not do much
18
18
  ```ruby
19
19
  require 'ruby-mpd-client'
20
20
 
21
- mpd = MPD::Client.new(host: 'localhost')
22
- mpd.volume(50)
23
- mpd.random(true)
24
- mpd.next
25
- # and so on
21
+ MPD::Commands::SetVolume.new(host: 'localhost') # :host can be ommited
22
+ .execute(75)
23
+ MPD::Commands::Next.new.execute
24
+
25
+ #
26
+ # to use one connection
27
+ #
28
+ conn = MPD::Connection.new(host: 'localhost', port: 6600)
29
+ conn.connect
30
+ MPD::Commands::Next.new(connection: conn).execute
31
+ MPD::Commands::Pause.new(connection: conn).execute
26
32
  ```
27
33
 
34
+ For available commands see [lib/mpd/commands](lib/mpd/commands).
35
+
28
36
  ## Contributing
29
37
 
30
38
  Bug reports and pull requests are welcome on GitHub at https://github.com/Nondv/ruby-mpd-client.
@@ -0,0 +1,61 @@
1
+ Dir[File.join(__dir__, 'commands', '*.rb')].each { |f| require f }
2
+
3
+ module MPD
4
+ #
5
+ # Contains classes representing MPD commands
6
+ #
7
+ module Commands
8
+ #
9
+ # To decrease code amount
10
+ #
11
+ def self.define_trivial_command(class_name, command)
12
+ klass = Class.new(::MPD::Commands::Abstract) do
13
+ define_method :execute do
14
+ super(command)
15
+ end
16
+ end
17
+
18
+ const_set(class_name, klass)
19
+ end
20
+
21
+ #
22
+ # To define commands like 'save "whatever this is"'
23
+ #
24
+ def self.define_text_argument_command(class_name, command)
25
+ klass = Class.new(::MPD::Commands::Abstract) do
26
+ define_method :execute do |arg|
27
+ super("#{command} \"#{arg}\"")
28
+ end
29
+ end
30
+
31
+ const_set(class_name, klass)
32
+ end
33
+
34
+ #
35
+ # To define commands like "random <1/0>"
36
+ #
37
+ def self.define_option_command(class_name, command)
38
+ klass = Class.new(::MPD::Commands::Abstract) do
39
+ define_method :execute do |state|
40
+ super(command + state ? ' 1' : ' 0')
41
+ end
42
+ end
43
+
44
+ const_set(class_name, klass)
45
+ end
46
+
47
+ define_trivial_command(:Pause, 'pause 1')
48
+ define_trivial_command(:Stop, 'stop')
49
+ define_trivial_command(:Previous, 'previous')
50
+ define_trivial_command(:Next, 'next')
51
+ define_trivial_command(:CurrentPlaylistClear, 'clear')
52
+
53
+ define_text_argument_command :PlaylistDelete, :rm
54
+ define_text_argument_command :PlaylistSave, :save
55
+ define_text_argument_command :PlaylistLoad, :load
56
+
57
+ %w[Consume Crossfade Random Repeat Single].each do |class_name|
58
+ define_option_command(class_name, class_name.downcase)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,61 @@
1
+ require 'mpd/connection'
2
+ require 'mpd/server_response'
3
+ require 'mpd/playlist'
4
+
5
+ module MPD
6
+ module Commands
7
+ #
8
+ # Base class for MPD commands.
9
+ #
10
+ class Abstract
11
+ attr_reader :connection
12
+
13
+ #
14
+ # You can provide you own connection. It should have same
15
+ #
16
+ def initialize(connection: nil, host: 'localhost', port: 6600)
17
+ @connection = connection || Connection.new(host: host, port: port).tap(&:connect).tap(&:gets)
18
+ end
19
+
20
+ #
21
+ # This method should be overriden.
22
+ # Example:
23
+ #
24
+ # def execute
25
+ # super('ping')
26
+ # end
27
+ #
28
+ def execute(command)
29
+ exec_command(command)
30
+ end
31
+
32
+ private
33
+
34
+ def exec_command(command)
35
+ connection.puts(command)
36
+ response = ServerResponse.from_connection(connection)
37
+ raise(MpdError, response.status) if response.error?
38
+ response
39
+ end
40
+
41
+ def exec_command_list(commands)
42
+ connection.puts('command_list_begin')
43
+ commands.each { |c| connection.puts(c) }
44
+ connection.puts('command_list_end')
45
+
46
+ response = ServerResponse.from_connection(connection)
47
+ raise(MpdError, response.status) if response.error?
48
+ response
49
+ end
50
+
51
+ def resolve_range(arg)
52
+ if arg.is_a?(Range)
53
+ last = arg.exclude_end? ? arg.end : arg.end + 1
54
+ "#{arg.begin}:#{last}"
55
+ else
56
+ arg
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,17 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Uses "listall" command to get
7
+ # all files (directories are filtered out) from db.
8
+ #
9
+ class AllFiles < Abstract
10
+ def execute
11
+ super('listall').key_value_pairs
12
+ .select { |e| e[0] == 'file' }
13
+ .map(&:last)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Increases/decreases volume by some number
7
+ #
8
+ class ChangeVolume < Abstract
9
+ def execute(n)
10
+ super("volume #{n}")
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Adds song(s) to current playlist
7
+ # `songs` is an array of URIs.
8
+ #
9
+ class CurrentPlaylistAdd < Abstract
10
+ #
11
+ # `songs` is position (as int) or range
12
+ #
13
+ def execute(songs)
14
+ return exec_command("add \"#{songs}\"") unless songs.is_a?(Array)
15
+ exec_command_list(songs.map { |s| "add \"#{s}\"" })
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Info about songs in current playlist
7
+ #
8
+ class CurrentPlaylistInfo < Abstract
9
+ # `songs` can be range
10
+ # or integer (to show info about one song)
11
+ # or completely ommited (to show info about all songs)
12
+ def execute(songs = nil)
13
+ response = super("playlistinfo #{resolve_range(songs)}")
14
+ Playlist.from_response(response)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Removes songs from current playlist
7
+ # by id or position/range
8
+ #
9
+ class CurrentPlaylistRemove < Abstract
10
+ #
11
+ # `position` is int or range
12
+ # `id` is int song id
13
+ #
14
+ def execute(position: nil, id: nil)
15
+ raise(ArgumentError) if position && id || !position && !id
16
+ exec_command(id ? "deleteid #{id}" : "delete #{resolve_range(position)}")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Current song info as hash
7
+ #
8
+ class CurrentSong < Abstract
9
+ def execute
10
+ super('currentsong').to_h
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Tries to execute "ping" command.
7
+ # Returns `true` if succedeed,
8
+ # raises error if `MpdError` occurred,
9
+ # `false` otherwise
10
+ #
11
+ class Ping < Abstract
12
+ # rubocop:disable Lint/RescueWithoutErrorClass
13
+ def execute
14
+ super('ping')
15
+ true
16
+ rescue => e
17
+ raise e if e.is_a?(MpdError)
18
+ false
19
+ end
20
+ # rubocop:enable Lint/RescueWithoutErrorClass
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Play specific song (by id or cur. playlist position).
7
+ #
8
+ #
9
+ class Play < Abstract
10
+ def execute(position: nil, id: nil)
11
+ raise(ArgumentError, 'too many arguments') if position && id
12
+
13
+ if position
14
+ super("play #{position}")
15
+ elsif id
16
+ super("playid #{id}")
17
+ else
18
+ super('play')
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Set specific volume to specific value
7
+ #
8
+ class SetVolume < Abstract
9
+ def execute(n)
10
+ super("setvol #{n}")
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'mpd/commands/abstract'
2
+
3
+ module MPD
4
+ module Commands
5
+ #
6
+ # Player status
7
+ #
8
+ class Status < Abstract
9
+ def execute
10
+ super('status').to_h
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,41 @@
1
+ require 'socket'
2
+
3
+ module MPD
4
+ #
5
+ # Simple wrapper over Socket
6
+ #
7
+ class Connection
8
+ def initialize(host:, port:)
9
+ @host = host
10
+ @port = port
11
+ end
12
+
13
+ def connect
14
+ disconnect if socket
15
+ @socket = TCPSocket.open(host, port)
16
+ end
17
+
18
+ def disconnect
19
+ socket && socket.close
20
+ @socket = nil
21
+ end
22
+
23
+ def puts(text)
24
+ raise ConnectionError unless socket
25
+ socket.puts(text)
26
+ rescue Errno::ECONNRESET
27
+ raise ConnectionError
28
+ end
29
+
30
+ def gets
31
+ raise ConnectionError unless socket
32
+ socket.gets || raise(ConnectionError)
33
+ rescue Errno::ECONNRESET
34
+ raise ConnectionError
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :socket, :host, :port
40
+ end
41
+ end
@@ -0,0 +1,50 @@
1
+ module MPD
2
+ #
3
+ # Just a frozen string with some useful methods
4
+ #
5
+ class ServerResponse < String
6
+ def self.from_connection(conn)
7
+ line = ''
8
+ buffer = ''
9
+ while line != "OK\n" && !line.start_with?('ACK')
10
+ line = conn.gets
11
+ raise(ConnectionError) if line.nil?
12
+ buffer << line
13
+ end
14
+
15
+ new(buffer.force_encoding('UTF-8'))
16
+ end
17
+
18
+ def initialize(response_text)
19
+ super
20
+ freeze
21
+ end
22
+
23
+ def to_h
24
+ key_value_pairs.to_h
25
+ end
26
+
27
+ def key_value_pairs
28
+ content.split("\n").map do |line|
29
+ index = line.index(':')
30
+ raise "can't create key-value pair" unless index
31
+ key = line[0...index]
32
+ value = line[(index + 1)..-1].strip
33
+ [key, value]
34
+ end
35
+ end
36
+
37
+ # text without status
38
+ def content
39
+ lines[0..-2].join
40
+ end
41
+
42
+ def status
43
+ lines.last.chomp
44
+ end
45
+
46
+ def error?
47
+ status.start_with?('ACK')
48
+ end
49
+ end
50
+ end
data/lib/mpd/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module MPD
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
@@ -1,3 +1,3 @@
1
1
  require 'mpd/version'
2
2
  require 'mpd/errors'
3
- require 'mpd/client'
3
+ require 'mpd/commands'
@@ -23,4 +23,5 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.13"
25
25
  spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency 'rspec-its'
26
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-mpd-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitriy Non
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-07-02 00:00:00.000000000 Z
11
+ date: 2017-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-its
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description:
42
56
  email:
43
57
  - non.dmitriy@gmail.com
@@ -46,21 +60,29 @@ extensions: []
46
60
  extra_rdoc_files: []
47
61
  files:
48
62
  - ".gitignore"
63
+ - ".travis.yml"
49
64
  - Gemfile
50
65
  - LICENSE.txt
51
66
  - README.md
52
67
  - Rakefile
53
68
  - bin/console
54
69
  - bin/setup
55
- - lib/mpd/client.rb
56
- - lib/mpd/client/commands.rb
57
- - lib/mpd/client/commands/current_playlist.rb
58
- - lib/mpd/client/commands/playback_control.rb
59
- - lib/mpd/client/commands/playback_options.rb
60
- - lib/mpd/client/connection.rb
61
- - lib/mpd/client/server_response.rb
70
+ - lib/mpd/commands.rb
71
+ - lib/mpd/commands/abstract.rb
72
+ - lib/mpd/commands/all_files.rb
73
+ - lib/mpd/commands/change_volume.rb
74
+ - lib/mpd/commands/current_playlist_add.rb
75
+ - lib/mpd/commands/current_playlist_info.rb
76
+ - lib/mpd/commands/current_playlist_remove.rb
77
+ - lib/mpd/commands/current_song.rb
78
+ - lib/mpd/commands/ping.rb
79
+ - lib/mpd/commands/play.rb
80
+ - lib/mpd/commands/set_volume.rb
81
+ - lib/mpd/commands/status.rb
82
+ - lib/mpd/connection.rb
62
83
  - lib/mpd/errors.rb
63
84
  - lib/mpd/playlist.rb
85
+ - lib/mpd/server_response.rb
64
86
  - lib/mpd/song.rb
65
87
  - lib/mpd/version.rb
66
88
  - lib/ruby-mpd-client.rb
@@ -85,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
107
  version: '0'
86
108
  requirements: []
87
109
  rubyforge_project:
88
- rubygems_version: 2.6.12
110
+ rubygems_version: 2.7.3
89
111
  signing_key:
90
112
  specification_version: 4
91
113
  summary: yet another MPD client on Ruby
data/lib/mpd/client.rb DELETED
@@ -1,51 +0,0 @@
1
- require 'mpd/client/connection'
2
- require 'mpd/client/server_response'
3
- require 'mpd/client/commands'
4
-
5
- module MPD
6
- class Client
7
- def self.connect(host: 'localhost', port: 6600)
8
- new(host: host, port: port).tap(&:connect)
9
- end
10
-
11
- def initialize(host: 'localhost', port: 6600)
12
- @connection = Connection.new(host: host, port: port)
13
- end
14
-
15
- def current_song
16
- execute('currentsong').to_h
17
- end
18
-
19
- def status
20
- response = execute('status')
21
- response.to_h
22
- end
23
-
24
- def execute(command)
25
- connection.puts(command)
26
- response = ServerResponse.from_connection(connection)
27
- raise(MpdError, response.status) if response.error?
28
- response
29
- end
30
-
31
- def connected?
32
- execute('ping')
33
- rescue => e
34
- raise e if e.is_a?(MpdError)
35
- false
36
- end
37
-
38
- def connect
39
- connection.connect
40
- raise(ConnectionError) unless connection.gets =~ /^OK/
41
- end
42
-
43
- def disconnect
44
- connection.disconnect
45
- end
46
-
47
- private
48
-
49
- attr_reader :connection
50
- end
51
- end
@@ -1,10 +0,0 @@
1
- Dir[File.join(__dir__, 'commands', '*.rb')].each { |f| require f }
2
-
3
- module MPD
4
- class Client
5
- # Module of modules that implement some MPD commands
6
- module Commands
7
- constants.each { |mod| Client.include(const_get(mod)) }
8
- end
9
- end
10
- end
@@ -1,17 +0,0 @@
1
- require 'mpd/playlist'
2
-
3
- module MPD
4
- class Client
5
- module Commands
6
- # https://www.musicpd.org/doc/protocol/queue.html
7
- module CurrentPlaylist
8
- # songs - integer or range
9
- def playlist_info(songs = nil)
10
- argument = songs.is_a?(Range) ? "#{songs.begin}:#{songs.end}" : songs
11
- response = execute "playlistinfo #{argument}"
12
- Playlist.from_response(response)
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,36 +0,0 @@
1
- module MPD
2
- class Client
3
- module Commands
4
- # https://www.musicpd.org/doc/protocol/playback_commands.html
5
- module PlaybackControl
6
- def play(position: nil, id: nil)
7
- raise(ArgumentError, 'too many arguments') if position && id
8
-
9
- if position
10
- execute "play #{position}"
11
- elsif id
12
- execute "playid #{id}"
13
- else
14
- execute 'pause 0'
15
- end
16
- end
17
-
18
- def pause
19
- execute 'pause 1'
20
- end
21
-
22
- def stop
23
- execute 'stop'
24
- end
25
-
26
- def previous
27
- execute 'previous'
28
- end
29
-
30
- def next
31
- execute 'next'
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,36 +0,0 @@
1
- module MPD
2
- class Client
3
- module Commands
4
- # https://www.musicpd.org/doc/protocol/playback_option_commands.html
5
- module PlaybackOptions
6
- def consume(state)
7
- execute "consume #{state ? 1 : 0}"
8
- end
9
-
10
- def crossfade(state)
11
- execute "crossfade #{state ? 1 : 0}"
12
- end
13
-
14
- def random(state)
15
- execute "random #{state ? 1 : 0}"
16
- end
17
-
18
- def repeat(state)
19
- execute "repeat #{state ? 1 : 0}"
20
- end
21
-
22
- def single(state)
23
- execute "single #{state ? 1 : 0}"
24
- end
25
-
26
- def volume(val)
27
- execute "setvol #{val}"
28
- end
29
-
30
- def change_volume_by(val)
31
- execute("volume #{val}")
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,39 +0,0 @@
1
- require 'socket'
2
-
3
- module MPD
4
- class Client
5
- #
6
- # It's `Client`'s internal class. Don't use it outside `Client`
7
- #
8
- class Connection
9
- def initialize(host:, port:)
10
- @host = host
11
- @port = port
12
- end
13
-
14
- def connect
15
- disconnect if socket
16
- @socket = TCPSocket.open(host, port)
17
- end
18
-
19
- def disconnect
20
- socket && socket.close
21
- @socket = nil
22
- end
23
-
24
- def puts(text)
25
- raise ConnectionError unless socket
26
- socket.puts(text)
27
- end
28
-
29
- def gets
30
- raise ConnectionError unless socket
31
- socket.gets
32
- end
33
-
34
- private
35
-
36
- attr_reader :socket, :host, :port
37
- end
38
- end
39
- end
@@ -1,52 +0,0 @@
1
- module MPD
2
- class Client
3
- #
4
- # Just a frozen string with some useful methods
5
- #
6
- class ServerResponse < String
7
- def self.from_connection(conn)
8
- line = ''
9
- buffer = ''
10
- while line != "OK\n" && !line.start_with?('ACK')
11
- line = conn.gets
12
- raise(ConnectionError) if line.nil?
13
- buffer << line
14
- end
15
-
16
- new(buffer.force_encoding('UTF-8'))
17
- end
18
-
19
- def initialize(response_text)
20
- super
21
- freeze
22
- end
23
-
24
- def to_h
25
- key_value_pairs.to_h
26
- end
27
-
28
- def key_value_pairs
29
- content.split("\n").map do |line|
30
- index = line.index(':')
31
- raise "can't create key-value pair" unless index
32
- key = line[0...index]
33
- value = line[(index + 1)..-1].strip
34
- [key, value]
35
- end
36
- end
37
-
38
- # text without status
39
- def content
40
- lines[0..-2].join
41
- end
42
-
43
- def status
44
- lines.last.chomp
45
- end
46
-
47
- def error?
48
- status.start_with?('ACK')
49
- end
50
- end
51
- end
52
- end