gopher2000 0.2.2 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +1 -16
- data/README.markdown +3 -1
- data/bin/gopher2000 +1 -1
- data/examples/default_route.rb +0 -0
- data/examples/figlet.rb +28 -0
- data/examples/nyan.rb +0 -0
- data/examples/simple.rb +2 -2
- data/examples/twitter.rb +0 -0
- data/examples/weather.rb +0 -0
- data/gopher2000.gemspec +5 -5
- data/lib/gopher2000.rb +1 -1
- data/lib/gopher2000/base.rb +83 -37
- data/lib/gopher2000/dispatcher.rb +13 -4
- data/lib/gopher2000/dsl.rb +1 -1
- data/lib/gopher2000/handlers/directory_handler.rb +5 -7
- data/lib/gopher2000/rendering/base.rb +42 -1
- data/lib/gopher2000/rendering/menu.rb +104 -15
- data/lib/gopher2000/request.rb +13 -2
- data/lib/gopher2000/server.rb +11 -4
- data/lib/gopher2000/version.rb +1 -1
- data/spec/application_spec.rb +12 -12
- data/spec/dispatching_spec.rb +38 -17
- data/spec/dsl_spec.rb +76 -67
- data/spec/handlers/directory_handler_spec.rb +35 -35
- data/spec/helpers_spec.rb +1 -1
- data/spec/rendering/base_spec.rb +16 -9
- data/spec/rendering/menu_spec.rb +40 -18
- data/spec/rendering_spec.rb +7 -7
- data/spec/request_spec.rb +21 -10
- data/spec/response_spec.rb +5 -5
- data/spec/routing_spec.rb +21 -21
- data/spec/server_spec.rb +23 -7
- metadata +117 -65
- data/.rvmrc +0 -1
data/lib/gopher2000/dsl.rb
CHANGED
@@ -27,7 +27,7 @@ module Gopher
|
|
27
27
|
|
28
28
|
#
|
29
29
|
# strip slashes, extra dots, etc, from an incoming selector and turn it into a 'normalized' path
|
30
|
-
# @param [String] path
|
30
|
+
# @param [String] p path to check
|
31
31
|
# @return clean path string
|
32
32
|
#
|
33
33
|
def sanitize(p)
|
@@ -65,12 +65,10 @@ module Gopher
|
|
65
65
|
#
|
66
66
|
# handle a request
|
67
67
|
#
|
68
|
-
# @param [Hash] the params as parsed during the dispatching process - the main thing here should be :splat, which will basically be the path requested.
|
69
|
-
# @param [Request]
|
68
|
+
# @param [Hash] params the params as parsed during the dispatching process - the main thing here should be :splat, which will basically be the path requested.
|
69
|
+
# @param [Request] request the Request object for this session -- not currently used?
|
70
70
|
#
|
71
71
|
def call(params = {}, request = nil)
|
72
|
-
# debug_log "DirectoryHandler: call #{params.inspect}, #{request.inspect}"
|
73
|
-
|
74
72
|
lookup = request_path(params)
|
75
73
|
|
76
74
|
raise Gopher::InvalidRequest if ! contained?(lookup)
|
@@ -86,7 +84,7 @@ module Gopher
|
|
86
84
|
|
87
85
|
#
|
88
86
|
# generate a directory listing
|
89
|
-
# @param [String] path to directory
|
87
|
+
# @param [String] dir path to directory
|
90
88
|
# @return rendered directory output for a response
|
91
89
|
#
|
92
90
|
def directory(dir)
|
@@ -98,7 +96,7 @@ module Gopher
|
|
98
96
|
# iterate through the contents of this directory.
|
99
97
|
# NOTE: we don't filter this, so we will ALWAYS list subdirectories of a mounted folder
|
100
98
|
#
|
101
|
-
Dir.glob("#{dir}
|
99
|
+
Dir.glob("#{dir}/*").each do |x|
|
102
100
|
# if this is a directory, then generate a directory link for it
|
103
101
|
if File.directory?(x)
|
104
102
|
m.directory File.basename(x), to_selector(x), @application.host, @application.port
|
@@ -5,10 +5,14 @@ module Gopher
|
|
5
5
|
#
|
6
6
|
module Rendering
|
7
7
|
|
8
|
+
require 'artii'
|
9
|
+
|
8
10
|
# "A CR LF denotes the end of the item." RFC 1436
|
9
11
|
# @see http://www.faqs.org/rfcs/rfc1436.html
|
10
12
|
LINE_ENDING = "\r\n"
|
11
13
|
|
14
|
+
DEFAULT_ENCODING = 'UTF-8'
|
15
|
+
|
12
16
|
#
|
13
17
|
# base class for rendering output. this class provides methods
|
14
18
|
# that can be used when rendering both text and gopher menus
|
@@ -40,7 +44,7 @@ module Gopher
|
|
40
44
|
# then adds any required spacing
|
41
45
|
#
|
42
46
|
def text(text)
|
43
|
-
self << text
|
47
|
+
self << text.force_encoding(DEFAULT_ENCODING)
|
44
48
|
add_spacing
|
45
49
|
end
|
46
50
|
|
@@ -94,6 +98,32 @@ module Gopher
|
|
94
98
|
self.to_s
|
95
99
|
end
|
96
100
|
|
101
|
+
#
|
102
|
+
# output a figlet, which is a big ASCII art header like this:
|
103
|
+
# _ _ _ _ _
|
104
|
+
# | | | | | | | | |
|
105
|
+
# | |__| | ___| | | ___ | |
|
106
|
+
# | __ |/ _ \ | |/ _ \| |
|
107
|
+
# | | | | __/ | | (_) |_|
|
108
|
+
# |_| |_|\___|_|_|\___/(_)
|
109
|
+
#
|
110
|
+
# This method doesn't do any width checks, so you should be
|
111
|
+
# careful with it.
|
112
|
+
# You can get a list of fonts from the artii source code or
|
113
|
+
# http://www.figlet.org/examples.html
|
114
|
+
# https://github.com/miketierney/artii/tree/master/lib/figlet/fonts
|
115
|
+
|
116
|
+
# @param [String] str the text you want to use for your figlet
|
117
|
+
# @param [String] font name of the font. Defaults to 'big'.
|
118
|
+
#
|
119
|
+
def figlet(str, font = 'big')
|
120
|
+
a = Artii::Base.new(:font => font)
|
121
|
+
a.asciify(str).split("\n").each do |l|
|
122
|
+
text l
|
123
|
+
end
|
124
|
+
self.to_s
|
125
|
+
end
|
126
|
+
|
97
127
|
#
|
98
128
|
# output a centered string with a nice underline below it,
|
99
129
|
# centered on the current output width
|
@@ -119,6 +149,17 @@ module Gopher
|
|
119
149
|
underline(@width, under)
|
120
150
|
end
|
121
151
|
|
152
|
+
#
|
153
|
+
# output a 'small' header, just the text with an underline
|
154
|
+
# @param [String] str - the string to output
|
155
|
+
# @param [String] under - the desired underline character
|
156
|
+
#
|
157
|
+
def small_header(str, under = '=')
|
158
|
+
str = " " + str + " "
|
159
|
+
text(str)
|
160
|
+
underline(str.length, under)
|
161
|
+
end
|
162
|
+
|
122
163
|
#
|
123
164
|
# output a centered string in a box
|
124
165
|
# @param [String] str the string to output
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Gopher
|
2
2
|
module Rendering
|
3
|
+
require 'mimemagic'
|
4
|
+
|
3
5
|
#
|
4
6
|
# The MenuContext is for rendering gopher menus in the "pseudo
|
5
7
|
# file-system hierarchy" defined by RFC1436
|
@@ -7,7 +9,6 @@ module Gopher
|
|
7
9
|
# @see http://www.ietf.org/rfc/rfc1436.txt
|
8
10
|
#
|
9
11
|
class Menu < Base
|
10
|
-
|
11
12
|
# default host value when rendering a line with no selector
|
12
13
|
NO_HOST = '(FALSE)'
|
13
14
|
|
@@ -15,7 +16,7 @@ module Gopher
|
|
15
16
|
NO_PORT = 0
|
16
17
|
|
17
18
|
# Sanitizes text for use in gopher menus
|
18
|
-
# @param [String]
|
19
|
+
# @param [String] raw text to cleanup
|
19
20
|
# @return string that can be used in a gopher menu
|
20
21
|
def sanitize_text(raw)
|
21
22
|
raw.
|
@@ -92,11 +93,51 @@ module Gopher
|
|
92
93
|
# method instead
|
93
94
|
# @param [String] host for link, defaults to current host
|
94
95
|
# @param [String] port for link, defaults to current port
|
95
|
-
|
96
|
-
|
96
|
+
# @param [String] real filepath of the link
|
97
|
+
# @param [String] selector type. if not specified, we will guess
|
98
|
+
def link(text, selector, host=nil, port=nil, filepath=nil, type=nil)
|
99
|
+
if !type
|
100
|
+
if filepath
|
101
|
+
type = determine_type(filepath)
|
102
|
+
else
|
103
|
+
type = determine_type(selector)
|
104
|
+
end
|
105
|
+
end
|
97
106
|
line type, text, selector, host, port
|
98
107
|
end
|
99
108
|
|
109
|
+
#
|
110
|
+
# output a link to text output
|
111
|
+
#
|
112
|
+
# @param [String] text the text of the link
|
113
|
+
# @param [String] selector the path of the link. the extension of this path will be used to
|
114
|
+
# detemine the type of link -- image, archive, etc. If you want
|
115
|
+
# to specify a specific link-type, you should use the text
|
116
|
+
# method instead
|
117
|
+
# @param [String] host for link, defaults to current host
|
118
|
+
# @param [String] port for link, defaults to current port
|
119
|
+
# @param [String] real filepath of the link
|
120
|
+
def text_link(text, selector, host=nil, port=nil, filepath=nil)
|
121
|
+
link(text, selector, host, port, filepath, '0')
|
122
|
+
end
|
123
|
+
|
124
|
+
# Create an HTTP link entry. This is how this works (via wikipedia)
|
125
|
+
#
|
126
|
+
# For example, to create a link to http://gopher.quux.org/, the
|
127
|
+
# item type is "h", the display string is the title of the link,
|
128
|
+
# the item selector is "URL:http://gopher.quux.org/", and the
|
129
|
+
# domain and port are that of the originating Gopher server (so
|
130
|
+
# that clients that do not support URL links will query the
|
131
|
+
# server and receive an HTML redirection page).
|
132
|
+
#
|
133
|
+
# @param [String] text the text of the link
|
134
|
+
# @param [String] URL of the link
|
135
|
+
# @param [String] host for link, defaults to current host
|
136
|
+
# @param [String] port for link, defaults to current port
|
137
|
+
def http(text, url, host=nil, port=nil)
|
138
|
+
line "h", text, "URL:#{url}", host, port
|
139
|
+
end
|
140
|
+
|
100
141
|
#
|
101
142
|
# output a search entry
|
102
143
|
# @param [String] text the text of the link
|
@@ -109,19 +150,67 @@ module Gopher
|
|
109
150
|
|
110
151
|
#
|
111
152
|
# Determines the gopher type for +selector+ based on the
|
112
|
-
#
|
113
|
-
#
|
114
|
-
# @param [String] selector, presumably a link to a file name with an extension
|
153
|
+
# information stored in the shared mime database.
|
154
|
+
# @param [String] filepath The full path to the file (should also exist, if possible)
|
115
155
|
# @return gopher selector type
|
116
156
|
#
|
117
|
-
def determine_type(
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
157
|
+
def determine_type(filepath)
|
158
|
+
# Determine MIME type by path
|
159
|
+
mimetype = MimeMagic.by_path(filepath)
|
160
|
+
|
161
|
+
# Determine MIME type by contents
|
162
|
+
if !mimetype
|
163
|
+
begin
|
164
|
+
# Open file
|
165
|
+
file = File.open(filepath)
|
166
|
+
|
167
|
+
# Try to detect MIME type using by recognition of typical characters
|
168
|
+
mimetype = MimeMagic.by_magic(file)
|
169
|
+
|
170
|
+
if !mimetype
|
171
|
+
file.rewind
|
172
|
+
|
173
|
+
# Read up to 1k of file data and look for a "\0\0" sequence (typical for binary files)
|
174
|
+
if file.read(1000).include?("\0\0")
|
175
|
+
mimetype = MimeMagic.new("application/octet-stream")
|
176
|
+
else
|
177
|
+
mimetype = MimeMagic.new("text/plain")
|
178
|
+
end
|
179
|
+
|
180
|
+
file.close
|
181
|
+
end
|
182
|
+
rescue SystemCallError,IOError
|
183
|
+
nil
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
if !mimetype
|
188
|
+
ext = File.extname(filepath).split(".").last
|
189
|
+
mimetype = MimeMagic.by_extension(ext)
|
190
|
+
end
|
191
|
+
|
192
|
+
if !mimetype
|
193
|
+
return '9' # Binary file
|
194
|
+
elsif mimetype.child_of?('application/gzip') || mimetype.child_of?('application/x-bzip') || mimetype.child_of?('application/zip')
|
195
|
+
return '5' # archive
|
196
|
+
elsif mimetype.child_of?('image/gif')
|
197
|
+
return 'g' # GIF image
|
198
|
+
elsif mimetype.child_of?('text/x-uuencode')
|
199
|
+
return '6' # UUEncode encoded file
|
200
|
+
elsif mimetype.child_of?('application/mac-binhex40')
|
201
|
+
return '4' # BinHex encoded file
|
202
|
+
elsif mimetype.child_of?('text/html') || mimetype.child_of?('application/xhtml+xml')
|
203
|
+
return 'h' # HTML file
|
204
|
+
elsif mimetype.mediatype == 'text' || mimetype.child_of?('text/plain')
|
205
|
+
return '0' # General text file
|
206
|
+
elsif mimetype.mediatype == 'image'
|
207
|
+
return 'I' # General image file
|
208
|
+
elsif mimetype.mediatype == 'audio'
|
209
|
+
return 's' # General audio file
|
210
|
+
elsif mimetype.mediatype == 'video'
|
211
|
+
return 'v' # General video file
|
212
|
+
else
|
213
|
+
return '9' # Binary file
|
125
214
|
end
|
126
215
|
end
|
127
216
|
end
|
data/lib/gopher2000/request.rb
CHANGED
@@ -7,10 +7,21 @@ module Gopher
|
|
7
7
|
attr_accessor :selector, :input, :ip_address
|
8
8
|
|
9
9
|
def initialize(raw, ip_addr=nil)
|
10
|
-
@
|
11
|
-
@
|
10
|
+
@raw = raw
|
11
|
+
@selector, @input = @raw.chomp.split("\t")
|
12
|
+
|
13
|
+
@selector = Gopher::Application.sanitize_selector(@selector)
|
14
|
+
@ip_address = ip_addr
|
12
15
|
end
|
13
16
|
|
17
|
+
def url?
|
18
|
+
@raw =~ /^URL\:/
|
19
|
+
end
|
20
|
+
|
21
|
+
def url
|
22
|
+
@raw.chomp.split("\t").first.gsub(/^URL\:/, '')
|
23
|
+
end
|
24
|
+
|
14
25
|
# confirm that this is actually a valid gopher request
|
15
26
|
# @return [Boolean] true if the request is valid, false otherwise
|
16
27
|
def valid?
|
data/lib/gopher2000/server.rb
CHANGED
@@ -8,12 +8,12 @@ module Gopher
|
|
8
8
|
|
9
9
|
#
|
10
10
|
# constructor
|
11
|
-
# @param [Application] instance of Gopher::Application we want to run
|
11
|
+
# @param [Application] a instance of Gopher::Application we want to run
|
12
12
|
#
|
13
13
|
def initialize(a)
|
14
14
|
@app = a
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
#
|
18
18
|
# @return [String] name of the host specified in our config
|
19
19
|
#
|
@@ -28,6 +28,13 @@ module Gopher
|
|
28
28
|
@app.config[:port] ||= 70
|
29
29
|
end
|
30
30
|
|
31
|
+
#
|
32
|
+
# @return [String] environment specified in config
|
33
|
+
#
|
34
|
+
def env
|
35
|
+
@app.config[:env] || 'development'
|
36
|
+
end
|
37
|
+
|
31
38
|
#
|
32
39
|
# main app loop. called via at_exit block defined in DSL
|
33
40
|
#
|
@@ -77,8 +84,8 @@ module Gopher
|
|
77
84
|
require 'optparse'
|
78
85
|
OptionParser.new { |op|
|
79
86
|
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 :
|
81
|
-
op.on('-e env', 'set the environment (default is development)') { |val| set :
|
87
|
+
op.on('-o addr', 'set the host (default is 0.0.0.0)') { |val| set :host, val }
|
88
|
+
op.on('-e env', 'set the environment (default is development)') { |val| set :env, val.to_sym }
|
82
89
|
}.parse!(ARGV.dup)
|
83
90
|
end
|
84
91
|
end
|
data/lib/gopher2000/version.rb
CHANGED
data/spec/application_spec.rb
CHANGED
@@ -9,46 +9,46 @@ describe Gopher::Application do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'should have default host/port' do
|
12
|
-
@app.host.
|
13
|
-
@app.port.
|
12
|
+
expect(@app.host).to eq("0.0.0.0")
|
13
|
+
expect(@app.port).to eq(70)
|
14
14
|
end
|
15
15
|
|
16
16
|
describe "should_reload?" do
|
17
17
|
it "is false if no scripts" do
|
18
|
-
@app.should_reload
|
18
|
+
expect(@app.should_reload?).to eq(false)
|
19
19
|
end
|
20
20
|
|
21
21
|
it "shouldn't do anything if last_reload not set" do
|
22
|
-
@app.last_reload.
|
22
|
+
expect(@app.last_reload).to be_nil
|
23
23
|
@app.scripts << "foo.rb"
|
24
|
-
@app.should_reload
|
24
|
+
expect(@app.should_reload?).to eq(false)
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should check script date" do
|
28
28
|
now = Time.now
|
29
|
-
Time.
|
29
|
+
allow(Time).to receive(:now).and_return(now)
|
30
30
|
|
31
31
|
@app.last_reload = Time.now - 1000
|
32
32
|
@app.scripts << "foo.rb"
|
33
|
-
File.
|
33
|
+
expect(File).to receive(:mtime).with("foo.rb").and_return(now)
|
34
34
|
|
35
|
-
@app.should_reload
|
35
|
+
expect(@app.should_reload?).to eq(true)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
describe "reload_stale" do
|
40
40
|
it "should load script and update last_reload" do
|
41
41
|
now = Time.now
|
42
|
-
Time.
|
42
|
+
allow(Time).to receive(:now).and_return(now)
|
43
43
|
|
44
|
-
@app.
|
44
|
+
expect(@app).to receive(:should_reload?).and_return(true)
|
45
45
|
|
46
46
|
@app.last_reload = Time.now - 1000
|
47
47
|
@app.scripts << "foo.rb"
|
48
|
-
@app.
|
48
|
+
expect(@app).to receive(:load).with("foo.rb")
|
49
49
|
@app.reload_stale
|
50
50
|
|
51
|
-
@app.last_reload.
|
51
|
+
expect(@app.last_reload).to eq(now)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
data/spec/dispatching_spec.rb
CHANGED
@@ -24,7 +24,7 @@ describe Gopher::Application do
|
|
24
24
|
@request = Gopher::Request.new("/about")
|
25
25
|
|
26
26
|
keys, block = @server.lookup(@request.selector)
|
27
|
-
keys.
|
27
|
+
expect(keys).to eq({})
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should translate path" do
|
@@ -32,7 +32,7 @@ describe Gopher::Application do
|
|
32
32
|
@request = Gopher::Request.new("/about/x/y")
|
33
33
|
|
34
34
|
keys, block = @server.lookup(@request.selector)
|
35
|
-
keys.
|
35
|
+
expect(keys).to eq({:foo => 'x', :bar => 'y'})
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should return default route if no other route found, and default is defined" do
|
@@ -41,8 +41,8 @@ describe Gopher::Application do
|
|
41
41
|
end
|
42
42
|
@request = Gopher::Request.new("/about/x/y")
|
43
43
|
@response = @server.dispatch(@request)
|
44
|
-
@response.body.
|
45
|
-
@response.code.
|
44
|
+
expect(@response.body).to eq("DEFAULT ROUTE")
|
45
|
+
expect(@response.code).to eq(:success)
|
46
46
|
end
|
47
47
|
|
48
48
|
it "should respond with error if no route found" do
|
@@ -50,7 +50,8 @@ describe Gopher::Application do
|
|
50
50
|
@request = Gopher::Request.new("/junk/x/y")
|
51
51
|
|
52
52
|
@response = @server.dispatch(@request)
|
53
|
-
@response.code.
|
53
|
+
expect(@response.code).to eq(:missing)
|
54
|
+
expect(@response.body).to contain_any_error
|
54
55
|
end
|
55
56
|
|
56
57
|
it "should respond with error if invalid request" do
|
@@ -58,7 +59,8 @@ describe Gopher::Application do
|
|
58
59
|
@request = Gopher::Request.new("x" * 256)
|
59
60
|
|
60
61
|
@response = @server.dispatch(@request)
|
61
|
-
@response.code.
|
62
|
+
expect(@response.code).to eq(:error)
|
63
|
+
expect(@response.body).to contain_any_error
|
62
64
|
end
|
63
65
|
|
64
66
|
it "should respond with error if there's an exception" do
|
@@ -66,7 +68,8 @@ describe Gopher::Application do
|
|
66
68
|
@request = Gopher::Request.new("/x")
|
67
69
|
|
68
70
|
@response = @server.dispatch(@request)
|
69
|
-
@response.code.
|
71
|
+
expect(@response.code).to eq(:error)
|
72
|
+
expect(@response.body).to contain_any_error
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
@@ -82,7 +85,7 @@ describe Gopher::Application do
|
|
82
85
|
|
83
86
|
it "should run the block" do
|
84
87
|
@response = @server.dispatch(@request)
|
85
|
-
@response.body.
|
88
|
+
expect(@response.body).to eq("GOPHERTRON")
|
86
89
|
end
|
87
90
|
end
|
88
91
|
|
@@ -97,37 +100,47 @@ describe Gopher::Application do
|
|
97
100
|
|
98
101
|
it "should use incoming params" do
|
99
102
|
@response = @server.dispatch(@request)
|
100
|
-
@response.body.
|
103
|
+
expect(@response.body).to eq("x/a/y/b")
|
101
104
|
end
|
102
105
|
end
|
103
106
|
|
104
107
|
describe "dispatch to mount" do
|
105
108
|
before(:each) do
|
106
|
-
@h =
|
107
|
-
@h.
|
108
|
-
Gopher::Handlers::DirectoryHandler.
|
109
|
+
@h = double(Gopher::Handlers::DirectoryHandler)
|
110
|
+
expect(@h).to receive(:application=).with(@server)
|
111
|
+
expect(Gopher::Handlers::DirectoryHandler).to receive(:new).with({:bar => :baz, :mount_point => "/foo"}).and_return(@h)
|
109
112
|
|
110
113
|
@server.mount "/foo", :bar => :baz
|
111
114
|
end
|
112
115
|
|
113
116
|
it "should work for root path" do
|
114
117
|
@request = Gopher::Request.new("/foo")
|
115
|
-
@h.
|
118
|
+
expect(@h).to receive(:call).with({:splat => ""}, @request)
|
116
119
|
|
117
120
|
@response = @server.dispatch(@request)
|
118
|
-
@response.code.
|
121
|
+
expect(@response.code).to eq(:success)
|
119
122
|
end
|
120
123
|
|
121
124
|
it "should work for subdir" do
|
122
125
|
@request = Gopher::Request.new("/foo/bar")
|
123
|
-
@h.
|
126
|
+
expect(@h).to receive(:call).with({:splat => "bar"}, @request)
|
124
127
|
|
125
128
|
@response = @server.dispatch(@request)
|
126
|
-
@response.code.
|
129
|
+
expect(@response.code).to eq(:success)
|
127
130
|
end
|
128
131
|
end
|
129
132
|
|
133
|
+
describe 'dispatch for URL requests' do
|
134
|
+
let(:target) { 'URL:http://github.com/muffinista/gopher2000' }
|
135
|
+
let(:request) { Gopher::Request.new(target) }
|
136
|
+
let(:response) { @server.dispatch(request) }
|
130
137
|
|
138
|
+
it "should return web page" do
|
139
|
+
expect(response.body).to include('<meta http-equiv="refresh" content="5;URL=http://github.com/muffinista/gopher2000">')
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
131
144
|
describe "globs" do
|
132
145
|
before(:each) do
|
133
146
|
@server.route '/about/*' do
|
@@ -138,7 +151,15 @@ describe Gopher::Application do
|
|
138
151
|
it "should put wildcard into param[:splat]" do
|
139
152
|
@request = Gopher::Request.new("/about/a/b")
|
140
153
|
@response = @server.dispatch(@request)
|
141
|
-
@response.body.
|
154
|
+
expect(@response.body).to eq("a/b")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
RSpec::Matchers.define :contain_any_error do
|
160
|
+
match do |actual|
|
161
|
+
actual.split(/\r?\n/).any? do |line|
|
162
|
+
line.match(/^3.*?\tnull\t\(FALSE\)\t0$/)
|
142
163
|
end
|
143
164
|
end
|
144
165
|
end
|