ws_sync_client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bd880be25c6299668ed273d8f8f4345809447191
4
+ data.tar.gz: a4cf1207d81d14513c5cf0f9828570ba135b5a5e
5
+ SHA512:
6
+ metadata.gz: 66fc604c66760b5d417e010cc8a2d3ee3a8596a4d28ccca319d5509c5ed27ba898e1e95c229555ac44f69596ef7970e164d0a1a16506996bbc13057f9eb0d161
7
+ data.tar.gz: 7621ceb91d7e8cbbb2cc4ad289ed40c27564dd20d7629108cd119a1995973f0173934bc7fb4ae42ca7c130bddf664c13c437680289ff6e2c6fc05252f4b19678
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'http://rubygems.org'
2
+ gem 'websocket', '>= 1.1.2'
3
+ gem 'websocket-native', '>= 1.0.0'
4
+
5
+ # Add dependencies to develop your gem here.
6
+ # Include everything needed to run rake, tests, features, etc.
7
+ group :development do
8
+ gem 'bundler', '>= 1.5.3'
9
+ gem 'debugger', '>= 1.6.6'
10
+ gem 'em-websocket', '>= 0'
11
+ gem 'jeweler', '>= 2.0.1'
12
+ gem 'minitest', '>= 5.3.0'
13
+ gem 'rdoc', '>= 4.1.1'
14
+ gem 'simplecov', '>= 0.8.2'
15
+ gem 'yard', '>= 0.8.7.3'
16
+ end
@@ -0,0 +1,84 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.3.5)
5
+ builder (3.2.2)
6
+ columnize (0.3.6)
7
+ debugger (1.6.6)
8
+ columnize (>= 0.3.1)
9
+ debugger-linecache (~> 1.2.0)
10
+ debugger-ruby_core_source (~> 1.3.2)
11
+ debugger-linecache (1.2.0)
12
+ debugger-ruby_core_source (1.3.2)
13
+ descendants_tracker (0.0.3)
14
+ docile (1.1.3)
15
+ em-websocket (0.5.0)
16
+ eventmachine (>= 0.12.9)
17
+ http_parser.rb (~> 0.5.3)
18
+ eventmachine (1.0.3)
19
+ faraday (0.9.0)
20
+ multipart-post (>= 1.2, < 3)
21
+ git (1.2.6)
22
+ github_api (0.11.3)
23
+ addressable (~> 2.3)
24
+ descendants_tracker (~> 0.0.1)
25
+ faraday (~> 0.8, < 0.10)
26
+ hashie (>= 1.2)
27
+ multi_json (>= 1.7.5, < 2.0)
28
+ nokogiri (~> 1.6.0)
29
+ oauth2
30
+ hashie (2.0.5)
31
+ highline (1.6.21)
32
+ http_parser.rb (0.5.3)
33
+ jeweler (2.0.1)
34
+ builder
35
+ bundler (>= 1.0)
36
+ git (>= 1.2.5)
37
+ github_api
38
+ highline (>= 1.6.15)
39
+ nokogiri (>= 1.5.10)
40
+ rake
41
+ rdoc
42
+ json (1.8.1)
43
+ jwt (0.1.11)
44
+ multi_json (>= 1.5)
45
+ mini_portile (0.5.2)
46
+ minitest (5.3.0)
47
+ multi_json (1.9.0)
48
+ multi_xml (0.5.5)
49
+ multipart-post (2.0.0)
50
+ nokogiri (1.6.1)
51
+ mini_portile (~> 0.5.0)
52
+ oauth2 (0.9.3)
53
+ faraday (>= 0.8, < 0.10)
54
+ jwt (~> 0.1.8)
55
+ multi_json (~> 1.3)
56
+ multi_xml (~> 0.5)
57
+ rack (~> 1.2)
58
+ rack (1.5.2)
59
+ rake (10.1.1)
60
+ rdoc (4.1.1)
61
+ json (~> 1.4)
62
+ simplecov (0.8.2)
63
+ docile (~> 1.1.0)
64
+ multi_json
65
+ simplecov-html (~> 0.8.0)
66
+ simplecov-html (0.8.0)
67
+ websocket (1.1.2)
68
+ websocket-native (1.0.0)
69
+ yard (0.8.7.3)
70
+
71
+ PLATFORMS
72
+ ruby
73
+
74
+ DEPENDENCIES
75
+ bundler (>= 1.5.3)
76
+ debugger (>= 1.6.6)
77
+ em-websocket
78
+ jeweler (>= 2.0.1)
79
+ minitest (>= 5.3.0)
80
+ rdoc (>= 4.1.1)
81
+ simplecov (>= 0.8.2)
82
+ websocket (>= 1.1.2)
83
+ websocket-native (>= 1.0.0)
84
+ yard (>= 0.8.7.3)
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Victor Costan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,19 @@
1
+ = ws_sync
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to ws_sync
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
9
+ * Fork the project.
10
+ * Start a feature/bugfix branch.
11
+ * Commit and push until you are happy with your contribution.
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2014 Victor Costan. See LICENSE.txt for
18
+ further details.
19
+
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
+ gem.name = "ws_sync_client"
18
+ gem.homepage = "http://github.com/pwnall/ws_sync_client"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Synchronous WebSocket client}
21
+ gem.description = %Q{WebSocket client that does not require asynchronous programming}
22
+ gem.email = "costan@gmail.com"
23
+ gem.authors = ["Victor Costan"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ desc "Code coverage detail"
36
+ task :simplecov do
37
+ ENV['COVERAGE'] = "true"
38
+ Rake::Task['test'].execute
39
+ end
40
+
41
+ task :default => :test
42
+
43
+ require 'yard'
44
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,133 @@
1
+ require 'socket' # For Addrinfo.
2
+
3
+ require 'websocket'
4
+
5
+ # Synchronous socket.
6
+ class WsSyncClient
7
+ # Create a socket.
8
+ #
9
+ # @param [String] url a ws:// URL
10
+ # @param [Hash] options socket creation options
11
+ # @option options [Socket] raw create this socket on top of a raw socket.
12
+ #
13
+ def initialize(url, options = {})
14
+ @url = url
15
+ @handshake = WebSocket::Handshake::Client.new url: @url
16
+
17
+ if options[:raw]
18
+ @socket = options[:raw]
19
+ else
20
+ @socket = self.class.raw_socket @handshake.host, @handshake.port
21
+ end
22
+ @max_recv = 4096
23
+
24
+ handshake
25
+ @closed = false
26
+ @incoming = WebSocket::Frame::Incoming::Client.new(
27
+ version: @handshake.version)
28
+ @incoming << @handshake.leftovers
29
+ end
30
+
31
+ # Send a WebSocket frame.
32
+ #
33
+ # @param [String] data the data to be sent
34
+ def send_frame(data)
35
+ frame = WebSocket::Frame::Outgoing::Client.new version: @handshake.version,
36
+ data: data, type: :text
37
+ @socket.send frame.to_s, 0
38
+ end
39
+
40
+ # Receive a WebSocket frame.
41
+ #
42
+ # @return [String] the frame data
43
+ def recv_frame
44
+ loop do
45
+ frame = @incoming.next
46
+ if frame.nil?
47
+ recv_bytes
48
+ next
49
+ end
50
+
51
+ case frame.type
52
+ when :text
53
+ return frame.data
54
+ when :binary
55
+ return frame.data
56
+ when :ping
57
+ send_pong frame.data
58
+ when :pong
59
+ # Ignore pong, since we don't ping.
60
+ when :close
61
+ @socket.close
62
+ @closed = true
63
+ end
64
+ end
65
+ end
66
+
67
+ # Closes the WebSocket.
68
+ #
69
+ # @param [Integer] code
70
+ # @param [String] reason
71
+ def close(code = 0, reason = '')
72
+ return if @closed
73
+ frame = WebSocket::Frame::Outgoing::Client.new version: @handshake.version,
74
+ data: '', type: :close
75
+ @socket.send frame.to_s, 0
76
+ @socket.close
77
+ @closed = true
78
+ end
79
+
80
+ # Complete the WebSocket handshake.
81
+ #
82
+ # @private
83
+ # This is used in the constructor
84
+ def handshake
85
+ @socket.send @handshake.to_s, 0
86
+
87
+ until @handshake.finished?
88
+ bytes = @socket.recv @max_recv
89
+ @handshake << bytes
90
+ end
91
+ unless @handshake.valid?
92
+ raise RuntimeError, 'Invalid WebSocket handshake'
93
+ end
94
+ end
95
+ private :handshake
96
+
97
+ # Receive a packet from the underlying raw socket.
98
+ #
99
+ # @private
100
+ # This is used in {WsSync#recv_frame}.
101
+ def recv_bytes
102
+ bytes = @socket.recv @max_recv
103
+ @incoming << bytes
104
+ end
105
+ private :recv_bytes
106
+
107
+ # Send
108
+ def send_pong(ping_data)
109
+ frame = WebSocket::Frame::Outgoing::Client.new version: @handshake.version,
110
+ data: ping_data, type: :pong
111
+ @socket.send frame.to_s, 0
112
+ end
113
+ private :send_pong
114
+
115
+ # Create a raw Socket connected to a host and port.
116
+ #
117
+ # @param [String] host hostname (e.g., DNS, mDNS, "localhost" name)
118
+ # @param [Integer] port the port that the server listens to
119
+ # @param [Number] timeout number of seconds to wait for the connection to
120
+ # succeed
121
+ # @return [Socket] the raw socket
122
+ def self.raw_socket(host, port, timeout = 30)
123
+ Addrinfo.foreach host, port, nil, :STREAM, nil,
124
+ Socket::AI_NUMERICSERV do |info|
125
+ begin
126
+ return info.connect
127
+ rescue StandardError
128
+ # Try the next address.
129
+ end
130
+ end
131
+ nil
132
+ end
133
+ end
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Tiny WebSocket test server for WsSync.
4
+ #
5
+ #
6
+ #
7
+ # Manual testing sequence for this test server:
8
+ #
9
+ # $ npm install -g ws
10
+ # $ wscat --connect ws://localhost:9969/hello/world?ohai
11
+ # connected (press CTRL+C to quit)
12
+ #
13
+ # < {"handshake":"completed","path":"/hello/world","query":"ohai","host":"localhost:9969"}
14
+ # > {"cmd":"echo", "seq": 666, "data": "Boom headshot!"}
15
+ #
16
+ # < {"status":"ok","seq":666,"data":"Boom headshot!"}
17
+ # > {"cmd":"echo ", "seq": 666, "data": "Boom headshot!"}
18
+ #
19
+ # < {"status":"error","seq":666,"reason":"unknown command"}
20
+ # (press Ctrl+C)
21
+
22
+ require 'json'
23
+ require 'rubygems'
24
+ require 'em-websocket'
25
+
26
+ EM.run do
27
+ EM::WebSocket.run host: '0.0.0.0', port: 9969 do |ws|
28
+ ws.onopen do |handshake|
29
+ ws.send JSON.dump(handshake: 'completed', path: handshake.path,
30
+ query: handshake.query_string,
31
+ host: handshake.headers['Host'])
32
+ end
33
+
34
+ ws.onmessage do |message|
35
+ command = JSON.parse message
36
+ case command['cmd']
37
+ when 'echo'
38
+ response = { status: 'ok', seq: command['seq'], data: command['data'] }
39
+ else
40
+ response = { status: 'error', seq: command['seq'],
41
+ reason: 'unknown command' }
42
+ end
43
+ ws.send JSON.dump(response)
44
+ end
45
+
46
+ ws.onclose do
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'minitest/autorun'
11
+ require 'minitest/spec'
12
+
13
+ require 'simplecov'
14
+ SimpleCov.start
15
+
16
+
17
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
18
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
19
+ require 'ws_sync_client'
20
+
21
+ require 'net/http'
22
+
23
+ # Launch a test WebSockets server and wait until it starts.
24
+ module RunServerInMinitest
25
+ def before_setup
26
+ super
27
+ @_server_pid = Process.spawn 'bundle exec test/fixtures/ws_server.rb'
28
+ Process.detach @_server_pid
29
+
30
+ loop do
31
+ begin
32
+ response = Net::HTTP.get_response URI.parse('http://localhost:9969')
33
+ break if response.kind_of?(Net::HTTPSuccess)
34
+ rescue EOFError
35
+ break
36
+ rescue SystemCallError
37
+ sleep 0.1
38
+ end
39
+ end
40
+ end
41
+
42
+ def after_teardown
43
+ Process.kill 'TERM', @_server_pid
44
+ super
45
+ end
46
+
47
+ def server_root_url
48
+ "ws://localhost:9969"
49
+ end
50
+ end
51
+ class MiniTest::Test
52
+ include RunServerInMinitest
53
+ end
54
+
55
+
56
+ class MiniTest::Test
57
+ end
@@ -0,0 +1,66 @@
1
+ require 'helper'
2
+
3
+ describe 'WsSync' do
4
+ before do
5
+ @ws = WsSyncClient.new server_root_url + "/hello/world?answer=42"
6
+ end
7
+ after do
8
+ @ws.close
9
+ end
10
+
11
+ describe '#recv_frame' do
12
+ it 'receives the handshake' do
13
+ parsed = JSON.parse @ws.recv_frame
14
+ parsed.must_equal 'handshake' => 'completed', 'path' => '/hello/world',
15
+ 'query' => 'answer=42', 'host' => 'localhost:9969'
16
+ end
17
+ end
18
+
19
+ describe '#send_frame' do
20
+ it 'completes a handshake/echo cycle' do
21
+ parsed = JSON.parse @ws.recv_frame
22
+ parsed['handshake'].must_equal 'completed'
23
+
24
+ @ws.send_frame JSON.dump(cmd: 'echo', seq: 1, data: 'Hello world!')
25
+ parsed = JSON.parse @ws.recv_frame
26
+ parsed.must_equal 'status' => 'ok', 'seq' => 1, 'data' => 'Hello world!'
27
+ end
28
+
29
+ it 'completes a handshake/echo cycle with a large payload' do
30
+ parsed = JSON.parse @ws.recv_frame
31
+ parsed['handshake'].must_equal 'completed'
32
+
33
+ data = 'Hello world!\n' * 10_000
34
+ @ws.send_frame JSON.dump(cmd: 'echo', seq: 1, data: data)
35
+ parsed = JSON.parse @ws.recv_frame
36
+ parsed.must_equal 'status' => 'ok', 'seq' => 1, 'data' => data
37
+ end
38
+
39
+ it 'completes a few synchronous handshake/echo cycles' do
40
+ parsed = JSON.parse @ws.recv_frame
41
+ parsed['handshake'].must_equal 'completed'
42
+
43
+ 1.upto 32 do |seq|
44
+ @ws.send_frame JSON.dump(cmd: 'echo', seq: seq, data: 'Hello world!')
45
+ parsed = JSON.parse @ws.recv_frame
46
+ parsed.must_equal 'status' => 'ok', 'seq' => seq,
47
+ 'data' => 'Hello world!'
48
+ end
49
+ end
50
+
51
+ it 'completes a few asynchronous handshake/echo cycles' do
52
+ parsed = JSON.parse @ws.recv_frame
53
+ parsed['handshake'].must_equal 'completed'
54
+
55
+ 1.upto 32 do |seq|
56
+ @ws.send_frame JSON.dump(cmd: 'echo', seq: seq, data: 'Hello world!')
57
+ end
58
+
59
+ 1.upto 32 do |seq|
60
+ parsed = JSON.parse @ws.recv_frame
61
+ parsed.must_equal 'status' => 'ok', 'seq' => seq,
62
+ 'data' => 'Hello world!'
63
+ end
64
+ end
65
+ end
66
+ end
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ws_sync_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Victor Costan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: websocket
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.1.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.1.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: websocket-native
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.5.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.5.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: debugger
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.6.6
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: 1.6.6
69
+ - !ruby/object:Gem::Dependency
70
+ name: em-websocket
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: jeweler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: 2.0.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 2.0.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: 5.3.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: 5.3.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rdoc
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: 4.1.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: 4.1.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: 0.8.2
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: 0.8.2
139
+ - !ruby/object:Gem::Dependency
140
+ name: yard
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: 0.8.7.3
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: 0.8.7.3
153
+ description: WebSocket client that does not require asynchronous programming
154
+ email: costan@gmail.com
155
+ executables: []
156
+ extensions: []
157
+ extra_rdoc_files:
158
+ - LICENSE.txt
159
+ - README.rdoc
160
+ files:
161
+ - .document
162
+ - Gemfile
163
+ - Gemfile.lock
164
+ - LICENSE.txt
165
+ - README.rdoc
166
+ - Rakefile
167
+ - VERSION
168
+ - lib/ws_sync_client.rb
169
+ - test/fixtures/ws_server.rb
170
+ - test/helper.rb
171
+ - test/test_ws_sync_client.rb
172
+ homepage: http://github.com/pwnall/ws_sync_client
173
+ licenses:
174
+ - MIT
175
+ metadata: {}
176
+ post_install_message:
177
+ rdoc_options: []
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - '>='
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - '>='
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ requirements: []
191
+ rubyforge_project:
192
+ rubygems_version: 2.0.14
193
+ signing_key:
194
+ specification_version: 4
195
+ summary: Synchronous WebSocket client
196
+ test_files: []