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,85 @@
|
|
1
|
+
module Gopher
|
2
|
+
|
3
|
+
#
|
4
|
+
# main class which will listen on a specified port, and pass requests to an Application class
|
5
|
+
#
|
6
|
+
class Server
|
7
|
+
attr_accessor :app
|
8
|
+
|
9
|
+
#
|
10
|
+
# constructor
|
11
|
+
# @param [Application] instance of Gopher::Application we want to run
|
12
|
+
#
|
13
|
+
def initialize(a)
|
14
|
+
@app = a
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# @return [String] name of the host specified in our config
|
19
|
+
#
|
20
|
+
def host
|
21
|
+
@app.config[:host] ||= '0.0.0.0'
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# @return [Integer] port specified in our config
|
26
|
+
#
|
27
|
+
def port
|
28
|
+
@app.config[:port] ||= 70
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# main app loop. called via at_exit block defined in DSL
|
33
|
+
#
|
34
|
+
def run!
|
35
|
+
EventMachine::run do
|
36
|
+
Signal.trap("INT") {
|
37
|
+
puts "It's a trap!"
|
38
|
+
EventMachine.stop
|
39
|
+
}
|
40
|
+
Signal.trap("TERM") {
|
41
|
+
puts "It's a trap!"
|
42
|
+
EventMachine.stop
|
43
|
+
}
|
44
|
+
|
45
|
+
EventMachine.kqueue = true if EventMachine.kqueue?
|
46
|
+
EventMachine.epoll = true if EventMachine.epoll?
|
47
|
+
|
48
|
+
|
49
|
+
STDERR.puts "start server at #{host} #{port}"
|
50
|
+
if @app.non_blocking?
|
51
|
+
STDERR.puts "Not blocking on requests"
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
EventMachine::start_server(host, port, Gopher::Dispatcher) do |conn|
|
56
|
+
#
|
57
|
+
# check if we should reload any scripts before moving along
|
58
|
+
#
|
59
|
+
@app.reload_stale
|
60
|
+
|
61
|
+
#
|
62
|
+
# roughly matching sinatra's style of duping the app to respond
|
63
|
+
# to requests, @see http://www.sinatrarb.com/intro#Request/Instance%20Scope
|
64
|
+
#
|
65
|
+
# this essentially means we have 'one instance per request'
|
66
|
+
#
|
67
|
+
conn.app = @app.dup
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
#
|
74
|
+
# don't try and parse arguments if someone already has done that
|
75
|
+
#
|
76
|
+
if ARGV.any? && ! defined?(OptionParser)
|
77
|
+
require 'optparse'
|
78
|
+
OptionParser.new { |op|
|
79
|
+
op.on('-p port', 'set the port (default is 70)') { |val| set :port, Integer(val) }
|
80
|
+
op.on('-o addr', 'set the host (default is 0.0.0.0)') { |val| set :bind, val }
|
81
|
+
op.on('-e env', 'set the environment (default is development)') { |val| set :environment, val.to_sym }
|
82
|
+
}.parse!(ARGV.dup)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/gopher2000.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'logging'
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
|
6
|
+
#
|
7
|
+
# Define everything needed to run a gopher server
|
8
|
+
#
|
9
|
+
module Gopher
|
10
|
+
require "gopher2000/version"
|
11
|
+
require "gopher2000/errors"
|
12
|
+
|
13
|
+
require 'gopher2000/rendering/abstract_renderer'
|
14
|
+
require 'gopher2000/rendering/base'
|
15
|
+
require 'gopher2000/rendering/text'
|
16
|
+
require 'gopher2000/rendering/menu'
|
17
|
+
|
18
|
+
require 'gopher2000/request'
|
19
|
+
require 'gopher2000/response'
|
20
|
+
|
21
|
+
require 'gopher2000/handlers/base_handler'
|
22
|
+
require 'gopher2000/handlers/directory_handler'
|
23
|
+
require 'gopher2000/base'
|
24
|
+
require 'gopher2000/server'
|
25
|
+
|
26
|
+
require 'gopher2000/dispatcher'
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# include Gopher DSL in the main object space
|
31
|
+
#
|
32
|
+
require 'gopher2000/dsl'
|
33
|
+
include Gopher::DSL
|
data/scripts/god.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
describe Gopher::Application do
|
5
|
+
before(:each) do
|
6
|
+
@app = Gopher::Application.new
|
7
|
+
@app.reset!
|
8
|
+
@app.scripts = []
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have default host/port' do
|
12
|
+
@app.host.should == "0.0.0.0"
|
13
|
+
@app.port.should == 70
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "should_reload?" do
|
17
|
+
it "is false if no scripts" do
|
18
|
+
@app.should_reload?.should == false
|
19
|
+
end
|
20
|
+
|
21
|
+
it "shouldn't do anything if last_reload not set" do
|
22
|
+
@app.last_reload.should be_nil
|
23
|
+
@app.scripts << "foo.rb"
|
24
|
+
@app.should_reload?.should == false
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should check script date" do
|
28
|
+
now = Time.now
|
29
|
+
Time.stub!(:now).and_return(now)
|
30
|
+
|
31
|
+
@app.last_reload = Time.now - 1000
|
32
|
+
@app.scripts << "foo.rb"
|
33
|
+
File.should_receive(:mtime).with("foo.rb").and_return(now)
|
34
|
+
|
35
|
+
@app.should_reload?.should == true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "reload_stale" do
|
40
|
+
it "should load script and update last_reload" do
|
41
|
+
now = Time.now
|
42
|
+
Time.stub!(:now).and_return(now)
|
43
|
+
|
44
|
+
@app.should_receive(:should_reload?).and_return(true)
|
45
|
+
|
46
|
+
@app.last_reload = Time.now - 1000
|
47
|
+
@app.scripts << "foo.rb"
|
48
|
+
@app.should_receive(:load).with("foo.rb")
|
49
|
+
@app.reload_stale
|
50
|
+
|
51
|
+
@app.last_reload.should == now
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
class MockApplication < Gopher::Application
|
4
|
+
attr_accessor :menus, :routes, :config, :scripts, :last_reload
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@routes = []
|
8
|
+
@menus = {}
|
9
|
+
@scripts ||= []
|
10
|
+
@config = {}
|
11
|
+
|
12
|
+
register_defaults
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe Gopher::Application do
|
17
|
+
before(:each) do
|
18
|
+
@server = MockApplication.new
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "lookup" do
|
22
|
+
it "should work with simple route" do
|
23
|
+
@server.route '/about' do; end
|
24
|
+
@request = Gopher::Request.new("/about")
|
25
|
+
|
26
|
+
keys, block = @server.lookup(@request.selector)
|
27
|
+
keys.should == {}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should translate path" do
|
31
|
+
@server.route '/about/:foo/:bar' do; end
|
32
|
+
@request = Gopher::Request.new("/about/x/y")
|
33
|
+
|
34
|
+
keys, block = @server.lookup(@request.selector)
|
35
|
+
keys.should == {:foo => 'x', :bar => 'y'}
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return default route if no other route found, and default is defined" do
|
39
|
+
@server.default_route do
|
40
|
+
"DEFAULT ROUTE"
|
41
|
+
end
|
42
|
+
@request = Gopher::Request.new("/about/x/y")
|
43
|
+
@response = @server.dispatch(@request)
|
44
|
+
@response.body.should == "DEFAULT ROUTE"
|
45
|
+
@response.code.should == :success
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should respond with error if no route found" do
|
49
|
+
@server.route '/about/:foo/:bar' do; end
|
50
|
+
@request = Gopher::Request.new("/junk/x/y")
|
51
|
+
|
52
|
+
@response = @server.dispatch(@request)
|
53
|
+
@response.code.should == :missing
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should respond with error if invalid request" do
|
57
|
+
@server.route '/about/:foo/:bar' do; end
|
58
|
+
@request = Gopher::Request.new("x" * 256)
|
59
|
+
|
60
|
+
@response = @server.dispatch(@request)
|
61
|
+
@response.code.should == :error
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should respond with error if there's an exception" do
|
65
|
+
@server.route '/x' do; raise Exception; end
|
66
|
+
@request = Gopher::Request.new("/x")
|
67
|
+
|
68
|
+
@response = @server.dispatch(@request)
|
69
|
+
@response.code.should == :error
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "dispatch" do
|
74
|
+
before(:each) do
|
75
|
+
#@server.should_receive(:lookup).and_return({})
|
76
|
+
@server.route '/about' do
|
77
|
+
'GOPHERTRON'
|
78
|
+
end
|
79
|
+
|
80
|
+
@request = Gopher::Request.new("/about")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should run the block" do
|
84
|
+
@response = @server.dispatch(@request)
|
85
|
+
@response.body.should == "GOPHERTRON"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "dispatch, with params" do
|
90
|
+
before(:each) do
|
91
|
+
@server.route '/about/:x/:y' do
|
92
|
+
params.to_a.join("/")
|
93
|
+
end
|
94
|
+
|
95
|
+
@request = Gopher::Request.new("/about/a/b")
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should use incoming params" do
|
99
|
+
@response = @server.dispatch(@request)
|
100
|
+
@response.body.should == "x/a/y/b"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "dispatch to mount" do
|
105
|
+
before(:each) do
|
106
|
+
@h = mock(Gopher::Handlers::DirectoryHandler)
|
107
|
+
@h.should_receive(:application=).with(@server)
|
108
|
+
Gopher::Handlers::DirectoryHandler.should_receive(:new).with({:bar => :baz, :mount_point => "/foo"}).and_return(@h)
|
109
|
+
|
110
|
+
@server.mount "/foo", :bar => :baz
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should work for root path" do
|
114
|
+
@request = Gopher::Request.new("/foo")
|
115
|
+
@h.should_receive(:call).with({:splat => ""}, @request)
|
116
|
+
|
117
|
+
@response = @server.dispatch(@request)
|
118
|
+
@response.code.should == :success
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should work for subdir" do
|
122
|
+
@request = Gopher::Request.new("/foo/bar")
|
123
|
+
@h.should_receive(:call).with({:splat => "bar"}, @request)
|
124
|
+
|
125
|
+
@response = @server.dispatch(@request)
|
126
|
+
@response.code.should == :success
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
describe "globs" do
|
132
|
+
before(:each) do
|
133
|
+
@server.route '/about/*' do
|
134
|
+
params[:splat]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should put wildcard into param[:splat]" do
|
139
|
+
@request = Gopher::Request.new("/about/a/b")
|
140
|
+
@response = @server.dispatch(@request)
|
141
|
+
@response.body.should == "a/b"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
data/spec/dsl_spec.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
class FakeApp < Gopher::Application
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
class FakeServer < Gopher::Server
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Gopher::DSL do
|
12
|
+
before(:each) do
|
13
|
+
@app = FakeApp.new
|
14
|
+
|
15
|
+
@server = FakeServer.new(@app)
|
16
|
+
@server.send :require, 'gopher2000/dsl'
|
17
|
+
@server.stub!(:application).and_return(@app)
|
18
|
+
@app.reset!
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
describe "set" do
|
23
|
+
it "should set a config var" do
|
24
|
+
@server.set :foo, 'bar'
|
25
|
+
@app.config[:foo].should == 'bar'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "route" do
|
30
|
+
it "should pass a lookup and block to the app" do
|
31
|
+
@app.should_receive(:route).with('/foo')
|
32
|
+
@server.route '/foo' do
|
33
|
+
"hi"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "default_route" do
|
39
|
+
it "should pass a default block to the app" do
|
40
|
+
@app.should_receive(:default_route)
|
41
|
+
@server.default_route do
|
42
|
+
"hi"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "mount" do
|
48
|
+
it "should pass a route, path, and some opts to the app" do
|
49
|
+
@app.should_receive(:mount).with('/foo', {:path => "/bar"})
|
50
|
+
@server.mount "/foo" => "/bar"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should pass a route, path, filter, and some opts to the app" do
|
54
|
+
@app.should_receive(:mount).with('/foo', {:path => "/bar", :filter => "*.jpg"})
|
55
|
+
@server.mount "/foo" => "/bar", :filter => "*.jpg"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "menu" do
|
60
|
+
it "should pass a menu key and block to the app" do
|
61
|
+
@app.should_receive(:menu).with('/foo')
|
62
|
+
@server.menu '/foo' do
|
63
|
+
"hi"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "text" do
|
69
|
+
it "should pass a text_template key and block to the app" do
|
70
|
+
@app.should_receive(:text).with('/foo')
|
71
|
+
@server.text '/foo' do
|
72
|
+
"hi"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "helpers" do
|
78
|
+
it "should pass a block to the app" do
|
79
|
+
@app.should_receive(:helpers)
|
80
|
+
@server.helpers do
|
81
|
+
"hi"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "watch" do
|
87
|
+
it "should pass a script app for watching" do
|
88
|
+
@app.scripts.should_receive(:<<).with("foo")
|
89
|
+
@server.watch("foo")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "run" do
|
94
|
+
it "should set any incoming opts" do
|
95
|
+
@server.should_receive(:set).with(:x, 1)
|
96
|
+
@server.should_receive(:set).with(:y, 2)
|
97
|
+
@server.stub!(:load)
|
98
|
+
|
99
|
+
@server.run("foo", {:x => 1, :y => 2})
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should turn on script watching if in debug mode" do
|
103
|
+
@app.config[:debug] = true
|
104
|
+
@server.should_receive(:watch).with("foo.rb")
|
105
|
+
@server.should_receive(:load).with("foo.rb")
|
106
|
+
|
107
|
+
@server.run("foo.rb")
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should load the script" do
|
111
|
+
@server.should_receive(:load).with("foo.rb")
|
112
|
+
@server.run("foo.rb")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
data/spec/gopher_spec.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '/spec_helper')
|
2
|
+
|
3
|
+
describe Gopher::Handlers::DirectoryHandler do
|
4
|
+
before(:each) do
|
5
|
+
app = mock(Gopher::Application,
|
6
|
+
:host => "host",
|
7
|
+
:port => 1234,
|
8
|
+
:config => {})
|
9
|
+
|
10
|
+
@h = Gopher::Handlers::DirectoryHandler.new(:path => "/tmp", :mount_point => "/xyz/123")
|
11
|
+
@h.application = app
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "filtering" do
|
15
|
+
before(:each) do
|
16
|
+
File.should_receive(:directory?).with("/tmp/bar/baz").and_return(true)
|
17
|
+
File.should_receive(:directory?).with("/tmp/bar/baz/a.txt").and_return(false)
|
18
|
+
File.should_receive(:directory?).with("/tmp/bar/baz/b.exe").and_return(false)
|
19
|
+
File.should_receive(:directory?).with("/tmp/bar/baz/dir2").and_return(true)
|
20
|
+
|
21
|
+
File.should_receive(:file?).with("/tmp/bar/baz/a.txt").and_return(true)
|
22
|
+
File.should_receive(:file?).with("/tmp/bar/baz/b.exe").and_return(true)
|
23
|
+
|
24
|
+
File.should_receive(:fnmatch).with("*.txt", "/tmp/bar/baz/a.txt").and_return(true)
|
25
|
+
File.should_receive(:fnmatch).with("*.txt", "/tmp/bar/baz/b.exe").and_return(false)
|
26
|
+
|
27
|
+
Dir.should_receive(:glob).with("/tmp/bar/baz/*.*").and_return([
|
28
|
+
"/tmp/bar/baz/a.txt",
|
29
|
+
"/tmp/bar/baz/b.exe",
|
30
|
+
"/tmp/bar/baz/dir2"])
|
31
|
+
|
32
|
+
@h.filter = "*.txt"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should use right filter" do
|
36
|
+
@h.call(:splat => "bar/baz")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "request_path" do
|
41
|
+
it "should join existing path with incoming path" do
|
42
|
+
@h.request_path(:splat => "bar/baz").should == "/tmp/bar/baz"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "to_selector" do
|
47
|
+
it "should work" do
|
48
|
+
@h.to_selector("/tmp/foo/bar.html").should == "/xyz/123/foo/bar.html"
|
49
|
+
@h.to_selector("/tmp/foo/baz").should == "/xyz/123/foo/baz"
|
50
|
+
@h.to_selector("/tmp").should == "/xyz/123"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "contained?" do
|
55
|
+
it "should be false if not under base path" do
|
56
|
+
@h.contained?("/home/gopher").should == false
|
57
|
+
end
|
58
|
+
it "should be true if under base path" do
|
59
|
+
@h.contained?("/tmp/gopher").should == true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "safety checks" do
|
64
|
+
it "should raise exception for invalid directory" do
|
65
|
+
lambda {
|
66
|
+
@h.call(:splat => "../../../home/foo/bar/baz").to_s.should == "0a\t/tmp/bar/baz/a\thost\t1234"
|
67
|
+
}.should raise_error(Gopher::InvalidRequest)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "directories" do
|
72
|
+
before(:each) do
|
73
|
+
File.should_receive(:directory?).with("/tmp/bar/baz").and_return(true)
|
74
|
+
File.should_receive(:directory?).with("/tmp/bar/baz/a").and_return(false)
|
75
|
+
File.should_receive(:directory?).with("/tmp/bar/baz/dir2").and_return(true)
|
76
|
+
|
77
|
+
File.should_receive(:file?).with("/tmp/bar/baz/a").and_return(true)
|
78
|
+
File.should_receive(:fnmatch).with("*.*", "/tmp/bar/baz/a").and_return(true)
|
79
|
+
|
80
|
+
Dir.should_receive(:glob).with("/tmp/bar/baz/*.*").and_return([
|
81
|
+
"/tmp/bar/baz/a",
|
82
|
+
"/tmp/bar/baz/dir2"])
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should work" do
|
86
|
+
@h.call(:splat => "bar/baz").to_s.should == "iBrowsing: /tmp/bar/baz\tnull\t(FALSE)\t0\r\n0a\t/xyz/123/bar/baz/a\thost\t1234\r\n1dir2\t/xyz/123/bar/baz/dir2\thost\t1234\r\n"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "files" do
|
91
|
+
before(:each) do
|
92
|
+
@file = mock(File)
|
93
|
+
File.should_receive(:directory?).with("/tmp/baz.txt").and_return(false)
|
94
|
+
|
95
|
+
File.should_receive(:file?).with("/tmp/baz.txt").and_return(true)
|
96
|
+
File.should_receive(:new).with("/tmp/baz.txt").and_return(@file)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should work" do
|
100
|
+
@h.call(:splat => "baz.txt").should == @file
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "missing stuff" do
|
105
|
+
before(:each) do
|
106
|
+
File.should_receive(:directory?).with("/tmp/baz.txt").and_return(false)
|
107
|
+
File.should_receive(:file?).with("/tmp/baz.txt").and_return(false)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should return not found" do
|
111
|
+
lambda {
|
112
|
+
@h.call(:splat => "baz.txt")
|
113
|
+
}.should raise_error(Gopher::NotFoundError)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
+
|
3
|
+
describe Gopher::Application do
|
4
|
+
before(:each) do
|
5
|
+
@obj = Gopher::Application.new
|
6
|
+
# @obj.extend(Gopher::Helpers)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should add code to target class' do
|
10
|
+
@obj.helpers do
|
11
|
+
def foo; "FOO"; end
|
12
|
+
end
|
13
|
+
|
14
|
+
@obj.foo.should == "FOO"
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/../spec_helper')
|
2
|
+
|
3
|
+
describe Gopher::Rendering::Base do
|
4
|
+
before(:each) do
|
5
|
+
@ctx = Gopher::Rendering::Base.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should add text' do
|
9
|
+
@ctx.text("line 1")
|
10
|
+
@ctx.text("line 2")
|
11
|
+
@ctx.result.should == "line 1\r\nline 2\r\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should add breaks correctly" do
|
15
|
+
@ctx.spacing 2
|
16
|
+
@ctx.text("line 1")
|
17
|
+
@ctx.text("line 2")
|
18
|
+
@ctx.result.should == "line 1\r\n\r\nline 2\r\n\r\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "br outputs a bunch of newlines" do
|
22
|
+
@ctx.br(2).should == "\r\n\r\n"
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "underline" do
|
26
|
+
it "underline outputs a pretty line" do
|
27
|
+
@ctx.underline(1, 'x').should == "x\r\n"
|
28
|
+
end
|
29
|
+
it "has defaults" do
|
30
|
+
@ctx.underline.should == "=" * 70 + "\r\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "big_header" do
|
35
|
+
it "outputs a box with text" do
|
36
|
+
@ctx.width(5)
|
37
|
+
@ctx.big_header('pie').should == "\r\n=====\r\n=pie=\r\n=====\r\n\r\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "header" do
|
42
|
+
it "outputs underlined text" do
|
43
|
+
@ctx.width(5)
|
44
|
+
@ctx.header('pie').should == " pie \r\n=====\r\n"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "uses to_s to output result" do
|
49
|
+
@ctx.text("line 1")
|
50
|
+
@ctx.to_s.should == @ctx.result
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "block" do
|
54
|
+
it "wraps text" do
|
55
|
+
@ctx.should_receive(:text).twice.with "a"
|
56
|
+
@ctx.block("a a",1)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|