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
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
|
+
[![Build Status](https://travis-ci.org/muffinista/gopher2000.svg?branch=master)](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)
|