gopher2000 0.2.2 → 0.5.5
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.
- 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
|