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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 599d0bfe771be1795d77d08bd7fa8ef1df0b5c8ef89a6270d344aa9ad206e5ab
|
4
|
+
data.tar.gz: 64ee23ab4b4f63351c9572e19a995c5ca3da96919a79703e47a2830b9ddf6fba
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7c16b9f80341276ad4f93aacbbf505d01b3aea5264da1e3119d43a10ea0037984b4d423ca51ff9f174a9af805daf8e079a71686296b9baee12607c0767706c59
|
7
|
+
data.tar.gz: 20adee6253ced84ab8d4a8c4c7413874b6f034a0b3ae12a86418336fa04acf16ca81ffc19fef41c6c4bdb28c348c7960a1214a4d9563274a80075a81d72fffae
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.3
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,27 +1,12 @@
|
|
1
|
-
source
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in gopher.gemspec
|
1
|
+
source 'https://rubygems.org'
|
4
2
|
gemspec
|
5
3
|
|
6
4
|
gem "rake"
|
7
|
-
gem "logging"
|
8
5
|
|
9
6
|
# Add dependencies to develop your gem here.
|
10
7
|
# Include everything needed to run rake, tests, features, etc.
|
11
8
|
group :development do
|
12
|
-
gem 'simplecov', :require => false, :group => :test
|
13
|
-
|
14
|
-
gem "shoulda", ">= 0"
|
15
|
-
gem "rspec"
|
16
|
-
|
17
|
-
gem "bundler", "~> 1.0.0"
|
18
|
-
gem "watchr"
|
19
9
|
|
20
10
|
# There's a god example script stashed away in the repo
|
21
11
|
gem "god"
|
22
|
-
|
23
|
-
#
|
24
|
-
# gems used in examples and for development.
|
25
|
-
#
|
26
|
-
gem "weather-underground"
|
27
12
|
end
|
data/README.markdown
CHANGED
@@ -16,6 +16,8 @@ Gopher2000 - A Gopher server for the next millenium
|
|
16
16
|
Gopher2000 is a ruby-based Gopher server. It is built for speedy, enjoyable development of
|
17
17
|
all sorts of gopher sites.
|
18
18
|
|
19
|
+
[](https://travis-ci.org/muffinista/gopher2000)
|
20
|
+
|
19
21
|
Features
|
20
22
|
--------
|
21
23
|
* Simple, Sintra-inspired routing DSL.
|
@@ -57,7 +59,7 @@ 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
|
end
|
63
65
|
|
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/default_route.rb
CHANGED
File without changes
|
data/examples/figlet.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
#
|
5
|
+
# Simple gopher example
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'gopher2000'
|
9
|
+
|
10
|
+
set :host, '0.0.0.0'
|
11
|
+
set :port, 7070
|
12
|
+
|
13
|
+
route '/figlet' do
|
14
|
+
render :figlet
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# special text output rendering
|
19
|
+
#
|
20
|
+
text :figlet do
|
21
|
+
@text = "Hello!"
|
22
|
+
|
23
|
+
# nicely wrapped text
|
24
|
+
figlet @text
|
25
|
+
|
26
|
+
# spacing
|
27
|
+
br(2)
|
28
|
+
end
|
data/examples/nyan.rb
CHANGED
File without changes
|
data/examples/simple.rb
CHANGED
data/examples/twitter.rb
CHANGED
File without changes
|
data/examples/weather.rb
CHANGED
File without changes
|
data/gopher2000.gemspec
CHANGED
@@ -12,7 +12,6 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = %q{Gopher2000 - A Gopher server for the next millenium}
|
13
13
|
s.description = %q{Gopher2000 is a ruby-based Gopher server. It is built for speedy, enjoyable development of all sorts of gopher sites.}
|
14
14
|
|
15
|
-
s.rubyforge_project = "gopher2000"
|
16
15
|
s.licenses = ["WTFPL"]
|
17
16
|
|
18
17
|
s.files = `git ls-files`.split("\n")
|
@@ -26,10 +25,11 @@ Gem::Specification.new do |s|
|
|
26
25
|
s.add_development_dependency "yard"
|
27
26
|
s.add_development_dependency "shoulda"
|
28
27
|
s.add_development_dependency "rdoc"
|
29
|
-
s.add_development_dependency "simplecov"
|
28
|
+
s.add_development_dependency "simplecov", "~> 0.16.1"
|
30
29
|
s.add_development_dependency "watchr"
|
31
|
-
s.add_development_dependency "eventmachine"
|
32
30
|
|
33
|
-
s.add_runtime_dependency "
|
34
|
-
s.add_runtime_dependency "
|
31
|
+
s.add_runtime_dependency "artii", ">= 2.0.1"
|
32
|
+
s.add_runtime_dependency "eventmachine", "~> 1.2.5"
|
33
|
+
s.add_runtime_dependency "logging"
|
34
|
+
s.add_runtime_dependency "mimemagic"
|
35
35
|
end
|
data/lib/gopher2000.rb
CHANGED
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
|
#
|
@@ -91,9 +98,9 @@ module Gopher
|
|
91
98
|
#
|
92
99
|
# mount a directory for browsing via gopher
|
93
100
|
#
|
94
|
-
# @param [Hash] A hash specifying the path your route will answer to, and the filesystem path to use '/route' => '/home/path/etc'
|
95
|
-
#
|
96
|
-
|
101
|
+
# @param [Hash] path A hash specifying the path your route will answer to, and the filesystem path to use '/route' => '/home/path/etc'
|
102
|
+
# @param [Hash] opts a hash of options for the mount. Primarily this is a filter, which will restrict the list files outputted. example: :filter => '*.jpg'
|
103
|
+
# @param [Class] klass The class that should be used to handle this mount. You could write and use a custom handler if desired
|
97
104
|
#
|
98
105
|
# @example mount the directory '/home/user/foo' at the gopher path '/files', and only show JPG files:
|
99
106
|
# mount '/files' => '/home/user/foo', :filter => '*.jpg'
|
@@ -118,8 +125,7 @@ module Gopher
|
|
118
125
|
|
119
126
|
#
|
120
127
|
# define a route.
|
121
|
-
# @param [String] the path your route will answer to. This is
|
122
|
-
# basically a URI path
|
128
|
+
# @param [String] path the path your route will answer to. This is basically a URI path
|
123
129
|
# @yield a block that handles your route
|
124
130
|
#
|
125
131
|
# @example respond with a simple string
|
@@ -133,7 +139,7 @@ module Gopher
|
|
133
139
|
# end
|
134
140
|
#
|
135
141
|
def route(path, &block)
|
136
|
-
selector = sanitize_selector(path)
|
142
|
+
selector = Gopher::Application.sanitize_selector(path)
|
137
143
|
sig = compile!(selector, &block)
|
138
144
|
|
139
145
|
debug_log("Add route for #{selector}")
|
@@ -145,6 +151,7 @@ module Gopher
|
|
145
151
|
|
146
152
|
#
|
147
153
|
# specify a default route to handle requests if no other route exists
|
154
|
+
# @yield a block to handle the default route
|
148
155
|
#
|
149
156
|
# @example render a template
|
150
157
|
# default_route do
|
@@ -158,16 +165,15 @@ module Gopher
|
|
158
165
|
#
|
159
166
|
# lookup an incoming path
|
160
167
|
#
|
161
|
-
# @param [String] the selector path of the incoming request
|
168
|
+
# @param [String] selector the selector path of the incoming request
|
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
|
#
|
@@ -190,7 +196,7 @@ module Gopher
|
|
190
196
|
|
191
197
|
#
|
192
198
|
# find and run the first route which matches the incoming request
|
193
|
-
# @param [Request] Gopher::Request object
|
199
|
+
# @param [Request] req Gopher::Request object
|
194
200
|
#
|
195
201
|
def dispatch(req)
|
196
202
|
debug_log(req)
|
@@ -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}")
|
@@ -233,11 +242,11 @@ module Gopher
|
|
233
242
|
# define a template which will be used to render a gopher-style
|
234
243
|
# menu.
|
235
244
|
#
|
236
|
-
# @param [String/Symbol]
|
237
|
-
#
|
245
|
+
# @param [String/Symbol] name the name of the template. This is what
|
246
|
+
# identifies the template when making a call to render
|
238
247
|
# @yield a block which will output the menu. This block is
|
239
|
-
#
|
240
|
-
#
|
248
|
+
# executed within an instance of Gopher::Rendering::Menu and will
|
249
|
+
# have access to all of its methods.
|
241
250
|
#
|
242
251
|
# @example a simple menu:
|
243
252
|
# menu :index do
|
@@ -273,7 +282,7 @@ module Gopher
|
|
273
282
|
# access to the methods defined in Gopher::Rendering::Text for
|
274
283
|
# wrapping strings, adding simple headers, etc.
|
275
284
|
#
|
276
|
-
# @param [String/Symbol]
|
285
|
+
# @param [String/Symbol] name the name of the template. This is what identifies the template when making a call to render
|
277
286
|
#
|
278
287
|
# @yield a block which will output the menu. This block is executed within an instance of Gopher::Rendering::Text and will have access to all of its methods.
|
279
288
|
# @example simple example
|
@@ -295,7 +304,7 @@ module Gopher
|
|
295
304
|
|
296
305
|
#
|
297
306
|
# find a template
|
298
|
-
# @param [String/Symbol] name of the template
|
307
|
+
# @param [String/Symbol] t name of the template
|
299
308
|
# @return template block and the class context it should use
|
300
309
|
#
|
301
310
|
def find_template(t)
|
@@ -311,8 +320,8 @@ module Gopher
|
|
311
320
|
|
312
321
|
#
|
313
322
|
# Find the desired template and call it within the proper context
|
314
|
-
# @param [String/Symbol] name of the template to render
|
315
|
-
# @param [Array] optional arguments to be passed to template
|
323
|
+
# @param [String/Symbol] template name of the template to render
|
324
|
+
# @param [Array] arguments optional arguments to be passed to template
|
316
325
|
# @return result of rendering
|
317
326
|
#
|
318
327
|
def render(template, *arguments)
|
@@ -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
|
@@ -385,7 +403,7 @@ module Gopher
|
|
385
403
|
# Gopher servers in production)
|
386
404
|
#
|
387
405
|
def non_blocking?
|
388
|
-
config[:non_blocking]
|
406
|
+
config.key?(:non_blocking) ? config[:non_blocking] : ! debug_mode?
|
389
407
|
end
|
390
408
|
|
391
409
|
|
@@ -411,7 +429,7 @@ module Gopher
|
|
411
429
|
# turn a path string with optional keys (/foo/:bar/:boo) into a
|
412
430
|
# regexp which will be used when searching for a route
|
413
431
|
#
|
414
|
-
# @param [String] the path to compile
|
432
|
+
# @param [String] path the path to compile
|
415
433
|
#
|
416
434
|
def compile(path)
|
417
435
|
keys = []
|
@@ -428,23 +446,25 @@ module Gopher
|
|
428
446
|
[/^#{pattern}$/, keys]
|
429
447
|
end
|
430
448
|
|
431
|
-
#
|
432
|
-
# Sanitizes a gopher selector
|
433
|
-
#
|
434
|
-
def sanitize_selector(raw)
|
435
|
-
raw.to_s.dup.
|
436
|
-
strip. # Strip whitespace
|
437
|
-
sub(/\/$/, ''). # Strip last rslash
|
438
|
-
sub(/^\/*/, '/'). # Strip extra lslashes
|
439
|
-
gsub(/\.+/, '.') # Don't want consecutive dots!
|
440
|
-
end
|
441
449
|
|
442
450
|
class << self
|
443
|
-
|
451
|
+
|
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
|
+
#
|
444
464
|
# generate a method which we will use to run routes. this is
|
445
465
|
# based on #generate_method as used by sinatra.
|
446
466
|
# @see https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb
|
447
|
-
# @param [String] name to use for the method
|
467
|
+
# @param [String] method_name name to use for the method
|
448
468
|
# @yield block to use for the method
|
449
469
|
def generate_method(method_name, &block)
|
450
470
|
define_method(method_name, &block)
|
@@ -453,7 +473,7 @@ module Gopher
|
|
453
473
|
method
|
454
474
|
end
|
455
475
|
end
|
456
|
-
|
476
|
+
|
457
477
|
#
|
458
478
|
# output a debugging message
|
459
479
|
#
|
@@ -470,15 +490,37 @@ module Gopher
|
|
470
490
|
#
|
471
491
|
def register_defaults
|
472
492
|
menu :'internal/not_found' do
|
473
|
-
|
493
|
+
error "Sorry, #{@request.selector} was not found"
|
474
494
|
end
|
475
495
|
|
476
496
|
menu :'internal/error' do |details|
|
477
|
-
|
497
|
+
error "Sorry, there was an error #{details}"
|
478
498
|
end
|
479
499
|
|
480
500
|
menu :'internal/invalid_request' do
|
481
|
-
|
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
|
482
524
|
end
|
483
525
|
end
|
484
526
|
|
@@ -486,6 +528,10 @@ module Gopher
|
|
486
528
|
render not_found_template
|
487
529
|
end
|
488
530
|
|
531
|
+
def handle_url(request)
|
532
|
+
render url_template, request
|
533
|
+
end
|
534
|
+
|
489
535
|
def handle_error(e)
|
490
536
|
render error_template, e
|
491
537
|
end
|
@@ -22,16 +22,25 @@ module Gopher
|
|
22
22
|
#
|
23
23
|
# called by EventMachine when there's an incoming request
|
24
24
|
#
|
25
|
-
# @param [String] incoming selector
|
25
|
+
# @param [String] selector incoming selector
|
26
26
|
# @return Response object
|
27
27
|
#
|
28
|
-
def receive_data
|
29
|
-
|
28
|
+
def receive_data data
|
29
|
+
(@buf ||= '') << data
|
30
|
+
|
31
|
+
while line = @buf.slice!(/(.*)\r?\n/)
|
32
|
+
receive_line(line)
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
36
|
+
# Invoked with lines received over the network
|
37
|
+
def receive_line(line)
|
38
|
+
call! Request.new(line, remote_ip)
|
39
|
+
end
|
40
|
+
|
32
41
|
#
|
33
42
|
# generate a request object from an incoming selector, and dispatch it to the app
|
34
|
-
# @param [
|
43
|
+
# @param [Request] request Request object to handle
|
35
44
|
# @return Response object
|
36
45
|
#
|
37
46
|
def call!(request)
|