vorhees 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :gemcutter
2
+
3
+ gem 'rspec'
4
+ gem 'eventmachine'
5
+ gem 'json_pure', :as => 'json'
6
+ if RUBY_VERSION < '1.9'
7
+ gem 'SystemTimer', :as => 'system_timer'
8
+ end
data/Manifest ADDED
@@ -0,0 +1,11 @@
1
+ Gemfile
2
+ Manifest
3
+ README
4
+ Rakefile
5
+ lib/vorhees.rb
6
+ lib/vorhees/client.rb
7
+ lib/vorhees/matchers.rb
8
+ spec/client_spec.rb
9
+ spec/spec.opts
10
+ spec/spec_helper.rb
11
+ spec/usage_spec.rb
data/README ADDED
@@ -0,0 +1,24 @@
1
+ http://github.com/davidlee/vorhees
2
+
3
+ Vorhees is a simple JSON client and accompanying rspec matcher.
4
+
5
+ It's designed to aid the authors of simple JSON socket protocols & servers.
6
+
7
+ It's opinionated, in that it expects you'll use a key (the default is
8
+ 'command') to differentiate types of message; it assumes that the commands are
9
+ uppercase; and that you're using rspec -- other than that it should be
10
+ reasonably universal.
11
+
12
+ As an example, the following will assert that a message was received within 2
13
+ seconds, with the values {"command":"HELLO", "recipient":"world"}. Additional
14
+ values are allowed (i.e., a "body" field wouldn't cause the spec to fail):
15
+
16
+ @client = Vorhees::Client.new(:host => 'localhost', :port => 1234)
17
+ @client.should receive(:hello, :timeout => 2.0) { |msg|
18
+ msg['recipient].should == 'world'
19
+ }
20
+
21
+ If you're interested, let me know and I'll try to add spec coverage for some
22
+ of the other (currently undocumented) features.
23
+
24
+ Provided under the MIT License.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'spec/rake/spectask'
6
+ require 'fileutils'
7
+
8
+ begin
9
+ require 'echoe'
10
+ Echoe.new('vorhees', '0.0.2') do |p|
11
+ p.description = "An opinionated JSON socket server client and matchers"
12
+ p.url = "http://github.com/davidlee/vorhees"
13
+ p.author = "David Lee"
14
+ p.email = "david at davelee.com.au"
15
+ p.ignore_pattern = ["tmp/*", "script/*"]
16
+ p.development_dependencies = []
17
+ end
18
+ rescue LoadError
19
+ end
20
+
21
+ begin
22
+ require 'cucumber/rake/task'
23
+ rescue LoadError
24
+ puts "cucumber is not installed."
25
+ end
26
+
27
+ require '.bundle/environment'
28
+ Bundler.setup()
29
+
30
+ if defined? Cucumber
31
+ namespace :features do
32
+ Cucumber::Rake::Task.new(:all) do |t|
33
+ t.cucumber_opts = %w{--format pretty --color}
34
+ end
35
+ end
36
+ task :features => 'features:all'
37
+ end
38
+
39
+ namespace :spec do
40
+ desc "Run the code examples in spec/*"
41
+ Spec::Rake::SpecTask.new(:all) do |t|
42
+ t.spec_opts = ['-c', '--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
43
+ t.spec_files = FileList["spec/**/*_spec.rb"]
44
+ end
45
+
46
+ Dir['spec/**'].select {|f| File.directory? f }.map {|f| File.split(f).last }.each do |folder|
47
+ desc "Run the code examples in spec/#{folder}"
48
+ Spec::Rake::SpecTask.new(folder.to_sym) do |t|
49
+ t.spec_opts = ['-c', '--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
50
+ t.spec_files = FileList["spec/#{folder}/*_spec.rb"]
51
+ end
52
+ end
53
+ end
54
+
55
+ task :spec => "spec:all"
56
+ task :default => :spec
data/lib/vorhees.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'vorhees/client'
2
+ require 'vorhees/matchers'
@@ -0,0 +1,243 @@
1
+ require 'socket'
2
+ require 'json'
3
+
4
+ unless Object.const_defined?('ActiveSupport')
5
+ class Hash
6
+ # Return a new hash with all keys converted to symbols.
7
+ def symbolize_keys
8
+ inject({}) do |options, (key, value)|
9
+ options[(key.to_sym rescue key) || key] = value
10
+ options
11
+ end
12
+ end
13
+
14
+ # Destructively convert all keys to symbols.
15
+ def symbolize_keys!
16
+ self.replace(self.symbolize_keys)
17
+ end
18
+ end
19
+ end
20
+
21
+ module Vorhees
22
+ class Client
23
+ attr_accessor :socket, :buffer, :sent, :received, :options, :env
24
+
25
+ if RUBY_VERSION < '1.9'
26
+ require 'system_timer'
27
+ else
28
+ SystemTimer = Timeout
29
+ end
30
+
31
+
32
+ GOT_NOTHING = nil
33
+ GOT_DATA = 1
34
+ GOT_MESSAGE = 2
35
+
36
+ #cattr_accessor :defaults
37
+ def self.defaults
38
+ @@defaults
39
+ end
40
+
41
+ @@defaults = {
42
+ :timeout => 0.06,
43
+ :eof => "\n",
44
+ :key => 'command',
45
+ :host => 'localhost',
46
+ :port => 80,
47
+ :bufsize => 1024
48
+ }
49
+
50
+ def self.const_missing k
51
+ if k =~ /^DEFAULT_(.*)$/
52
+ @@defaults[$1.to_s.downcase.to_sym]
53
+ else super
54
+ end
55
+ end
56
+
57
+ def self.set_defaults(options={})
58
+ defaults.merge! options.symbolize_keys!
59
+ end
60
+
61
+ def initialize(options={})
62
+ @options = Client.defaults.merge(options.symbolize_keys!)
63
+ @socket = TCPSocket.new(options[:host], options[:port])
64
+ @env = {}
65
+ @buffer = ''
66
+ clear
67
+ end
68
+
69
+ def eof
70
+ options[:eof]
71
+ end
72
+
73
+ alias :messages :received
74
+
75
+ # client.sends 'ERROR', :message => 'INVALID_RECORD'
76
+ # => '{"command":"ERROR", "message":"INVALID_RECORD"}'
77
+ def sends *args
78
+ if args.last.is_a?(Hash)
79
+ send_message(*args)
80
+ else
81
+ begin
82
+ JSON.unparse(args.flatten.first)
83
+ send_data(*args)
84
+ rescue
85
+ send_message(*args)
86
+ end
87
+ end
88
+ end
89
+
90
+ def send_message *args
91
+ values = args.last.is_a?(Hash) ? args.pop : {}
92
+ values[options[:key]] = args.shift if args.first.is_a?(String)
93
+ send_json values
94
+ end
95
+
96
+ def send_json hash
97
+ send_data hash.to_json # JSON.unparse(hash)
98
+ end
99
+
100
+ def send_data(data)
101
+ data = data.chomp(options[:eof]) + eof
102
+ sent << data
103
+ socket.print data
104
+ socket.flush
105
+ end
106
+
107
+ def wait_for_responses(opts={})
108
+ wait_for opts do
109
+ if options[:exactly]
110
+ received.length == options[:exactly]
111
+ else
112
+ received.length >=(options[:at_least] || 1)
113
+ end
114
+ end
115
+ received
116
+ end
117
+
118
+ def wait_for_response opts={}
119
+ opts = options.merge(opts)
120
+ response = wait_for_responses opts
121
+ yield(response.first && response.first.parse) if block_given?
122
+ response.first
123
+ end
124
+ alias :response :wait_for_response
125
+
126
+ # FIXME use wait_for, clean this up
127
+ def discard_responses_until(value, opts={})
128
+ opts = options.merge(opts)
129
+ SystemTimer.timeout(opts[:timeout]) do
130
+ loop do
131
+ wait_for_response opts do |msg|
132
+ if msg && msg[Client::DEFAULT_KEY] == value
133
+ return msg
134
+ else
135
+ opts[:debug] ? p(received.shift) : received.shift
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ def wait_for opts={}, &block
143
+ opts = options.merge(opts)
144
+ assertion_failed = nil
145
+ test = lambda do
146
+ begin
147
+ yield
148
+ rescue Spec::Expectations::ExpectationNotMetError => e
149
+ assertion_failed = true
150
+ # if there's a background server running, now is a good time
151
+ # to let it do it's thing.
152
+ Thread.pass
153
+ retry
154
+ end
155
+ end
156
+ SystemTimer.timeout(opts[:timeout]) do
157
+ until test.call do
158
+ receive_data options
159
+ end
160
+ end
161
+ rescue Timeout::Error
162
+ ensure
163
+ # let the error be thrown one more time, this time it won't be caught
164
+ yield if assertion_failed
165
+ end
166
+
167
+ def consume_message
168
+ received.shift.parse rescue nil
169
+ end
170
+
171
+ def consume
172
+ v = received.parse
173
+ @received = [].extend MessageList
174
+ v
175
+ end
176
+
177
+ def clear
178
+ @sent = [].extend MessageList
179
+ @received = [].extend MessageList
180
+ # @buffer = ""
181
+ end
182
+
183
+ def connected?
184
+ !disconnected?
185
+ end
186
+
187
+ # for flash XMLSocket
188
+ def request_policy_file
189
+ @socket.print "<policy-file-request/>\0"
190
+ self
191
+ end
192
+
193
+ def disconnected?
194
+ wait_for :timeout => 0.1 do
195
+ begin
196
+ return socket && socket.eof?
197
+ rescue Errno::ECONNRESET
198
+ return true
199
+ end
200
+ end
201
+ return false
202
+ end
203
+
204
+ module MessageList
205
+ def parse
206
+ map { |json| JSON.parse json }
207
+ end
208
+ end
209
+
210
+ module MessageString
211
+ def parse
212
+ JSON.parse self
213
+ end
214
+ end
215
+
216
+ private
217
+
218
+ def receive_data opts={}
219
+ opts = options.merge(opts) # not really necessary here
220
+ start_time = Time.now
221
+ begin
222
+ data = socket.read_nonblock opts[:bufsize]
223
+ if data.match(opts[:eof] || '')
224
+ data, @buffer = (buffer + data).split(opts[:eof]), ''
225
+ data.each {|str| str.extend MessageString }
226
+ @received += data
227
+ @received.extend MessageList
228
+ GOT_MESSAGE
229
+ else
230
+ @buffer += data
231
+ GOT_DATA
232
+ end
233
+ elapsed = (Time.now.to_f - start_time.to_f)
234
+ elapsed = (elapsed * 10000).round / 10000
235
+ rescue Errno::EAGAIN, EOFError
236
+ # yield to background thread if there is one
237
+ Thread.pass
238
+ GOT_NOTHING
239
+ end
240
+ end
241
+
242
+ end
243
+ end
@@ -0,0 +1,78 @@
1
+ module Vorhees
2
+ module Matchers
3
+
4
+ def receive_nothing(options={})
5
+ Spec::Matchers::Matcher.new :receive_nothing do
6
+ match do |client|
7
+ client.clear
8
+ if client.received.empty?
9
+ client.wait_for_responses options
10
+ end
11
+ client.received.empty?
12
+ end
13
+
14
+ failure_message_for_should do |client|
15
+ "Expected nothing but received #{client.received}"
16
+ end
17
+ end
18
+ end
19
+
20
+ def receive(expected=nil, options={})
21
+ Spec::Matchers::Matcher.new :receive, expected do |_expected_|
22
+ raw = nil
23
+ msg = nil
24
+ err = nil
25
+
26
+ match do |client|
27
+ if client.received.empty?
28
+ client.wait_for_responses options
29
+ end
30
+ if expected == false && !block_given?
31
+ raw = client.received.shift
32
+ msg = raw.parse if raw
33
+ client.received.empty?
34
+ else
35
+ raw = client.received.shift || raise('No Message Received')
36
+ msg = raw.parse
37
+ if block_given?
38
+ begin
39
+ msg['command'].should == expected.to_s.upcase if expected
40
+ yield msg # stick expectations in the block
41
+ true
42
+ rescue Spec::Expectations::ExpectationNotMetError => e
43
+ err = e
44
+ false
45
+ end
46
+ else
47
+ case expected
48
+ when '?'
49
+ $stderr.puts ' ?? -----> ' + msg.inspect
50
+ true
51
+ when String
52
+ msg == JSON.parse(expected)
53
+ when Symbol
54
+ msg['command'] == expected.to_s.upcase
55
+ else
56
+ msg == expected
57
+ end
58
+ end
59
+
60
+ end
61
+ end # match
62
+
63
+ failure_message_for_should do |actual|
64
+ if err
65
+ "#{err.inspect} \n\n-- #{raw}"
66
+ elsif expected == false
67
+ "Expected no message but received #{raw.inspect}"
68
+ elsif msg.nil?
69
+ "Expected a message, but got nothing."
70
+ else
71
+ "Expected #{expected.inspect} but received #{msg.inspect} --> #{raw}"
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,84 @@
1
+ require File.join(File.dirname(__FILE__), './spec_helper')
2
+
3
+ describe Vorhees::Client do
4
+ Client = Vorhees::Client
5
+
6
+ before :each do
7
+ TCPSocket.should_receive(:new).any_number_of_times
8
+ end
9
+
10
+ describe 'defaults' do
11
+ it 'should be the default options for new instances' do
12
+ c = Vorhees::Client.new
13
+ c.options.should == Vorhees::Client.defaults
14
+ end
15
+
16
+ it 'should be overridden by any supplied options' do
17
+ c = Vorhees::Client.new 'timeout' => 2, :port => 8080
18
+ c.options[:timeout].should == 2
19
+ c.options[:port].should == 8080
20
+ end
21
+ end
22
+
23
+ describe 'set_defaults' do
24
+ it 'should change the defaults for new instances' do
25
+ Vorhees::Client.set_defaults 'port' => 8080, :eof => "\000"
26
+ Vorhees::Client.defaults[:port].should == 8080
27
+ Vorhees::Client.defaults[:eof].should == "\000"
28
+ c = Vorhees::Client.new
29
+ c.options[:eof].should == "\000"
30
+ c.options[:port].should == 8080
31
+ end
32
+
33
+ it 'should not modify the options of extant instances' do
34
+ c = Vorhees::Client.new
35
+ lambda {
36
+ Vorhees::Client.set_defaults :eof => "\000"
37
+ }.should_not change(c, :options)
38
+ end
39
+ end
40
+
41
+ describe '#env' do
42
+ it 'should be a user-assignable hash' do
43
+ c = Vorhees::Client.new
44
+ c.env.should == {}
45
+ c.env[:connection_id] = 'foo'
46
+ c.env[:connection_id].should == 'foo'
47
+ end
48
+ end
49
+
50
+
51
+ describe 'a new client' do
52
+ describe '#buffer' do
53
+ it 'should be an empty string' do
54
+ Client.new.buffer.should == ''
55
+ end
56
+ end
57
+
58
+ describe '#sent' do
59
+ it 'should be empty' do
60
+ Client.new.sent.should == []
61
+ end
62
+ end
63
+
64
+ describe '#received' do
65
+ it 'should be empty' do
66
+ Client.new.received.should == []
67
+ end
68
+ end
69
+
70
+ describe '#socket' do
71
+ it 'should return the raw socket'
72
+ end
73
+
74
+ describe '#options' do
75
+ it 'should be the options merged with defaults' do
76
+ o = {:eof => 'XXX'}
77
+ c = Client.new(o)
78
+ c.options[:eof].should == "XXX"
79
+ c.options[:timeout].should == Client.defaults[:timeout]
80
+ end
81
+ end
82
+ end
83
+
84
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --format
2
+ nested
3
+ --color
4
+ --loadby
5
+ mtime
6
+ --backtrace
@@ -0,0 +1,93 @@
1
+ # -*- coding: utf-8 -*-
2
+ $:.unshift File.dirname(__FILE__)
3
+
4
+ require '.bundle/environment'
5
+ Bundler.setup()
6
+
7
+ require 'pp'
8
+ # require 'spec'
9
+ require 'lib/vorhees/client'
10
+ require 'lib/vorhees/matchers'
11
+ require 'eventmachine'
12
+
13
+ class MockSocket
14
+ attr_accessor :received, :sent
15
+
16
+ def initialize
17
+ @received = []
18
+ @sent = []
19
+ end
20
+
21
+ def print data
22
+ sent << data
23
+ end
24
+
25
+ def flush
26
+ # noop
27
+ end
28
+ end
29
+
30
+ # simple EM json server
31
+ class TestServer < EventMachine::Connection
32
+ EOF= "\n"
33
+
34
+ def post_init
35
+ @buffer = ''
36
+ end
37
+
38
+ # ensure a null byte at EOF
39
+ def send_data(data)
40
+ unless data[-1] == 0
41
+ data << EOF
42
+ end
43
+ super data
44
+ Thread.pass
45
+ end
46
+
47
+ def receive_data(data)
48
+ @buffer << data
49
+ @buffer = process_whole_messages(@buffer)
50
+ end
51
+
52
+ # process any whole messages in the buffer,
53
+ # and return the new contents of the buffer
54
+ def process_whole_messages(data)
55
+ return data if data !~ /#{EOF}/ # only process if data contains a \0 char
56
+ messages = data.split(EOF)
57
+ if data =~ /#{EOF}$/
58
+ data = ''
59
+ else
60
+ # remove the last message from the list (because it is incomplete) before processing
61
+ data = messages.pop
62
+ end
63
+ messages.each {|message| process_message(message.strip)}
64
+ return data
65
+ end
66
+
67
+ def process_message(ln)
68
+ request = nil
69
+ begin
70
+ request = JSON.parse(ln)
71
+ rescue JSON::ParserError => e
72
+ error ["CorruptJSON", ln]
73
+ send_error 'corrupt_JSON'
74
+ raise ['CorruptJSON', ln].inspect
75
+ end
76
+ dispatch request
77
+ end
78
+
79
+ def dispatch(request)
80
+ # usually this would be a case on request['command']
81
+ # in this case just delay delivery if the request contains
82
+ # 'delay' => sec
83
+ delay = request['delay'].to_f
84
+ if delay > 0
85
+ # Ha, looks like EM::Timer doesn't allow floats in 1.8.7 ?
86
+ EM::Timer.new(delay) do
87
+ send_data request.to_json + EOF
88
+ end
89
+ else
90
+ send_data request.to_json + EOF
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,165 @@
1
+ require File.join(File.dirname(__FILE__), './spec_helper')
2
+
3
+ TEST_SERVER_PORT = 4001
4
+ @@em = nil
5
+
6
+ def with_server options={}, &bl
7
+ Thread.abort_on_exception = true
8
+ @@em ||= Thread.fork do
9
+ EM.run do
10
+ EM.start_server('localhost', TEST_SERVER_PORT, TestServer)
11
+ end
12
+ exit
13
+ end
14
+ if block_given?
15
+ yield
16
+ end
17
+ end
18
+
19
+ describe Vorhees::Client do
20
+ include Vorhees::Matchers
21
+ Client = Vorhees::Client
22
+
23
+ context 'mocked socket' do
24
+ before :each do
25
+ @socket = MockSocket.new
26
+ TCPSocket.should_receive(:new).and_return(@socket)
27
+ @client = Client.new
28
+ end
29
+
30
+
31
+ describe '#send_data' do
32
+ it 'should print a string directly to the socket with the EOF' do
33
+ @client.options[:eof].should == "\n"
34
+ str = '{"msg": "HELLO"}'
35
+ @client.send_data str
36
+ @socket.sent.should == [str + "\n"]
37
+ end
38
+
39
+ it 'does not append an extra EOF' do
40
+ @client.options[:eof].should == "\n"
41
+ str = '{"msg": "HELLO"}' + "\n"
42
+ @client.send_data str
43
+ @socket.sent.should == [str]
44
+ end
45
+ end
46
+
47
+ describe '#sends' do
48
+ context 'given a hash' do
49
+ it 'sends the hash as JSON with the EOF' do
50
+ data = {'command' => 'HELLO', 'payload' => '0xfff'}
51
+ @client.sends data
52
+ @socket.sent.length.should == 1
53
+ JSON.parse(@socket.sent.first).should == data
54
+ end
55
+
56
+ end
57
+
58
+ context 'given a symbol' do
59
+ it 'sends the uppercased symbol as the default key' do
60
+ @client.options[:key].should == 'command'
61
+ @client.sends :foo
62
+ @socket.sent.should == [JSON.unparse('command' => 'FOO') + @client.eof]
63
+ end
64
+ end
65
+
66
+ context 'given a string' do
67
+ it 'sends a JSON pair of the default key and the string as the value' do
68
+ @client.options[:key].should == 'command'
69
+ @client.sends 'FOO'
70
+ @socket.sent.should == [JSON.unparse('command' => 'FOO') + @client.eof]
71
+ end
72
+
73
+ it 'appends any additional values' do
74
+ @client.sends 'ERROR', :message => 'NOT_FOUND'
75
+ @client.options[:key].should == 'command'
76
+ @socket.sent.length.should == 1
77
+ JSON.parse(@socket.sent.first).should == {'command' => 'ERROR', 'message' => 'NOT_FOUND'}
78
+ end
79
+
80
+ it 'appends an EOF' do
81
+ data = {'command' => 'HELLO', 'payload' => '0xfff'}
82
+ @client.sends data
83
+ @client.sent.first[-1,1].should == @client.eof
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'should receive matcher (running against an echo server)' do
90
+ it 'sanity check' do
91
+ with_server do
92
+ @client = Client.new(:host => 'localhost', :port => TEST_SERVER_PORT)
93
+ @client.sends 'HELLO'
94
+ @client.should receive('{"command":"HELLO"}')
95
+ end
96
+ end
97
+
98
+ it 'waits for the specified duration' do
99
+ with_server do
100
+ @client = Client.new(:host => 'localhost', :port => TEST_SERVER_PORT)
101
+ @client.sends 'HELLO', :delay => 0.1
102
+ @client.should receive(:hello, :timeout => 0.3)
103
+ end
104
+ end
105
+
106
+ it 'throws an error if it does not receive a message in the timeout' do
107
+ with_server do
108
+ # sanity test:
109
+ lambda { SystemTimer.timeout(0.1) { sleep 1 } }.should raise_error
110
+
111
+ @client = Client.new(:host => 'localhost', :port => TEST_SERVER_PORT)
112
+ @client.sends 'HELLO', :delay => 1
113
+ lambda {
114
+ @client.should receive(:hello, :timeout => 0.1)
115
+ }.should raise_error(RuntimeError)
116
+ end
117
+ end
118
+
119
+ it 'raises if the wrong command (or custom :key value) is returned' do
120
+ with_server do
121
+ @client = Client.new(:host => 'localhost', :port => TEST_SERVER_PORT)
122
+ @client.sends 'HELLO', :delay => 0.2
123
+
124
+ lambda {
125
+ @client.should receive(:goodbye)
126
+ }.should raise_error #(Spec::Expectations::ExpectationNotMetError, RuntimeError)
127
+ end
128
+ end
129
+
130
+ it 'raises if any expectations in the block fail' do
131
+ with_server do
132
+ @client = Client.new(:host => 'localhost', :port => TEST_SERVER_PORT)
133
+ @client.sends 'HELLO'
134
+ lambda {
135
+ @client.should receive(:hello) {|msg| msg['missing'].should_not be_nil }
136
+ }.should raise_error(Spec::Expectations::ExpectationNotMetError)
137
+ end
138
+ end
139
+
140
+ it 'yields the message to the block' do
141
+ with_server do
142
+ @client = Client.new(:host => 'localhost', :port => TEST_SERVER_PORT)
143
+ @client.sends 'HELLO', :recipient => 'world'
144
+ recipient = nil
145
+ @client.should receive(:hello) {|msg| recipient = msg['recipient'] }
146
+ recipient.should == 'world'
147
+ end
148
+ end
149
+
150
+ it 'prints the message given should receive("?")' do
151
+ # ok, this was probably going overboard ...
152
+ require 'stringio'
153
+ with_server do
154
+ @client = Client.new(:host => 'localhost', :port => TEST_SERVER_PORT)
155
+ @client.sends 'HELLO'
156
+ recipient = nil
157
+ stderr, $stderr = $stderr, StringIO.new('','w+')
158
+ @client.should receive('?')
159
+ stderr, $stderr = $stderr, stderr
160
+ stderr.rewind
161
+ stderr.read.gsub(/^.*\{|\}.*$/, '').should == '"command"=>"HELLO"' + "\n"
162
+ end
163
+ end
164
+ end
165
+ end
data/vorhees.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{vorhees}
5
+ s.version = "0.0.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["David Lee"]
9
+ s.date = %q{2010-03-15}
10
+ s.description = %q{An opinionated JSON socket server client and matchers}
11
+ s.email = %q{david at davelee.com.au}
12
+ s.extra_rdoc_files = ["README", "lib/vorhees.rb", "lib/vorhees/client.rb", "lib/vorhees/matchers.rb"]
13
+ s.files = ["Gemfile", "Manifest", "README", "Rakefile", "lib/vorhees.rb", "lib/vorhees/client.rb", "lib/vorhees/matchers.rb", "spec/client_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/usage_spec.rb", "vorhees.gemspec"]
14
+ s.homepage = %q{http://github.com/davidlee/vorhees}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Vorhees", "--main", "README"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{vorhees}
18
+ s.rubygems_version = %q{1.3.6}
19
+ s.summary = %q{An opinionated JSON socket server client and matchers}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
+ else
27
+ end
28
+ else
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vorhees
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - David Lee
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-15 00:00:00 +11:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: An opinionated JSON socket server client and matchers
22
+ email: david at davelee.com.au
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README
29
+ - lib/vorhees.rb
30
+ - lib/vorhees/client.rb
31
+ - lib/vorhees/matchers.rb
32
+ files:
33
+ - Gemfile
34
+ - Manifest
35
+ - README
36
+ - Rakefile
37
+ - lib/vorhees.rb
38
+ - lib/vorhees/client.rb
39
+ - lib/vorhees/matchers.rb
40
+ - spec/client_spec.rb
41
+ - spec/spec.opts
42
+ - spec/spec_helper.rb
43
+ - spec/usage_spec.rb
44
+ - vorhees.gemspec
45
+ has_rdoc: true
46
+ homepage: http://github.com/davidlee/vorhees
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --line-numbers
52
+ - --inline-source
53
+ - --title
54
+ - Vorhees
55
+ - --main
56
+ - README
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 1
72
+ - 2
73
+ version: "1.2"
74
+ requirements: []
75
+
76
+ rubyforge_project: vorhees
77
+ rubygems_version: 1.3.6
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: An opinionated JSON socket server client and matchers
81
+ test_files: []
82
+