gopher2000 0.1.0
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 +4 -0
- data/.rvmrc +1 -0
- data/Gemfile +27 -0
- data/LICENSE.txt +14 -0
- data/README.markdown +344 -0
- data/Rakefile +38 -0
- data/bin/gopher2000 +51 -0
- data/examples/default_route.rb +22 -0
- data/examples/nyan.rb +62 -0
- data/examples/simple.rb +147 -0
- data/examples/twitter.rb +61 -0
- data/examples/weather.rb +69 -0
- data/gopher2000.gemspec +35 -0
- data/lib/gopher2000/base.rb +552 -0
- data/lib/gopher2000/dispatcher.rb +81 -0
- data/lib/gopher2000/dsl.rb +128 -0
- data/lib/gopher2000/errors.rb +14 -0
- data/lib/gopher2000/handlers/base_handler.rb +18 -0
- data/lib/gopher2000/handlers/directory_handler.rb +125 -0
- data/lib/gopher2000/rendering/abstract_renderer.rb +10 -0
- data/lib/gopher2000/rendering/base.rb +174 -0
- data/lib/gopher2000/rendering/menu.rb +129 -0
- data/lib/gopher2000/rendering/text.rb +10 -0
- data/lib/gopher2000/request.rb +21 -0
- data/lib/gopher2000/response.rb +25 -0
- data/lib/gopher2000/server.rb +85 -0
- data/lib/gopher2000/version.rb +4 -0
- data/lib/gopher2000.rb +33 -0
- data/scripts/god.rb +8 -0
- data/spec/application_spec.rb +54 -0
- data/spec/dispatching_spec.rb +144 -0
- data/spec/dsl_spec.rb +116 -0
- data/spec/gopher_spec.rb +1 -0
- data/spec/handlers/directory_handler_spec.rb +116 -0
- data/spec/helpers_spec.rb +16 -0
- data/spec/rendering/base_spec.rb +59 -0
- data/spec/rendering/menu_spec.rb +109 -0
- data/spec/rendering_spec.rb +84 -0
- data/spec/request_spec.rb +30 -0
- data/spec/response_spec.rb +33 -0
- data/spec/routing_spec.rb +92 -0
- data/spec/sandbox/old/socks.txt +0 -0
- data/spec/sandbox/socks.txt +0 -0
- data/spec/server_spec.rb +127 -0
- data/spec/spec_helper.rb +52 -0
- data/specs.watchr +60 -0
- metadata +211 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/../spec_helper')
|
2
|
+
|
3
|
+
describe Gopher::Rendering::Menu do
|
4
|
+
before(:each) do
|
5
|
+
@app = Gopher::Application.new
|
6
|
+
@app.reset!
|
7
|
+
@app.config[:host] = "host"
|
8
|
+
@app.config[:port] = 1234
|
9
|
+
|
10
|
+
@ctx = Gopher::Rendering::Menu.new(@app)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should add text as a gopher line' do
|
14
|
+
@ctx.text("gopher forever")
|
15
|
+
@ctx.result.should == "igopher forever\tnull\t(FALSE)\t0\r\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "sanitize_text" do
|
19
|
+
it "should remove extra whitespace from end of line" do
|
20
|
+
@ctx.sanitize_text("x ").should == "x"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should convert tabs to spaces" do
|
24
|
+
@ctx.sanitize_text("x\tx").should == "x x"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should remove newlines" do
|
28
|
+
@ctx.sanitize_text("x\nx").should == "xx"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "line" do
|
33
|
+
it "should work" do
|
34
|
+
@ctx.line("type", "text", "selector", "host", "port").should == "typetext\tselector\thost\tport\r\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should use application host/port as defaults" do
|
38
|
+
@ctx.line("type", "text", "selector").should == "typetext\tselector\thost\t1234\r\n"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "error" do
|
43
|
+
it "should call text with right selector" do
|
44
|
+
@ctx.should_receive(:text).with("foo", '3')
|
45
|
+
@ctx.error("foo")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "directory" do
|
50
|
+
it "should call link with right selector" do
|
51
|
+
@ctx.should_receive(:line).with("1", "foo", "/bar/foo", nil, nil)
|
52
|
+
@ctx.directory("foo", "/bar/foo")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "link" do
|
57
|
+
it "should get type with determine_type" do
|
58
|
+
@ctx.should_receive(:determine_type).with("foo.txt").and_return("A")
|
59
|
+
@ctx.link("FILE", "foo.txt").should == "AFILE\tfoo.txt\thost\t1234\r\n"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "search" do
|
64
|
+
it "should output link type/text" do
|
65
|
+
@ctx.search("FIND", "search").should == "7FIND\tsearch\thost\t1234\r\n"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "menu" do
|
70
|
+
it "should output link type/text" do
|
71
|
+
@ctx.menu("MENU ITEM", "item").should == "1MENU ITEM\titem\thost\t1234\r\n"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "br" do
|
76
|
+
it "should generate an empty text line" do
|
77
|
+
@ctx.should_receive(:text).with("i", "")
|
78
|
+
@ctx.br
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should call #text multiple times" do
|
82
|
+
@ctx.should_receive(:text).twice.with("i", "")
|
83
|
+
@ctx.br(2)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should output an empty menu item" do
|
87
|
+
@ctx.br
|
88
|
+
@ctx.result.should == "i\tnull\t(FALSE)\t0\r\n"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "determine_type" do
|
93
|
+
{
|
94
|
+
"foo.zip" => '5',
|
95
|
+
"foo.gz" => '5',
|
96
|
+
"foo.bz2" => '5',
|
97
|
+
"foo.gif" => 'g',
|
98
|
+
"foo.jpg" => 'I',
|
99
|
+
"foo.png" => 'I',
|
100
|
+
"foo.mp3" => 's',
|
101
|
+
"foo.wav" => 's',
|
102
|
+
"foo.random-file" => "0"
|
103
|
+
}.each do |file, expected|
|
104
|
+
it "should have right selector for #{file}" do
|
105
|
+
@ctx.determine_type(file).should == expected
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
class MockServer < Gopher::Application
|
4
|
+
attr_accessor :menus, :text_templates, :params, :request
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@menus = {}
|
8
|
+
@text_templates = {}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
describe Gopher::Application do
|
14
|
+
before(:each) do
|
15
|
+
@s = MockServer.new
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "find_template" do
|
19
|
+
it "should check in menus" do
|
20
|
+
@s.menus['foo'] = "bar"
|
21
|
+
@s.find_template('foo').should == ["bar", Gopher::Rendering::Menu]
|
22
|
+
end
|
23
|
+
it "should check in text_templates" do
|
24
|
+
@s.text_templates['foo'] = "bar"
|
25
|
+
@s.find_template('foo').should == ["bar", Gopher::Rendering::Text]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "render" do
|
30
|
+
it "should raise error if no such template" do
|
31
|
+
expect{@s.render('xyzzy')}.to raise_error(Gopher::TemplateNotFound)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "has access to params obj" do
|
35
|
+
@s.params = "xyz"
|
36
|
+
@s.menu :foo do
|
37
|
+
@params
|
38
|
+
end
|
39
|
+
|
40
|
+
@s.render(:foo).should == "xyz"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "has access to request obj" do
|
44
|
+
@s.request = "abc"
|
45
|
+
@s.menu :foo do
|
46
|
+
@request
|
47
|
+
end
|
48
|
+
|
49
|
+
@s.render(:foo).should == "abc"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "rendering text access to request obj" do
|
53
|
+
@s.request = "abc"
|
54
|
+
@s.text :foo do
|
55
|
+
@request
|
56
|
+
end
|
57
|
+
|
58
|
+
@s.render(:foo).should == "abc"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "not_found_template" do
|
63
|
+
before(:each) do
|
64
|
+
@s.reset!
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should use custom template if provided" do
|
68
|
+
@s.not_found do ; end
|
69
|
+
@s.not_found_template.should == :not_found
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should use default otherwise" do
|
73
|
+
@s.not_found_template.should == :'internal/not_found'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# describe "register_defaults" do
|
78
|
+
# it "should add to internal" do
|
79
|
+
# @s.find_template(:'internal/not_found').should be_nil
|
80
|
+
# @s.register_defaults
|
81
|
+
# @s.find_template(:'internal/not_found').should_not be_nil
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
describe Gopher::Request do
|
4
|
+
it 'should split raw request' do
|
5
|
+
request = Gopher::Request.new("foo\tbar")
|
6
|
+
request.selector.should == "foo"
|
7
|
+
request.input.should == "bar"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should be ok with just selector" do
|
11
|
+
request = Gopher::Request.new("foo")
|
12
|
+
request.selector.should == "foo"
|
13
|
+
request.input.should == nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should accept ip_address" do
|
17
|
+
request = Gopher::Request.new("foo", "bar")
|
18
|
+
request.ip_address.should == "bar"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "valid? == true for valid selectors" do
|
22
|
+
request = Gopher::Request.new("x" * 255, "bar")
|
23
|
+
request.valid?.should == true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "valid? == false for invalid selectors" do
|
27
|
+
request = Gopher::Request.new("x" * 256, "bar")
|
28
|
+
request.valid?.should == false
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
describe Gopher::Response do
|
5
|
+
before(:each) do
|
6
|
+
@response = Gopher::Response.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "gets size for string results" do
|
10
|
+
@response.body = "hi"
|
11
|
+
@response.size.should == 2
|
12
|
+
end
|
13
|
+
|
14
|
+
it "gets size for stringio results" do
|
15
|
+
@response.body = StringIO.new("12345")
|
16
|
+
@response.size.should == 5
|
17
|
+
end
|
18
|
+
|
19
|
+
it "defaults to 0 size for weird objects" do
|
20
|
+
@response.body = mock(Object)
|
21
|
+
@response.size.should == 0
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
it "gets size for file results" do
|
26
|
+
temp_file = Tempfile.new('result')
|
27
|
+
temp_file.write("1234567890")
|
28
|
+
temp_file.flush
|
29
|
+
|
30
|
+
@response.body = File.new(temp_file.path)
|
31
|
+
@response.size.should == 10
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
class MockServer < Gopher::Application
|
4
|
+
# attr_accessor :routes
|
5
|
+
# include Gopher::Routing
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Gopher::Application do
|
9
|
+
before(:each) do
|
10
|
+
@router = MockServer.new
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "default_route" do
|
14
|
+
it "should set route as default" do
|
15
|
+
@router.default_route do
|
16
|
+
"hi"
|
17
|
+
end
|
18
|
+
junk, block = @router.lookup("sfssfdfsfsd")
|
19
|
+
block.class.should eql(UnboundMethod)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "globify" do
|
24
|
+
it "should add glob if none yet" do
|
25
|
+
@router.globify("/foo").should == "/foo/?*"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be ok with trailing slashes" do
|
29
|
+
@router.globify("/foo/").should == "/foo/?*"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "shouldn't add glob if there is one already" do
|
33
|
+
@router.globify("/foo/*").should == "/foo/*"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "mount" do
|
38
|
+
before(:each) do
|
39
|
+
@h = mock(Gopher::Handlers::DirectoryHandler)
|
40
|
+
@h.should_receive(:application=).with(@router)
|
41
|
+
|
42
|
+
Gopher::Handlers::DirectoryHandler.should_receive(:new).with({:bar => :baz, :mount_point => "/foo"}).and_return(@h)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should work" do
|
46
|
+
@router.mount("/foo", :bar => :baz)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "compile" do
|
51
|
+
it "should generate a basic string for routes without keys" do
|
52
|
+
lookup, keys, block = @router.compile! "/foo" do; end
|
53
|
+
lookup.to_s.should == /^\/foo$/.to_s
|
54
|
+
keys.should == []
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with keys" do
|
58
|
+
it "should generate a lookup and keys for routes with keys" do
|
59
|
+
lookup, keys, block = @router.compile! "/foo/:bar" do; end
|
60
|
+
lookup.to_s.should == "(?-mix:^\\/foo\\/([^\\/?#]+)$)"
|
61
|
+
|
62
|
+
keys.should == ["bar"]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should match correctly" do
|
66
|
+
lookup, keys, block = @router.compile! "/foo/:bar" do; end
|
67
|
+
lookup.to_s.should == "(?-mix:^\\/foo\\/([^\\/?#]+)$)"
|
68
|
+
|
69
|
+
lookup.match("/foo/baz").should_not be_nil
|
70
|
+
lookup.match("/foo2/baz").should be_nil
|
71
|
+
lookup.match("/baz/foo/baz").should be_nil
|
72
|
+
lookup.match("/foo/baz/bar").should be_nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with splat" do
|
77
|
+
it "should work with splats" do
|
78
|
+
lookup, keys, block = @router.compile! "/foo/*" do; end
|
79
|
+
lookup.to_s.should == "(?-mix:^\\/foo\\/(.*?)$)"
|
80
|
+
keys.should == ["splat"]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should match correctly" do
|
84
|
+
lookup, keys, block = @router.compile! "/foo/*" do; end
|
85
|
+
|
86
|
+
lookup.match("/foo/baz/bar/bam").should_not be_nil
|
87
|
+
lookup.match("/foo2/baz").should be_nil
|
88
|
+
lookup.match("/baz/foo/baz").should be_nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
File without changes
|
File without changes
|
data/spec/server_spec.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
if ENV["WITH_SERVER_SPECS"].to_i == 1
|
5
|
+
|
6
|
+
class FakeApp < Gopher::Application
|
7
|
+
attr_accessor :fake_response
|
8
|
+
def dispatch(x)
|
9
|
+
@fake_response
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Gopher::Server do
|
14
|
+
before(:each) do
|
15
|
+
@application = FakeApp.new
|
16
|
+
@application.scripts = []
|
17
|
+
@application.reset!
|
18
|
+
|
19
|
+
@host = "0.0.0.0"
|
20
|
+
@port = 12345
|
21
|
+
|
22
|
+
@application.config[:host] = @host
|
23
|
+
@application.config[:port] = @port
|
24
|
+
|
25
|
+
@request = Gopher::Request.new("foo", "bar")
|
26
|
+
|
27
|
+
@response = Gopher::Response.new(@request)
|
28
|
+
@response.code = :success
|
29
|
+
@response.body = "hi"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should work in non-blocking mode" do
|
33
|
+
@application.fake_response = @response
|
34
|
+
@application.stub!(:non_blocking?).and_return(false)
|
35
|
+
|
36
|
+
::EM.run {
|
37
|
+
server = Gopher::Server.new(@application)
|
38
|
+
server.run!
|
39
|
+
|
40
|
+
# opens the socket client connection
|
41
|
+
socket = ::EM.connect(@host, @port, FakeSocketClient)
|
42
|
+
socket.send_data("123\n")
|
43
|
+
|
44
|
+
socket.onopen = lambda {
|
45
|
+
socket.data.last.chomp.should == "hi\r\n."
|
46
|
+
EM.stop
|
47
|
+
}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should handle Gopher::Response results" do
|
52
|
+
@application.fake_response = @response
|
53
|
+
|
54
|
+
::EM.run {
|
55
|
+
server = Gopher::Server.new(@application)
|
56
|
+
server.run!
|
57
|
+
|
58
|
+
# opens the socket client connection
|
59
|
+
socket = ::EM.connect(@host, @port, FakeSocketClient)
|
60
|
+
socket.send_data("123\n")
|
61
|
+
|
62
|
+
socket.onopen = lambda {
|
63
|
+
socket.data.last.chomp.should == "hi\r\n."
|
64
|
+
EM.stop
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should handle string results" do
|
70
|
+
@application.fake_response = @response
|
71
|
+
|
72
|
+
::EM.run {
|
73
|
+
server = Gopher::Server.new(@application)
|
74
|
+
server.run!
|
75
|
+
|
76
|
+
# opens the socket client connection
|
77
|
+
socket = ::EM.connect(@host, @port, FakeSocketClient)
|
78
|
+
socket.send_data("123\n")
|
79
|
+
|
80
|
+
socket.onopen = lambda {
|
81
|
+
socket.data.last.chomp.should == "hi\r\n."
|
82
|
+
EM.stop
|
83
|
+
}
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should handle File results" do
|
88
|
+
file = Tempfile.new('foo')
|
89
|
+
file.write("hi")
|
90
|
+
file.close
|
91
|
+
|
92
|
+
@application.fake_response = File.new(file)
|
93
|
+
|
94
|
+
::EM.run {
|
95
|
+
server = Gopher::Server.new(@application)
|
96
|
+
server.run!
|
97
|
+
|
98
|
+
# opens the socket client connection
|
99
|
+
socket = ::EM.connect(@host, @port, FakeSocketClient)
|
100
|
+
socket.send_data("123\n")
|
101
|
+
|
102
|
+
socket.onopen = lambda {
|
103
|
+
socket.data.last.chomp.should == "hi"
|
104
|
+
EM.stop
|
105
|
+
}
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should handle StringIO results" do
|
110
|
+
@application.fake_response = StringIO.new("hi")
|
111
|
+
|
112
|
+
::EM.run {
|
113
|
+
server = Gopher::Server.new(@application)
|
114
|
+
server.run!
|
115
|
+
|
116
|
+
# opens the socket client connection
|
117
|
+
socket = ::EM.connect(@host, @port, FakeSocketClient)
|
118
|
+
socket.send_data("123\n")
|
119
|
+
|
120
|
+
socket.onopen = lambda {
|
121
|
+
socket.data.last.chomp.should == "hi\r\n."
|
122
|
+
EM.stop
|
123
|
+
}
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
ENV['gopher_test'] = "1"
|
2
|
+
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start do
|
5
|
+
add_filter "/spec/"
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'bundler/setup'
|
9
|
+
Bundler.require
|
10
|
+
|
11
|
+
# Requires supporting files with custom matchers and macros, etc,
|
12
|
+
# in ./support/ and its subdirectories.
|
13
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
14
|
+
|
15
|
+
|
16
|
+
require 'eventmachine'
|
17
|
+
|
18
|
+
#
|
19
|
+
# http://www.rosskaff.com/2010/12/behavior-driven-event-driven-eventmachine-rspec/
|
20
|
+
#
|
21
|
+
class FakeSocketClient < EventMachine::Connection
|
22
|
+
|
23
|
+
attr_writer :onopen, :onclose, :onmessage
|
24
|
+
attr_reader :data
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
super
|
28
|
+
|
29
|
+
@state = :new
|
30
|
+
@data = []
|
31
|
+
end
|
32
|
+
|
33
|
+
def receive_data(data)
|
34
|
+
#puts "RECV: #{data}"
|
35
|
+
@data << data
|
36
|
+
if @state == :new
|
37
|
+
@onopen.call if @onopen
|
38
|
+
@state = :open
|
39
|
+
else
|
40
|
+
@onmessage.call(data) if @onmessage
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def unbind
|
45
|
+
@onclose.call if @onclose
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
class FakeSocketServer < FakeSocketClient
|
51
|
+
attr_accessor :application
|
52
|
+
end
|
data/specs.watchr
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# Run me with:
|
2
|
+
#
|
3
|
+
# $ watchr specs.watchr
|
4
|
+
|
5
|
+
# --------------------------------------------------
|
6
|
+
# Convenience Methods
|
7
|
+
# --------------------------------------------------
|
8
|
+
def all_spec_files
|
9
|
+
Dir['spec/**/*_spec.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_spec_matching(thing_to_match)
|
13
|
+
puts "run #{thing_to_match}"
|
14
|
+
matches = all_spec_files.grep(/#{thing_to_match}/i)
|
15
|
+
if matches.empty?
|
16
|
+
puts "Sorry, thanks for playing, but there were no matches for #{thing_to_match}"
|
17
|
+
else
|
18
|
+
run matches.join(' ')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(files_to_run)
|
23
|
+
puts("Running: #{files_to_run}")
|
24
|
+
system("clear;rspec -cfs #{files_to_run}")
|
25
|
+
no_int_for_you
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_all_specs
|
29
|
+
run(all_spec_files.join(' '))
|
30
|
+
end
|
31
|
+
|
32
|
+
# --------------------------------------------------
|
33
|
+
# Watchr Rules
|
34
|
+
# --------------------------------------------------
|
35
|
+
watch('^spec/(.*)_spec\.rb') { |m| run_spec_matching(m[1]) }
|
36
|
+
watch("^lib/gopher2000/(.*)\.rb") { |m| run_all_specs }
|
37
|
+
|
38
|
+
watch('^spec/spec_helper\.rb') { run_all_spec }
|
39
|
+
|
40
|
+
# --------------------------------------------------
|
41
|
+
# Signal Handling
|
42
|
+
# --------------------------------------------------
|
43
|
+
|
44
|
+
def no_int_for_you
|
45
|
+
@sent_an_int = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
Signal.trap 'INT' do
|
49
|
+
if @sent_an_int then
|
50
|
+
puts " A second INT? Ok, I get the message. Shutting down now."
|
51
|
+
exit
|
52
|
+
else
|
53
|
+
puts " Did you just send me an INT? Ugh. I'll quit for real if you do it again."
|
54
|
+
@sent_an_int = true
|
55
|
+
Kernel.sleep 1.5
|
56
|
+
run_all_specs
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
run_all_specs
|