gopher2000 0.5.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +19 -0
- data/.gitignore +3 -0
- data/.ruby-version +1 -1
- data/Dockerfile +17 -0
- data/LICENSE.txt +669 -9
- data/README.markdown +30 -3
- data/bin/gopher2000 +1 -1
- data/examples/simple.rb +4 -2
- data/lib/gopher2000/base.rb +63 -21
- data/lib/gopher2000/dispatcher.rb +10 -4
- data/lib/gopher2000/rendering/base.rb +17 -2
- data/lib/gopher2000/request.rb +12 -3
- data/lib/gopher2000/server.rb +10 -3
- data/lib/gopher2000/version.rb +1 -1
- data/spec/dispatching_spec.rb +21 -0
- data/spec/dsl_spec.rb +76 -67
- data/spec/rendering/base_spec.rb +14 -2
- data/spec/rendering/menu_spec.rb +19 -3
- data/spec/request_spec.rb +6 -0
- data/spec/server_spec.rb +17 -1
- metadata +8 -23
- data/.travis.yml +0 -8
data/README.markdown
CHANGED
@@ -25,11 +25,10 @@ Features
|
|
25
25
|
* built on Event Machine.
|
26
26
|
* Easy to mount directories and serve up files.
|
27
27
|
* built in logging and stats.
|
28
|
-
* Runs on Ruby 1.9.2 with all the modern conveniences.
|
29
28
|
|
30
29
|
Requirements
|
31
30
|
------------
|
32
|
-
* Ruby
|
31
|
+
* Ruby 2 or greater
|
33
32
|
* Nerves of steel
|
34
33
|
|
35
34
|
Examples
|
@@ -59,7 +58,7 @@ menu :index do
|
|
59
58
|
br(2)
|
60
59
|
|
61
60
|
# link somewhere
|
62
|
-
|
61
|
+
text_link 'current time', '/time'
|
63
62
|
br
|
64
63
|
end
|
65
64
|
|
@@ -108,6 +107,34 @@ Command line options will override defaults specified in your script
|
|
108
107
|
-- so you can try out things on a different port/address if needed.
|
109
108
|
|
110
109
|
|
110
|
+
Docker
|
111
|
+
------
|
112
|
+
|
113
|
+
There's a pretty simple docker script which you can use to run an
|
114
|
+
app. To run one of the included examples, you could do something like:
|
115
|
+
|
116
|
+
|
117
|
+
```
|
118
|
+
docker build -t gopher2000 .
|
119
|
+
docker run -p 7070:7070 --rm -it gopher2000 examples/simple.rb
|
120
|
+
```
|
121
|
+
|
122
|
+
This will run the `simple` example on port 7070. You can view it
|
123
|
+
locally by running something like:
|
124
|
+
|
125
|
+
```
|
126
|
+
lynx gopher://0.0.0.0:7070
|
127
|
+
```
|
128
|
+
|
129
|
+
The Dockerfile is also published to Docker Hub, so you could run
|
130
|
+
something like this:
|
131
|
+
|
132
|
+
```
|
133
|
+
docker run -p 7070:7070 --rm -v $PWD:/opt muffinista/gopher2000 /opt/gopher-script.rb
|
134
|
+
```
|
135
|
+
|
136
|
+
|
137
|
+
|
111
138
|
Developing Gopher Sites
|
112
139
|
-----------------------
|
113
140
|
|
data/bin/gopher2000
CHANGED
@@ -31,7 +31,7 @@ params = {
|
|
31
31
|
|
32
32
|
opts.on('-d', '--debug', "run in debug mode") { params[:debug] = true }
|
33
33
|
opts.on('-p port', 'set the port (default is 70)') { |val| params[:port] = Integer(val) }
|
34
|
-
opts.on('-o addr', 'set the host (default is 0.0.0.0)') { |val| params[host] = val }
|
34
|
+
opts.on('-o addr', 'set the host (default is 0.0.0.0)') { |val| params[:host] = val }
|
35
35
|
opts.on('-e env', 'set the environment (default is development)') { |val| params[:env] = val.to_sym }
|
36
36
|
|
37
37
|
opts.on_tail("-h", "--help", "Show this message") do
|
data/examples/simple.rb
CHANGED
@@ -5,6 +5,8 @@
|
|
5
5
|
# Simple gopher example
|
6
6
|
#
|
7
7
|
|
8
|
+
require "rubygems"
|
9
|
+
require "bundler/setup"
|
8
10
|
require 'gopher2000'
|
9
11
|
|
10
12
|
set :host, '0.0.0.0'
|
@@ -57,11 +59,11 @@ menu :index do
|
|
57
59
|
br(2)
|
58
60
|
|
59
61
|
# link somewhere
|
60
|
-
|
62
|
+
text_link 'current time', '/time'
|
61
63
|
br
|
62
64
|
|
63
65
|
# another link
|
64
|
-
|
66
|
+
text_link 'about', '/about'
|
65
67
|
br
|
66
68
|
|
67
69
|
# ask for some input
|
data/lib/gopher2000/base.rb
CHANGED
@@ -54,6 +54,13 @@ module Gopher
|
|
54
54
|
config[:port] ||= 70
|
55
55
|
end
|
56
56
|
|
57
|
+
#
|
58
|
+
# return the application environment
|
59
|
+
#
|
60
|
+
def env
|
61
|
+
config[:env] ||= 'development'
|
62
|
+
end
|
63
|
+
|
57
64
|
#
|
58
65
|
# are we in debugging mode?
|
59
66
|
#
|
@@ -162,12 +169,11 @@ module Gopher
|
|
162
169
|
#
|
163
170
|
def lookup(selector)
|
164
171
|
unless routes.nil?
|
165
|
-
|
166
|
-
|
172
|
+
routes.each do |pattern, keys, block|
|
167
173
|
if match = pattern.match(selector)
|
168
174
|
match = match.to_a
|
169
175
|
url = match.shift
|
170
|
-
|
176
|
+
|
171
177
|
params = to_params_hash(keys, match)
|
172
178
|
|
173
179
|
#
|
@@ -201,6 +207,9 @@ module Gopher
|
|
201
207
|
if ! @request.valid?
|
202
208
|
response.body = handle_invalid_request
|
203
209
|
response.code = :error
|
210
|
+
elsif @request.url?
|
211
|
+
response.body = handle_url(@request)
|
212
|
+
response.code = :success
|
204
213
|
else
|
205
214
|
begin
|
206
215
|
debug_log("do lookup for #{@request.selector}")
|
@@ -347,6 +356,15 @@ module Gopher
|
|
347
356
|
menus.include?(:error) ? :error : :'internal/error'
|
348
357
|
end
|
349
358
|
|
359
|
+
|
360
|
+
#
|
361
|
+
# get the id of the template that will be used when rendering an html page
|
362
|
+
# @return name of error template
|
363
|
+
#
|
364
|
+
def url_template
|
365
|
+
menus.include?(:html) ? :html : :'internal/url'
|
366
|
+
end
|
367
|
+
|
350
368
|
#
|
351
369
|
# get the id of the template that will be used when rendering an
|
352
370
|
# invalid request
|
@@ -431,20 +449,18 @@ module Gopher
|
|
431
449
|
|
432
450
|
class << self
|
433
451
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
#
|
452
|
+
#
|
453
|
+
# Sanitizes a gopher selector
|
454
|
+
#
|
455
|
+
def sanitize_selector(raw)
|
456
|
+
"/#{raw}".dup.
|
457
|
+
strip. # Strip whitespace
|
458
|
+
sub(/\/$/, ''). # Strip last rslash
|
459
|
+
sub(/^\/*/, '/'). # Strip extra lslashes
|
460
|
+
gsub(/\.+/, '.') # Don't want consecutive dots!
|
461
|
+
end
|
462
|
+
|
463
|
+
#
|
448
464
|
# generate a method which we will use to run routes. this is
|
449
465
|
# based on #generate_method as used by sinatra.
|
450
466
|
# @see https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb
|
@@ -457,7 +473,7 @@ module Gopher
|
|
457
473
|
method
|
458
474
|
end
|
459
475
|
end
|
460
|
-
|
476
|
+
|
461
477
|
#
|
462
478
|
# output a debugging message
|
463
479
|
#
|
@@ -474,15 +490,37 @@ module Gopher
|
|
474
490
|
#
|
475
491
|
def register_defaults
|
476
492
|
menu :'internal/not_found' do
|
477
|
-
|
493
|
+
error "Sorry, #{@request.selector} was not found"
|
478
494
|
end
|
479
495
|
|
480
496
|
menu :'internal/error' do |details|
|
481
|
-
|
497
|
+
error "Sorry, there was an error #{details}"
|
482
498
|
end
|
483
499
|
|
484
500
|
menu :'internal/invalid_request' do
|
485
|
-
|
501
|
+
error "invalid request"
|
502
|
+
end
|
503
|
+
|
504
|
+
menu :'internal/url' do
|
505
|
+
output = <<-EOHTML
|
506
|
+
<html>
|
507
|
+
<head>
|
508
|
+
<meta http-equiv="refresh" content="5;URL=#{@request.url}">
|
509
|
+
</head>
|
510
|
+
<body>
|
511
|
+
<p>
|
512
|
+
You are following a link from gopher to a website. If your browser supports it, you will be
|
513
|
+
automatically taken to the web site shortly. If you do not get
|
514
|
+
sent there, please click <a href="#{@request.url}">here</a>.
|
515
|
+
</p>
|
516
|
+
<p>
|
517
|
+
The URL linked is: <a href="#{@request.url}">#{@request.url}</a>.
|
518
|
+
</p>
|
519
|
+
<p>Have a nice day!</p>
|
520
|
+
</body>
|
521
|
+
</html>
|
522
|
+
EOHTML
|
523
|
+
output
|
486
524
|
end
|
487
525
|
end
|
488
526
|
|
@@ -490,6 +528,10 @@ module Gopher
|
|
490
528
|
render not_found_template
|
491
529
|
end
|
492
530
|
|
531
|
+
def handle_url(request)
|
532
|
+
render url_template, request
|
533
|
+
end
|
534
|
+
|
493
535
|
def handle_error(e)
|
494
536
|
render error_template, e
|
495
537
|
end
|
@@ -27,15 +27,21 @@ module Gopher
|
|
27
27
|
#
|
28
28
|
def receive_data data
|
29
29
|
(@buf ||= '') << data
|
30
|
-
|
30
|
+
first_line = true
|
31
|
+
|
32
|
+
ip_address = remote_ip
|
31
33
|
while line = @buf.slice!(/(.*)\r?\n/)
|
32
|
-
|
34
|
+
is_proxy = first_line && line.match?(/^PROXY TCP[4,6] /)
|
35
|
+
receive_line(line, ip_address) unless is_proxy
|
36
|
+
ip_address = line.split(/ /)[2] if is_proxy
|
37
|
+
|
38
|
+
first_line = false
|
33
39
|
end
|
34
40
|
end
|
35
41
|
|
36
42
|
# Invoked with lines received over the network
|
37
|
-
def receive_line(line)
|
38
|
-
call! Request.new(line,
|
43
|
+
def receive_line(line, ip_address)
|
44
|
+
call! Request.new(line, ip_address)
|
39
45
|
end
|
40
46
|
|
41
47
|
#
|
@@ -35,7 +35,7 @@ module Gopher
|
|
35
35
|
# @param [String] string text to add to the output
|
36
36
|
#
|
37
37
|
def <<(string)
|
38
|
-
@result << string.to_s
|
38
|
+
@result << clean_line(string.to_s)
|
39
39
|
end
|
40
40
|
|
41
41
|
#
|
@@ -89,7 +89,9 @@ module Gopher
|
|
89
89
|
# this is a hack - recombine lines, then re-split on newlines
|
90
90
|
# doing this because word_wrap is returning an array of lines, but
|
91
91
|
# those lines have newlines in them where we should wrap
|
92
|
-
|
92
|
+
#
|
93
|
+
lines = word_wrap(text, width)
|
94
|
+
.join("\n").split("\n")
|
93
95
|
|
94
96
|
lines.each do |line|
|
95
97
|
text line.lstrip.rstrip
|
@@ -206,6 +208,19 @@ module Gopher
|
|
206
208
|
end
|
207
209
|
end
|
208
210
|
|
211
|
+
#
|
212
|
+
# handle lines of a single period not at the end of the
|
213
|
+
# transmission
|
214
|
+
#
|
215
|
+
# RFC 1436 states: Note: Lines beginning with
|
216
|
+
# periods must be prepended with an extra period to
|
217
|
+
# ensure that the transmission is not terminated
|
218
|
+
# early. The client should strip extra periods at
|
219
|
+
# the beginning of the line.
|
220
|
+
def clean_line(line)
|
221
|
+
line.match?(/^\./) ? ['.', line].join('') : line
|
222
|
+
end
|
223
|
+
|
209
224
|
private
|
210
225
|
def add_spacing
|
211
226
|
br(@spacing)
|
data/lib/gopher2000/request.rb
CHANGED
@@ -7,12 +7,21 @@ module Gopher
|
|
7
7
|
attr_accessor :selector, :input, :ip_address
|
8
8
|
|
9
9
|
def initialize(raw, ip_addr=nil)
|
10
|
-
@
|
10
|
+
@raw = raw
|
11
|
+
@selector, @input = @raw.chomp.split("\t")
|
12
|
+
|
13
|
+
@selector = Gopher::Application.sanitize_selector(@selector)
|
14
|
+
@ip_address = ip_addr
|
15
|
+
end
|
11
16
|
|
12
|
-
|
13
|
-
|
17
|
+
def url?
|
18
|
+
@raw =~ /^URL\:/
|
14
19
|
end
|
15
20
|
|
21
|
+
def url
|
22
|
+
@raw.chomp.split("\t").first.gsub(/^URL\:/, '')
|
23
|
+
end
|
24
|
+
|
16
25
|
# confirm that this is actually a valid gopher request
|
17
26
|
# @return [Boolean] true if the request is valid, false otherwise
|
18
27
|
def valid?
|
data/lib/gopher2000/server.rb
CHANGED
@@ -13,7 +13,7 @@ module Gopher
|
|
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/dispatching_spec.rb
CHANGED
@@ -51,6 +51,7 @@ describe Gopher::Application do
|
|
51
51
|
|
52
52
|
@response = @server.dispatch(@request)
|
53
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
|
@@ -59,6 +60,7 @@ describe Gopher::Application do
|
|
59
60
|
|
60
61
|
@response = @server.dispatch(@request)
|
61
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
|
@@ -67,6 +69,7 @@ describe Gopher::Application do
|
|
67
69
|
|
68
70
|
@response = @server.dispatch(@request)
|
69
71
|
expect(@response.code).to eq(:error)
|
72
|
+
expect(@response.body).to contain_any_error
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
@@ -127,7 +130,17 @@ describe Gopher::Application do
|
|
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
|
@@ -142,3 +155,11 @@ describe Gopher::Application do
|
|
142
155
|
end
|
143
156
|
end
|
144
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$/)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
data/spec/dsl_spec.rb
CHANGED
@@ -14,103 +14,112 @@ describe Gopher::DSL do
|
|
14
14
|
|
15
15
|
@server = FakeServer.new(@app)
|
16
16
|
@server.send :require, 'gopher2000/dsl'
|
17
|
-
allow(@server).to receive(:application).and_return(@app)
|
18
|
-
@app.reset!
|
19
17
|
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@server.set :foo, 'bar'
|
25
|
-
expect(@app.config[:foo]).to eq('bar')
|
19
|
+
describe "application" do
|
20
|
+
it "should return a Gopher::Application" do
|
21
|
+
expect(@server.application).to be_a(Gopher::Application)
|
26
22
|
end
|
27
23
|
end
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
@
|
33
|
-
|
25
|
+
context "with application" do
|
26
|
+
before do
|
27
|
+
allow(@server).to receive(:application).and_return(@app)
|
28
|
+
@app.reset!
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "set" do
|
32
|
+
it "should set a config var" do
|
33
|
+
@server.set :foo, 'bar'
|
34
|
+
expect(@app.config[:foo]).to eq('bar')
|
34
35
|
end
|
35
36
|
end
|
36
|
-
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
describe "route" do
|
39
|
+
it "should pass a lookup and block to the app" do
|
40
|
+
expect(@app).to receive(:route).with('/foo')
|
41
|
+
@server.route '/foo' do
|
42
|
+
"hi"
|
43
|
+
end
|
43
44
|
end
|
44
45
|
end
|
45
|
-
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
47
|
+
describe "default_route" do
|
48
|
+
it "should pass a default block to the app" do
|
49
|
+
expect(@app).to receive(:default_route)
|
50
|
+
@server.default_route do
|
51
|
+
"hi"
|
52
|
+
end
|
53
|
+
end
|
51
54
|
end
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
+
describe "mount" do
|
57
|
+
it "should pass a route, path, and some opts to the app" do
|
58
|
+
expect(@app).to receive(:mount).with('/foo', {:path => "/bar"})
|
59
|
+
@server.mount "/foo" => "/bar"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should pass a route, path, filter, and some opts to the app" do
|
63
|
+
expect(@app).to receive(:mount).with('/foo', {:path => "/bar", :filter => "*.jpg"})
|
64
|
+
@server.mount "/foo" => "/bar", :filter => "*.jpg"
|
65
|
+
end
|
56
66
|
end
|
57
|
-
end
|
58
67
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
68
|
+
describe "menu" do
|
69
|
+
it "should pass a menu key and block to the app" do
|
70
|
+
expect(@app).to receive(:menu).with('/foo')
|
71
|
+
@server.menu '/foo' do
|
72
|
+
"hi"
|
73
|
+
end
|
64
74
|
end
|
65
75
|
end
|
66
|
-
end
|
67
76
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
77
|
+
describe "text" do
|
78
|
+
it "should pass a text_template key and block to the app" do
|
79
|
+
expect(@app).to receive(:text).with('/foo')
|
80
|
+
@server.text '/foo' do
|
81
|
+
"hi"
|
82
|
+
end
|
73
83
|
end
|
74
84
|
end
|
75
|
-
end
|
76
85
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
86
|
+
describe "helpers" do
|
87
|
+
it "should pass a block to the app" do
|
88
|
+
expect(@app).to receive(:helpers)
|
89
|
+
@server.helpers do
|
90
|
+
"hi"
|
91
|
+
end
|
82
92
|
end
|
83
93
|
end
|
84
|
-
end
|
85
94
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
95
|
+
describe "watch" do
|
96
|
+
it "should pass a script app for watching" do
|
97
|
+
expect(@app.scripts).to receive(:<<).with("foo")
|
98
|
+
@server.watch("foo")
|
99
|
+
end
|
90
100
|
end
|
91
|
-
end
|
92
101
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
102
|
+
describe "run" do
|
103
|
+
it "should set any incoming opts" do
|
104
|
+
expect(@server).to receive(:set).with(:x, 1)
|
105
|
+
expect(@server).to receive(:set).with(:y, 2)
|
106
|
+
allow(@server).to receive(:load)
|
98
107
|
|
99
|
-
|
100
|
-
|
108
|
+
@server.run("foo", {:x => 1, :y => 2})
|
109
|
+
end
|
101
110
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
111
|
+
it "should turn on script watching if in debug mode" do
|
112
|
+
@app.config[:debug] = true
|
113
|
+
expect(@server).to receive(:watch).with("foo.rb")
|
114
|
+
expect(@server).to receive(:load).with("foo.rb")
|
106
115
|
|
107
|
-
|
108
|
-
|
116
|
+
@server.run("foo.rb")
|
117
|
+
end
|
109
118
|
|
110
|
-
|
111
|
-
|
112
|
-
|
119
|
+
it "should load the script" do
|
120
|
+
expect(@server).to receive(:load).with("foo.rb")
|
121
|
+
@server.run("foo.rb")
|
122
|
+
end
|
113
123
|
end
|
114
124
|
end
|
115
|
-
|
116
125
|
end
|
data/spec/rendering/base_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe Gopher::Rendering::Base do
|
|
10
10
|
@ctx.text("line 2")
|
11
11
|
expect(@ctx.result).to eq("line 1\r\nline 2\r\n")
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
it "should add breaks correctly" do
|
15
15
|
@ctx.spacing 2
|
16
16
|
@ctx.text("line 1")
|
@@ -18,6 +18,13 @@ describe Gopher::Rendering::Base do
|
|
18
18
|
expect(@ctx.result).to eq("line 1\r\n\r\nline 2\r\n\r\n")
|
19
19
|
end
|
20
20
|
|
21
|
+
it "should add extra period to lines beginning with period" do
|
22
|
+
@ctx.text("line 1")
|
23
|
+
@ctx.text(".")
|
24
|
+
@ctx.text("line 2")
|
25
|
+
expect(@ctx.result).to eq("line 1\r\n..\r\nline 2\r\n")
|
26
|
+
end
|
27
|
+
|
21
28
|
it "br outputs a bunch of newlines" do
|
22
29
|
expect(@ctx.br(2)).to eq("\r\n\r\n")
|
23
30
|
end
|
@@ -60,7 +67,12 @@ describe Gopher::Rendering::Base do
|
|
60
67
|
describe "block" do
|
61
68
|
it "wraps text" do
|
62
69
|
expect(@ctx).to receive(:text).twice.with "a"
|
63
|
-
@ctx.block("a a",1)
|
70
|
+
@ctx.block("a a", 1)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "handles stray period" do
|
74
|
+
@ctx.block("a a .", 1)
|
75
|
+
expect(@ctx.result).to eq("a\r\na\r\n..\r\n")
|
64
76
|
end
|
65
77
|
end
|
66
78
|
end
|
data/spec/rendering/menu_spec.rb
CHANGED
@@ -54,9 +54,25 @@ describe Gopher::Rendering::Menu do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
describe "link" do
|
57
|
-
|
58
|
-
|
59
|
-
|
57
|
+
context "with filepath" do
|
58
|
+
it "should get type with determine_type" do
|
59
|
+
expect(@ctx).to receive(:determine_type).with("foo.txt").and_return("A")
|
60
|
+
expect(@ctx.link("FILE", "thing", "external-server.com", 70, "foo.txt")).to eq("AFILE\tthing\texternal-server.com\t70\r\n")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "without filepath" do
|
65
|
+
it "should get type with determine_type" do
|
66
|
+
expect(@ctx).to receive(:determine_type).with("foo.txt").and_return("A")
|
67
|
+
expect(@ctx.link("FILE", "foo.txt")).to eq("AFILE\tfoo.txt\thost\t1234\r\n")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "text_link" do
|
74
|
+
it "should work" do
|
75
|
+
expect(@ctx.text_link("text link", "/files/foo.txt")).to eq("0text link\t/files/foo.txt\thost\t1234\r\n")
|
60
76
|
end
|
61
77
|
end
|
62
78
|
|
data/spec/request_spec.rb
CHANGED
@@ -32,4 +32,10 @@ describe Gopher::Request do
|
|
32
32
|
request = Gopher::Request.new("x" * 255, "bar")
|
33
33
|
expect(request.valid?).to eq(false)
|
34
34
|
end
|
35
|
+
|
36
|
+
it 'detects urls' do
|
37
|
+
request = Gopher::Request.new("URL:http://github.com/muffinista/gopher2000")
|
38
|
+
expect(request).to be_url
|
39
|
+
expect(request.url).to eql('http://github.com/muffinista/gopher2000')
|
40
|
+
end
|
35
41
|
end
|