vorhees 0.0.2

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/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
+