em-rocketio-client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in em-rocketio-client.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Sho Hashimoto
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ em-rocketio-client
2
+ ==================
3
+ [Sinatra RocketIO](https://github.com/shokai/sinatra-rocketio) Client for eventmachine
4
+
5
+ * https://github.com/shokai/em-rocketio-client
6
+
7
+ Installation
8
+ ------------
9
+
10
+ % gem install em-rocketio-client
11
+
12
+
13
+ Usage
14
+ -----
15
+
16
+ ```ruby
17
+ require 'eventmachine'
18
+ require 'em-rocketio-client'
19
+
20
+ EM::run do
21
+ io = EM::RocketIO::Client.new('http://localhost:5000').connect
22
+ # io = EM::RocketIO::Client.new('http://localhost:5000', :type => :comet).connect
23
+
24
+ io.on :connect do |session|
25
+ puts "#{io.type} connect!! (sessin_id:#{session})"
26
+ end
27
+
28
+ io.on :disconnect do
29
+ puts "#{io.type} disconnect"
30
+ end
31
+
32
+ io.on :error do |err|
33
+ STDERR.puts err
34
+ end
35
+
36
+ ## regist receive "chat" event
37
+ io.on :chat do |data|
38
+ puts "#{data['name']} - #{data['message']}"
39
+ end
40
+
41
+ ## push "chat" event to Server
42
+ EM::add_periodic_timer 10 do
43
+ io.push :chat, {:message => Time.now.to_s, :name => 'clock'}
44
+ end
45
+ end
46
+ ```
47
+
48
+
49
+ Sample
50
+ ------
51
+
52
+ start [chat server](https://github.com/shokai/rocketio-chat-sample)
53
+
54
+ % git clone git://github.com/shokai/rocketio-chat-sample.git
55
+ % cd rocketio-chat-sample
56
+ % bundle install
57
+ % foreman start
58
+
59
+ => http://localhost:5000
60
+
61
+
62
+ sample chat client
63
+
64
+ % ruby sample/cui_chat_client.rb
65
+
66
+
67
+ Test
68
+ ----
69
+
70
+ % gem install bundler
71
+ % bundle install
72
+ % export PORT=5000
73
+ % export WS_PORT=8080
74
+ % export PID_FILE=/tmp/em-rocketio-client-testapp.pid
75
+ % rake test
76
+
77
+
78
+ Contributing
79
+ ------------
80
+
81
+ 1. Fork it
82
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
83
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
84
+ 4. Push to the branch (`git push origin my-new-feature`)
85
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.pattern = "test/test_*.rb"
6
+ end
7
+
8
+ task :default => :test
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'em-rocketio-client/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "em-rocketio-client"
8
+ spec.version = EventMachine::RocketIO::Client::VERSION
9
+ spec.authors = ["Sho Hashimoto"]
10
+ spec.email = ["hashimoto@shokai.org"]
11
+ spec.description = %q{Sinatra RocketIO client for eventmachine}
12
+ spec.summary = spec.description
13
+ spec.homepage = "https://github.com/shokai/em-rocketio-client"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/).reject{|f| f == "Gemfile.lock" }
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "minitest"
24
+ spec.add_development_dependency "sinatra-rocketio"
25
+ spec.add_development_dependency "thin"
26
+
27
+ spec.add_dependency "em-cometio-client"
28
+ spec.add_dependency "em-websocketio-client"
29
+ spec.add_dependency "eventmachine"
30
+ spec.add_dependency "event_emitter"
31
+ end
@@ -0,0 +1,50 @@
1
+ module EventMachine
2
+ module RocketIO
3
+ class Client
4
+ class Error < StandardError
5
+ end
6
+
7
+ include EventEmitter
8
+ attr_reader :settings, :type, :io
9
+
10
+ def initialize(url, opt={:type => :websocket})
11
+ @settings = JSON.parse HTTParty.get("#{url}/rocketio/settings").body
12
+ type = opt[:type].to_sym
13
+ if type == :websocket and @settings.include? 'websocket'
14
+ @type = :websocket
15
+ @io = EM::WebSocketIO::Client.new @settings['websocket']
16
+ elsif type == :comet or @settings.include? 'comet'
17
+ @type = :comet
18
+ @io = EM::CometIO::Client.new @settings['comet']
19
+ else
20
+ raise Error, "cannot find #{type} IO #{url}"
21
+ end
22
+ this = self
23
+ if @io
24
+ @io.on :* do |event_name, *args|
25
+ this.emit event_name, *args
26
+ end
27
+ end
28
+ self
29
+ end
30
+
31
+ def connect
32
+ @io.connect
33
+ self
34
+ end
35
+
36
+ def close
37
+ @io.close
38
+ end
39
+
40
+ def push(type, data={})
41
+ @io.push type, data
42
+ end
43
+
44
+ def method_missing(name, *args)
45
+ @io.__send__ name, *args
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,7 @@
1
+ module EventMachine
2
+ module RocketIO
3
+ class Client
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ require "em-cometio-client"
2
+ require "em-websocketio-client"
3
+ require "event_emitter"
4
+ require "httparty"
5
+
6
+ require "em-rocketio-client/version"
7
+ require "em-rocketio-client/client"
8
+
9
+ module EventMachine
10
+ module RocketIO
11
+ class Client
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.expand_path '../lib', File.dirname(__FILE__)
3
+ require 'rubygems'
4
+ require 'em-rocketio-client'
5
+
6
+ name = `whoami`.strip || 'shokai'
7
+
8
+ EM::run do
9
+ io = EM::RocketIO::Client.new('http://localhost:5000').connect
10
+ # io = EM::RocketIO::Client.new('http://localhost:5000', :type => :comet).connect
11
+
12
+ puts "waiting #{io.url}"
13
+
14
+ io.on :connect do |session|
15
+ puts "#{io.type} connect!! (sessin_id:#{session})"
16
+ end
17
+
18
+ io.on :disconnect do
19
+ puts "#{io.type} disconnect"
20
+ end
21
+
22
+ io.on :chat do |data|
23
+ puts "<#{data['name']}> #{data['message']}"
24
+ end
25
+
26
+ io.on :error do |err|
27
+ STDERR.puts err
28
+ end
29
+
30
+ EM::defer do
31
+ loop do
32
+ line = STDIN.gets.strip
33
+ next if line.empty?
34
+ io.push :chat, {:message => line, :name => name}
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+ require 'sinatra/base'
4
+ $stdout.sync = true
5
+ require 'sinatra/rocketio'
6
+ require File.dirname(__FILE__)+'/main'
7
+
8
+ set :websocketio, :port => ENV['WS_PORT'].to_i
9
+
10
+ run TestApp
data/test/app/main.rb ADDED
@@ -0,0 +1,38 @@
1
+ pid_file = ENV['PID_FILE'] || "/tmp/em-rocketio-test-pid"
2
+ EM::defer do
3
+ while !EM::reactor_running? do
4
+ sleep 0.1
5
+ end
6
+ File.open(pid_file, "w+") do |f|
7
+ f.write Process.pid.to_s
8
+ end
9
+ end
10
+
11
+ class TestApp < Sinatra::Base
12
+ register Sinatra::RocketIO
13
+ io = Sinatra::RocketIO
14
+
15
+ get '/' do
16
+ "sinatra-rocketio v#{Sinatra::RocketIO::VERSION}"
17
+ end
18
+
19
+ io.on :connect do |session, type|
20
+ puts "new client <session:#{session}> <type:#{type}>"
21
+ end
22
+
23
+ io.on :disconnect do |session, type|
24
+ puts "disconnect client <session:#{session}> <type:#{type}>"
25
+ end
26
+
27
+ io.on :broadcast do |data, from, type|
28
+ puts from
29
+ puts "broadcast <session:#{from}> <type:#{type}> - #{data.to_json}"
30
+ push :broadcast, data
31
+ end
32
+
33
+ io.on :message do |data, from, type|
34
+ puts "message <session:#{from}> <type:#{type}> - #{data.to_json}"
35
+ push :message, data, :to => data['to']
36
+ end
37
+
38
+ end
data/test/app.rb ADDED
@@ -0,0 +1,71 @@
1
+ class App
2
+
3
+ def self.running
4
+ @running ? true : false
5
+ end
6
+
7
+ def self.port
8
+ ENV['PORT'] || 5000
9
+ end
10
+
11
+ def self.ws_port
12
+ ENV['WS_PORT'] || 8080
13
+ end
14
+
15
+ def self.url
16
+ "http://localhost:#{port}"
17
+ end
18
+
19
+ def self.websocketio_url
20
+ "ws://localhost:#{ws_port}"
21
+ end
22
+
23
+ def self.cometio_url
24
+ "http://localhost:#{port}/cometio/io"
25
+ end
26
+
27
+ def self.pid_file
28
+ ENV['PID_FILE'] || "/tmp/em-rocketio-testapp.pid"
29
+ end
30
+
31
+ def self.app_dir
32
+ File.expand_path 'app', File.dirname(__FILE__)
33
+ end
34
+
35
+ def self.pid
36
+ return unless @running
37
+ File.open(pid_file) do |f|
38
+ pid = f.gets.strip.to_i
39
+ return pid if pid > 0
40
+ end
41
+ return
42
+ end
43
+
44
+ def self.start
45
+ return if @running
46
+ File.delete pid_file if File.exists? pid_file
47
+ Thread.new do
48
+ IO::popen "cd #{app_dir} && PID_FILE=#{pid_file} WS_PORT=#{ws_port} rackup config.ru -p #{port} > /dev/null 2>&1"
49
+ end
50
+ @running = true
51
+ 100.times do
52
+ if File.exists? pid_file
53
+ sleep 2
54
+ return true
55
+ end
56
+ sleep 0.1
57
+ end
58
+ @running = false
59
+ return false
60
+ end
61
+
62
+ def self.stop
63
+ return unless @running
64
+ if File.exists? pid_file
65
+ system "kill -9 #{pid}"
66
+ File.delete pid_file
67
+ end
68
+ @running = false
69
+ end
70
+
71
+ end
@@ -0,0 +1,110 @@
1
+ require File.expand_path 'test_helper', File.dirname(__FILE__)
2
+
3
+ class TestEmRocketioClient < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ App.start
7
+ end
8
+
9
+ def teardown
10
+ App.stop
11
+ end
12
+
13
+ def test_websocket_to_comet
14
+ ## websocket --> server --> comet
15
+ post_data = {:time => Time.now.to_s, :msg => 'hello!!', :to => nil}
16
+ res = nil
17
+ res2 = nil
18
+ EM::run do
19
+ client = EM::RocketIO::Client.new(App.url, :type => :websocket).connect
20
+ client.on :message do |data|
21
+ res = data
22
+ EM::add_timer 1 do
23
+ EM::stop
24
+ end
25
+ end
26
+
27
+ client.on :disconnect do
28
+ EM::add_timer 1 do
29
+ EM::stop
30
+ end
31
+ end
32
+
33
+ client.on :connect do |session|
34
+ client2 = EM::RocketIO::Client.new(App.url, :type => :comet).connect
35
+ client2.on :connect do |session2|
36
+ post_data['to'] = session2
37
+ client.push :message, post_data
38
+ end
39
+ client2.on :message do |data|
40
+ res2 = data
41
+ client2.close
42
+ client.close
43
+ EM::add_timer 1 do
44
+ EM::stop
45
+ end
46
+ end
47
+ end
48
+
49
+ EM::defer do
50
+ 50.times do
51
+ break if res != nil
52
+ sleep 0.1
53
+ end
54
+ client.close
55
+ end
56
+ end
57
+ assert res2 != nil, 'server not respond'
58
+ assert res2["time"] == post_data[:time]
59
+ assert res2["msg"] == post_data[:msg]
60
+ assert res == nil
61
+ end
62
+
63
+ def test_comet_to_websocket
64
+ ## comet --> server --> websocket
65
+ post_data = {:time => Time.now.to_s, :msg => 'hello!!', :to => nil}
66
+ res = nil
67
+ res2 = nil
68
+ EM::run do
69
+ client = EM::RocketIO::Client.new(App.url, :type => :comet).connect
70
+ client.on :message do |data|
71
+ res = data
72
+ EM::add_timer 1 do
73
+ EM::stop
74
+ end
75
+ end
76
+
77
+ client.on :connect do |session|
78
+ client2 = EM::RocketIO::Client.new(App.url, :type => :websocket).connect
79
+ client2.on :connect do |session2|
80
+ post_data['to'] = session2
81
+ client.push :message, post_data
82
+ end
83
+ client2.on :message do |data|
84
+ res2 = data
85
+ client2.close
86
+ client.close
87
+ EM::add_timer 1 do
88
+ EM::stop
89
+ end
90
+ end
91
+ end
92
+
93
+ EM::defer do
94
+ 50.times do
95
+ break if res != nil
96
+ sleep 0.1
97
+ end
98
+ client.close
99
+ EM::add_timer 1 do
100
+ EM::stop
101
+ end
102
+ end
103
+ end
104
+ assert res2 != nil, 'server not respond'
105
+ assert res2["time"] == post_data[:time]
106
+ assert res2["msg"] == post_data[:msg]
107
+ assert res == nil
108
+ end
109
+
110
+ end
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ $:.unshift File.expand_path '../lib', File.dirname(__FILE__)
4
+ require 'minitest/autorun'
5
+ require 'em-rocketio-client'
6
+ require File.expand_path 'app', File.dirname(__FILE__)
7
+
8
+
9
+ ['SIGHUP', 'SIGINT', 'SIGKILL', 'SIGTERM'].each do |sig|
10
+ Kernel.trap sig do
11
+ App.stop
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,216 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-rocketio-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sho Hashimoto
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: minitest
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: sinatra-rocketio
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: thin
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: em-cometio-client
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: em-websocketio-client
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: eventmachine
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: event_emitter
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :runtime
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ description: Sinatra RocketIO client for eventmachine
159
+ email:
160
+ - hashimoto@shokai.org
161
+ executables: []
162
+ extensions: []
163
+ extra_rdoc_files: []
164
+ files:
165
+ - .gitignore
166
+ - Gemfile
167
+ - LICENSE.txt
168
+ - README.md
169
+ - Rakefile
170
+ - em-rocketio-client.gemspec
171
+ - lib/em-rocketio-client.rb
172
+ - lib/em-rocketio-client/client.rb
173
+ - lib/em-rocketio-client/version.rb
174
+ - sample/cui_chat_client.rb
175
+ - test/app.rb
176
+ - test/app/config.ru
177
+ - test/app/main.rb
178
+ - test/test_em_rocketio_client.rb
179
+ - test/test_helper.rb
180
+ homepage: https://github.com/shokai/em-rocketio-client
181
+ licenses:
182
+ - MIT
183
+ post_install_message:
184
+ rdoc_options: []
185
+ require_paths:
186
+ - lib
187
+ required_ruby_version: !ruby/object:Gem::Requirement
188
+ none: false
189
+ requirements:
190
+ - - ! '>='
191
+ - !ruby/object:Gem::Version
192
+ version: '0'
193
+ segments:
194
+ - 0
195
+ hash: 2360181630930510065
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ none: false
198
+ requirements:
199
+ - - ! '>='
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ segments:
203
+ - 0
204
+ hash: 2360181630930510065
205
+ requirements: []
206
+ rubyforge_project:
207
+ rubygems_version: 1.8.24
208
+ signing_key:
209
+ specification_version: 3
210
+ summary: Sinatra RocketIO client for eventmachine
211
+ test_files:
212
+ - test/app.rb
213
+ - test/app/config.ru
214
+ - test/app/main.rb
215
+ - test/test_em_rocketio_client.rb
216
+ - test/test_helper.rb