editserver 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/README.markdown +3 -2
- data/lib/editserver/command.rb +66 -13
- data/lib/editserver/version.rb +1 -1
- data/lib/editserver.rb +2 -3
- data/test/editserver/command.test.rb +196 -13
- data/test/editserver/socket-test.rb +16 -0
- metadata +5 -7
- data/test/editserver/terminal/emacs.test.rb +0 -5
- data/test/editserver/terminal/vim.test.rb +0 -5
data/.gitignore
CHANGED
data/README.markdown
CHANGED
|
@@ -20,9 +20,10 @@ Everything works, and core tests are in place. More information forthcoming.
|
|
|
20
20
|
|
|
21
21
|
### TODO
|
|
22
22
|
|
|
23
|
-
* Finish remaining tests
|
|
24
23
|
* Improve applescript reliability
|
|
25
|
-
*
|
|
24
|
+
* Avoid dynamic creation of Editor subclasses in `Editserver::` namespace
|
|
25
|
+
(a consequence of an earlier design decision)
|
|
26
|
+
* Special case: OS X's `Terminal.app` as `editor['terminal']`
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
[1]: https://chrome.google.com/webstore/detail/ppoadiihggafnhokfkpphojggcdigllp
|
data/lib/editserver/command.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'optparse'
|
|
2
|
+
require 'fileutils'
|
|
2
3
|
require 'yaml'
|
|
3
4
|
require 'webrick/log'
|
|
4
5
|
require 'rack'
|
|
@@ -24,6 +25,7 @@ class Editserver
|
|
|
24
25
|
:AccessLog => [], # rack does its own access logging, so keep this blank
|
|
25
26
|
:pid => nil,
|
|
26
27
|
:config => '',
|
|
28
|
+
:daemonize => false,
|
|
27
29
|
:environment => 'deployment'
|
|
28
30
|
}
|
|
29
31
|
end
|
|
@@ -38,36 +40,65 @@ class Editserver
|
|
|
38
40
|
Options:
|
|
39
41
|
).gsub /^ +/, ''
|
|
40
42
|
|
|
41
|
-
opt.on '-
|
|
43
|
+
opt.on '-H', '--host HOST', "IP/Hostname to bind to; #{rackopts[:Host]} by default" do |arg|
|
|
44
|
+
@rackopts[:Host] = arg
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
opt.on '-p', '--port NUMBER', Integer, "Port to bind; #{rackopts[:Port]} by default" do |arg|
|
|
42
48
|
@rackopts[:Port] = arg
|
|
43
49
|
end
|
|
44
50
|
|
|
51
|
+
opt.on '-d', '--default EDITOR', 'Editor to launch at root path; May be one of:',
|
|
52
|
+
(Editserver.new(editoropts).editors.keys - ['default']).join(', ') do |arg|
|
|
53
|
+
@editoropts['default'] = arg
|
|
54
|
+
end
|
|
55
|
+
|
|
45
56
|
opt.on '-t', '--terminal CMD', 'Terminal to launch for console editors' do |arg|
|
|
46
57
|
@editoropts['terminal'] = arg
|
|
47
58
|
end
|
|
48
59
|
|
|
49
|
-
opt.on '
|
|
50
|
-
|
|
51
|
-
@
|
|
60
|
+
opt.on '-f', '--fork', 'Fork and daemonize; returns pid of daemon' do
|
|
61
|
+
@rackopts[:daemonize] = true
|
|
62
|
+
@rackopts[:pid] = "/tmp/#{File.basename $0}/#{File.basename $0}.pid"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
opt.on '-q', '--quiet', 'Produce no output' do
|
|
66
|
+
@opts[:quiet] = true
|
|
67
|
+
@rackopts[:Logger] = WEBrick::Log.new nil, WEBrick::BasicLog::FATAL - 1 # zero, essentially
|
|
68
|
+
@rackopts[:environment] = 'none'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
opt.on '--rc PATH', "Path to rc file; #{@opts[:rcfile]} by default" do |arg|
|
|
72
|
+
@rcopts = nil # reset cached user opts
|
|
52
73
|
@opts[:rcfile] = File.expand_path arg
|
|
53
74
|
end
|
|
54
75
|
|
|
55
76
|
opt.on '--no-rc', 'Suppress reading of rc file' do
|
|
77
|
+
@rcopts = nil
|
|
56
78
|
@opts[:norcfile] = true
|
|
57
79
|
end
|
|
80
|
+
|
|
81
|
+
# normally implicit, but must be explicit when having an option beginning with `h'
|
|
82
|
+
opt.on_tail '-h', '--help' do
|
|
83
|
+
puts opt; exit
|
|
84
|
+
end
|
|
58
85
|
end
|
|
59
86
|
end
|
|
60
87
|
|
|
88
|
+
def say str
|
|
89
|
+
puts str unless @opts[:quiet]
|
|
90
|
+
end
|
|
91
|
+
|
|
61
92
|
def rcopts
|
|
62
93
|
@rcopts ||= begin
|
|
63
94
|
empty = { 'rack' => {}, 'editor' => {} }
|
|
64
|
-
rcfile = File.expand_path
|
|
95
|
+
rcfile = File.expand_path @opts[:rcfile]
|
|
65
96
|
|
|
66
97
|
if @opts[:norcfile]
|
|
67
98
|
empty
|
|
68
99
|
elsif File.exists? rcfile
|
|
69
100
|
opts = YAML.load_file File.expand_path(rcfile)
|
|
70
|
-
opts
|
|
101
|
+
opts = {} unless opts.is_a? Hash
|
|
71
102
|
opts['rack'] ||= {}
|
|
72
103
|
opts['editor'] ||= {}
|
|
73
104
|
opts
|
|
@@ -103,13 +134,30 @@ class Editserver
|
|
|
103
134
|
|
|
104
135
|
def run
|
|
105
136
|
options.parse @args
|
|
137
|
+
$0 = 'editserver'
|
|
138
|
+
|
|
139
|
+
# Rack::Server issues shutdown on SIGINT only
|
|
140
|
+
trap :TERM do
|
|
141
|
+
trap :TERM, 'DEFAULT'
|
|
142
|
+
Process.kill :INT, $$
|
|
143
|
+
end
|
|
106
144
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
145
|
+
if rackopts[:daemonize]
|
|
146
|
+
FileUtils.mkdir_p File.dirname(rackopts[:pid])
|
|
147
|
+
Process.wait fork { server.start }
|
|
148
|
+
sleep 0.1 until File.exists? rackopts[:pid] and File.read(rackopts[:pid]).to_i > 0
|
|
149
|
+
|
|
150
|
+
say host_and_port
|
|
151
|
+
say "Editserver PID: #{fx File.read(rackopts[:pid]), [36,1]}"
|
|
152
|
+
else
|
|
153
|
+
begin
|
|
154
|
+
say banner
|
|
155
|
+
server.start
|
|
156
|
+
say fx("\nGoodbye!", [32,1])
|
|
157
|
+
rescue StandardError => e
|
|
158
|
+
say fx(e.to_s, [31,1])
|
|
159
|
+
exit e.respond_to?(:errno) ? e.errno : 1
|
|
160
|
+
end
|
|
113
161
|
end
|
|
114
162
|
end
|
|
115
163
|
|
|
@@ -125,10 +173,15 @@ class Editserver
|
|
|
125
173
|
\\ \\____\\ \\___,_\\ \\_\\ \\__\\/\\____/\\ \\____\\\\ \\_\\ \\ \\___/ \\ \\____\\\\ \\_\\
|
|
126
174
|
\\/____/\\/__,_ /\\/_/\\/__/\\/___/ \\/____/ \\/_/ \\/__/ \\/____/ \\/_/
|
|
127
175
|
|
|
128
|
-
|
|
176
|
+
#{host_and_port}
|
|
177
|
+
Press #{fx 'Ctrl-C', [36,1]} to exit.\
|
|
129
178
|
).gsub(/^ {8}/, '')
|
|
130
179
|
end
|
|
131
180
|
|
|
181
|
+
def host_and_port
|
|
182
|
+
"Listening on #{fx "#{rackopts[:Host]}:#{rackopts[:Port]}", [32,1]}"
|
|
183
|
+
end
|
|
184
|
+
|
|
132
185
|
def fx str, effects = []
|
|
133
186
|
return str unless $stdout.tty?
|
|
134
187
|
str.gsub /^(.*)$/, "\e[#{[effects].flatten.join ';'}m\\1\e[0m"
|
data/lib/editserver/version.rb
CHANGED
data/lib/editserver.rb
CHANGED
|
@@ -12,9 +12,8 @@ class Editserver
|
|
|
12
12
|
# OS X editors
|
|
13
13
|
'mate' => 'mate -w',
|
|
14
14
|
'mvim' => 'mvim --nofork --servername EDITSERVER', # does not return when app must be launched
|
|
15
|
-
'kod' => 'open -a Kod -W', # app must quit to release control
|
|
16
15
|
'bbedit' => 'bbedit -w' # does not open file properly when app is launched
|
|
17
|
-
}
|
|
16
|
+
}.reject { |k,v| not File.executable? %x(which #{k.shellsplit[0]}).chomp }
|
|
18
17
|
|
|
19
18
|
attr_reader :editors
|
|
20
19
|
|
|
@@ -78,8 +77,8 @@ class Editserver
|
|
|
78
77
|
klass = editor request.path_info
|
|
79
78
|
Response.new(klass.new, request).call
|
|
80
79
|
rescue RoutingError => e
|
|
81
|
-
warn e.to_s
|
|
82
80
|
res = Rack::Response.new
|
|
81
|
+
res.write e.to_s
|
|
83
82
|
res.status = 500
|
|
84
83
|
res.finish
|
|
85
84
|
end
|
|
@@ -1,37 +1,57 @@
|
|
|
1
1
|
$:.unshift File.expand_path('../../lib', __FILE__)
|
|
2
|
+
$:.unshift File.dirname(__FILE__)
|
|
2
3
|
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
require 'yaml'
|
|
6
|
+
require 'webrick/log'
|
|
7
|
+
require 'rack/server'
|
|
3
8
|
require 'editserver/command'
|
|
4
9
|
require 'minitest/pride' if $stdout.tty?
|
|
5
10
|
require 'minitest/autorun'
|
|
11
|
+
require 'socket-test'
|
|
6
12
|
|
|
7
13
|
describe Editserver::Command do
|
|
14
|
+
before { @cmd = Editserver::Command.new ['--no-rc'] }
|
|
15
|
+
|
|
8
16
|
describe :initialize do
|
|
9
17
|
it 'should take a single optional argument' do
|
|
10
18
|
Editserver::Command.method(:initialize).arity.must_equal -1
|
|
11
19
|
end
|
|
12
20
|
|
|
13
21
|
it 'should set internal state' do
|
|
14
|
-
cmd
|
|
15
|
-
cmd.instance_variable_get(:@
|
|
16
|
-
cmd.instance_variable_get(:@
|
|
17
|
-
cmd.instance_variable_get(:@
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
].sort_by &:to_s
|
|
22
|
+
@cmd.instance_variable_get(:@args).must_equal ['--no-rc']
|
|
23
|
+
@cmd.instance_variable_get(:@opts).must_equal(:rcfile => '~/.editserverrc')
|
|
24
|
+
@cmd.instance_variable_get(:@editoropts).must_equal('default' => nil, 'terminal' => nil)
|
|
25
|
+
@cmd.instance_variable_get(:@rackopts).keys.sort_by(&:to_s).must_equal [
|
|
26
|
+
:Host, :Port, :Logger, :AccessLog, :pid, :config, :daemonize, :environment
|
|
27
|
+
].sort_by(&:to_s)
|
|
21
28
|
end
|
|
22
29
|
end
|
|
23
30
|
|
|
24
31
|
describe :options do
|
|
25
|
-
before { @cmd = Editserver::Command.new ['--no-rc'] }
|
|
26
|
-
|
|
27
32
|
it 'should return an OptionParser object' do
|
|
28
33
|
@cmd.options.must_be_kind_of OptionParser
|
|
29
34
|
end
|
|
30
35
|
|
|
31
36
|
it 'should modify internal state when parsing a list of arguments' do
|
|
37
|
+
@cmd.options.parse %w[--host 0.0.0.0]
|
|
38
|
+
@cmd.instance_variable_get(:@rackopts)[:Host].must_equal '0.0.0.0'
|
|
39
|
+
|
|
32
40
|
@cmd.options.parse %w[--port 1000]
|
|
33
41
|
@cmd.instance_variable_get(:@rackopts)[:Port].must_equal 1000
|
|
34
42
|
|
|
43
|
+
@cmd.options.parse %w[--fork]
|
|
44
|
+
@cmd.instance_variable_get(:@rackopts)[:daemonize].must_equal true
|
|
45
|
+
@cmd.instance_variable_get(:@rackopts)[:pid].must_equal "/tmp/#{File.basename $0}/#{File.basename $0}.pid"
|
|
46
|
+
|
|
47
|
+
@cmd.options.parse %w[--quiet]
|
|
48
|
+
@cmd.instance_variable_get(:@opts)[:quiet].must_equal true
|
|
49
|
+
@cmd.instance_variable_get(:@rackopts)[:Logger].level.must_equal WEBrick::BasicLog::FATAL - 1
|
|
50
|
+
@cmd.instance_variable_get(:@rackopts)[:environment].must_equal 'none'
|
|
51
|
+
|
|
52
|
+
@cmd.options.parse %w[--default mate]
|
|
53
|
+
@cmd.instance_variable_get(:@editoropts)['default'].must_equal 'mate'
|
|
54
|
+
|
|
35
55
|
@cmd.options.parse %w[--terminal xterm]
|
|
36
56
|
@cmd.instance_variable_get(:@editoropts)['terminal'].must_equal 'xterm'
|
|
37
57
|
|
|
@@ -43,22 +63,185 @@ describe Editserver::Command do
|
|
|
43
63
|
end
|
|
44
64
|
end
|
|
45
65
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
66
|
+
describe :say do
|
|
67
|
+
it 'should write to $stdout unless --quiet option is specified' do
|
|
68
|
+
capture_io { @cmd.say 'AHHHHHH!' }.first.must_equal "AHHHHHH!\n"
|
|
69
|
+
@cmd.instance_variable_get(:@opts)[:quiet] = true
|
|
70
|
+
capture_io { @cmd.say 'AHHHHHH!' }.first.must_equal ''
|
|
71
|
+
end
|
|
72
|
+
end
|
|
49
73
|
|
|
50
74
|
describe :rcopts do
|
|
51
|
-
|
|
75
|
+
before do
|
|
76
|
+
@rcfile = Tempfile.new 'editserverrc'
|
|
77
|
+
@cmd.instance_variable_get(:@opts)[:rcfile] = @rcfile.path
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
after { (@rcfile.close; @rcfile.unlink) if @rcfile.path }
|
|
81
|
+
|
|
82
|
+
it 'should load the YAML file specified at @opts[:rcfile]' do
|
|
83
|
+
opts = { 'editor' => { 'default' => 'emacs', 'terminal' => 'xterm' }, 'rack' => { 'port' => 1000 } }
|
|
84
|
+
@rcfile.write opts.to_yaml
|
|
85
|
+
@rcfile.rewind
|
|
86
|
+
@cmd.rcopts.must_equal opts
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'should create any missing top level keys' do
|
|
90
|
+
@rcfile.write({ 'foo' => 'bar' }.to_yaml)
|
|
91
|
+
@rcfile.rewind
|
|
92
|
+
@cmd.rcopts.must_equal 'foo' => 'bar', 'rack' => {}, 'editor' => {}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'should return bare options if --no-rc is specified' do
|
|
96
|
+
opts = { 'editor' => { 'default' => 'emacs', 'terminal' => 'xterm' }, 'rack' => { 'port' => 1000 } }
|
|
97
|
+
@rcfile.write opts.to_yaml
|
|
98
|
+
@rcfile.rewind
|
|
99
|
+
@cmd.instance_variable_get(:@opts)[:norcfile] = true
|
|
100
|
+
@cmd.rcopts.must_equal 'rack' => {}, 'editor' => {}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'should return bare options if rcfile does not exist' do
|
|
104
|
+
opts = { 'editor' => { 'default' => 'emacs', 'terminal' => 'xterm' }, 'rack' => { 'port' => 1000 } }
|
|
105
|
+
@rcfile.write opts.to_yaml
|
|
106
|
+
@rcfile.rewind
|
|
107
|
+
@rcfile.close
|
|
108
|
+
@rcfile.unlink
|
|
109
|
+
@cmd.rcopts.must_equal 'rack' => {}, 'editor' => {}
|
|
110
|
+
end
|
|
111
|
+
end # rcopts
|
|
52
112
|
|
|
53
113
|
describe :rackopts do
|
|
114
|
+
it 'should return @rackopts masked with @rcopts' do
|
|
115
|
+
@cmd.instance_variable_get(:@opts)[:rcfile] = '/dev/null'
|
|
116
|
+
@cmd.rackopts[:Port].must_equal 9999
|
|
117
|
+
@cmd.rackopts[:Host].must_equal '127.0.0.1'
|
|
118
|
+
@cmd.instance_variable_get(:@rcopts).merge!('rack' => { 'port' => 65535, 'host' => '1.1.1.1' })
|
|
119
|
+
@cmd.rackopts[:Port].must_equal 65535
|
|
120
|
+
@cmd.rackopts[:Host].must_equal '1.1.1.1'
|
|
121
|
+
end
|
|
54
122
|
end
|
|
55
123
|
|
|
56
124
|
describe :editoropts do
|
|
125
|
+
it 'should return @editoropts masked with @rcopts' do
|
|
126
|
+
@cmd.instance_variable_get(:@opts)[:rcfile] = '/dev/null'
|
|
127
|
+
@cmd.editoropts['default'].must_equal nil
|
|
128
|
+
@cmd.editoropts['terminal'].must_equal nil
|
|
129
|
+
@cmd.instance_variable_get(:@rcopts).merge!('editor' => { 'default' => 'pony', 'terminal' => 'sparkles' })
|
|
130
|
+
@cmd.editoropts['default'].must_equal 'pony'
|
|
131
|
+
@cmd.editoropts['terminal'].must_equal 'sparkles'
|
|
132
|
+
end
|
|
57
133
|
end
|
|
58
134
|
|
|
59
135
|
describe :server do
|
|
136
|
+
it 'should return an instance of Rack::Server' do
|
|
137
|
+
@cmd.server.must_be_kind_of Rack::Server
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it 'should pass rack options to new server instance' do
|
|
141
|
+
@cmd.rcopts['rack']['port'] = 4000
|
|
142
|
+
@cmd.server.options[:Port].must_equal 4000
|
|
143
|
+
@cmd.rcopts['rack']['pid'] = '/dev/null'
|
|
144
|
+
@cmd.server.options[:pid].must_equal '/dev/null'
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "should set the server's @app to an instance of Editserver" do
|
|
148
|
+
@cmd.server.app.must_be_kind_of Editserver
|
|
149
|
+
end
|
|
60
150
|
end
|
|
61
151
|
|
|
62
152
|
describe :run do
|
|
153
|
+
it 'should parse the arguments stored in @args' do
|
|
154
|
+
@cmd.instance_variable_set :@args, ['--help']
|
|
155
|
+
|
|
156
|
+
rd, wr = IO.pipe
|
|
157
|
+
|
|
158
|
+
pid = fork do
|
|
159
|
+
rd.close
|
|
160
|
+
$stdout.reopen wr
|
|
161
|
+
@cmd.run
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
wr.close
|
|
165
|
+
Process.wait2(pid).last.exitstatus.must_equal 0
|
|
166
|
+
rd.read.must_match /Usage:.*--help/m
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it 'should start the server, and shutdown on SIGINT and SIGTERM' do
|
|
170
|
+
# thread, because we don't want to serially boot two servers
|
|
171
|
+
pool = []
|
|
172
|
+
[[:INT, 10000], [:TERM, 10001]].each do |sig, port|
|
|
173
|
+
pool << Thread.new do
|
|
174
|
+
cmd = @cmd.dup
|
|
175
|
+
rd, wr = IO.pipe
|
|
176
|
+
|
|
177
|
+
cmd.instance_variable_get(:@rackopts)[:Port] = port
|
|
178
|
+
|
|
179
|
+
pid = fork do
|
|
180
|
+
rd.close
|
|
181
|
+
$stdout.reopen wr
|
|
182
|
+
cmd.run
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
wr.close
|
|
186
|
+
|
|
187
|
+
sleep 0.1 until SocketTest.open? cmd.rackopts[:Host], port
|
|
188
|
+
|
|
189
|
+
Process.kill sig, pid
|
|
190
|
+
|
|
191
|
+
# give the server some time to shutdown
|
|
192
|
+
tries = 0
|
|
193
|
+
until Process.wait pid, Process::WNOHANG
|
|
194
|
+
sleep 0.1
|
|
195
|
+
# but no more than 2 seconds
|
|
196
|
+
Process.kill :KILL, pid if (tries += 1) > 20
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
(tries <= 20).must_equal true
|
|
200
|
+
rd.read.must_match /Listening.*#{cmd.rackopts[:Host]}:#{port}/
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
pool.each &:join
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it 'should daemonize and write pidfile in daemon mode' do
|
|
208
|
+
@cmd.options.parse ['--fork', '--port=10002']
|
|
209
|
+
|
|
210
|
+
begin
|
|
211
|
+
bgpid = fork do
|
|
212
|
+
$stdout.reopen '/dev/null' # we're not too interested in this output
|
|
213
|
+
@cmd.run
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
sleep 0.1 until SocketTest.open? @cmd.rackopts[:Host], @cmd.rackopts[:Port]
|
|
217
|
+
Process.wait bgpid
|
|
218
|
+
|
|
219
|
+
pidfile = @cmd.rackopts[:pid]
|
|
220
|
+
pidbuf = File.read pidfile
|
|
221
|
+
pid = pidbuf.to_i
|
|
222
|
+
|
|
223
|
+
pidbuf.must_match /\A\d+\z/ # does it look like a pid?
|
|
224
|
+
Process.kill(0, pid).must_equal 1 # is it really alive?
|
|
225
|
+
ensure
|
|
226
|
+
# make sure the sucker dies
|
|
227
|
+
Process.kill :INT, pid
|
|
228
|
+
tries = 0
|
|
229
|
+
loop do
|
|
230
|
+
begin
|
|
231
|
+
Process.kill 0, pid
|
|
232
|
+
sleep 0.1
|
|
233
|
+
rescue Errno::ESRCH
|
|
234
|
+
break
|
|
235
|
+
end
|
|
236
|
+
if (tries += 1) > 20
|
|
237
|
+
Process.kill :KILL, pid
|
|
238
|
+
break
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
(tries <= 20).must_equal true
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
File.exists?(@cmd.rackopts[:pid]).must_equal false
|
|
245
|
+
end
|
|
63
246
|
end
|
|
64
247
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
|
|
3
|
+
module SocketTest
|
|
4
|
+
class << self
|
|
5
|
+
include Socket::Constants
|
|
6
|
+
|
|
7
|
+
def open? host, port
|
|
8
|
+
sock = Socket.new AF_INET, SOCK_STREAM, 0
|
|
9
|
+
addr = Socket.sockaddr_in port, host
|
|
10
|
+
sock.connect addr
|
|
11
|
+
true
|
|
12
|
+
rescue Errno::ECONNREFUSED
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
metadata
CHANGED
|
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
|
5
5
|
segments:
|
|
6
6
|
- 0
|
|
7
7
|
- 1
|
|
8
|
-
-
|
|
9
|
-
version: 0.1.
|
|
8
|
+
- 4
|
|
9
|
+
version: 0.1.4
|
|
10
10
|
platform: ruby
|
|
11
11
|
authors:
|
|
12
12
|
- Sung Pae
|
|
@@ -14,7 +14,7 @@ autorequire:
|
|
|
14
14
|
bindir: bin
|
|
15
15
|
cert_chain: []
|
|
16
16
|
|
|
17
|
-
date: 2011-02-
|
|
17
|
+
date: 2011-02-17 00:00:00 -06:00
|
|
18
18
|
default_executable:
|
|
19
19
|
dependencies:
|
|
20
20
|
- !ruby/object:Gem::Dependency
|
|
@@ -86,8 +86,7 @@ files:
|
|
|
86
86
|
- test/editserver/command.test.rb
|
|
87
87
|
- test/editserver/editor.test.rb
|
|
88
88
|
- test/editserver/response.test.rb
|
|
89
|
-
- test/editserver/
|
|
90
|
-
- test/editserver/terminal/vim.test.rb
|
|
89
|
+
- test/editserver/socket-test.rb
|
|
91
90
|
- test/test-editor
|
|
92
91
|
has_rdoc: true
|
|
93
92
|
homepage: http://github.com/guns/editserver
|
|
@@ -126,6 +125,5 @@ test_files:
|
|
|
126
125
|
- test/editserver/command.test.rb
|
|
127
126
|
- test/editserver/editor.test.rb
|
|
128
127
|
- test/editserver/response.test.rb
|
|
129
|
-
- test/editserver/
|
|
130
|
-
- test/editserver/terminal/vim.test.rb
|
|
128
|
+
- test/editserver/socket-test.rb
|
|
131
129
|
- test/test-editor
|