gopher2000 0.4.0 → 0.5.3
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 -15
- data/README.markdown +2 -0
- data/examples/default_route.rb +0 -0
- data/examples/figlet.rb +0 -0
- data/examples/nyan.rb +0 -0
- data/examples/simple.rb +0 -0
- data/examples/twitter.rb +0 -0
- data/examples/weather.rb +0 -0
- data/gopher2000.gemspec +3 -4
- data/lib/gopher2000/base.rb +1 -1
- data/lib/gopher2000/dispatcher.rb +11 -2
- data/lib/gopher2000/handlers/directory_handler.rb +1 -1
- data/lib/gopher2000/rendering/base.rb +37 -35
- data/lib/gopher2000/rendering/menu.rb +103 -14
- data/lib/gopher2000/version.rb +1 -1
- data/spec/application_spec.rb +12 -12
- data/spec/dispatching_spec.rb +17 -17
- data/spec/dsl_spec.rb +16 -16
- data/spec/handlers/directory_handler_spec.rb +35 -35
- data/spec/helpers_spec.rb +1 -1
- data/spec/rendering/base_spec.rb +10 -10
- data/spec/rendering/menu_spec.rb +23 -17
- data/spec/rendering_spec.rb +7 -7
- data/spec/request_spec.rb +8 -8
- data/spec/response_spec.rb +5 -5
- data/spec/routing_spec.rb +21 -21
- data/spec/server_spec.rb +6 -6
- metadata +110 -70
- data/.rvmrc +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6c507fab7aaa1412d98ac4a18870fe786098aa9aa4e393bd1204cc476f111dfb
|
4
|
+
data.tar.gz: e767f8ea12042fc19a7c6f6fc25766b3d91838f053abf1abe97b17b8c99da4e5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3497713e468d3d6eefecafcb68cc7421c8af9db40bcd0e30c865f54e1a8a0e8ab0a8098fa8f5369a518cf4dfd391612ba3ada0d4a4ba51b17240934fa500275d
|
7
|
+
data.tar.gz: 89145000523a7d3d7c77ebad777a0421211b05edfe973c4bc3cbe45ea37d2541bfd773be0ed2c86cf114a0a6c47c1fa6a8e64b2ab76e9a8d278423d5b19cb80b
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.3
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,6 +1,4 @@
|
|
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"
|
@@ -8,19 +6,7 @@ gem "rake"
|
|
8
6
|
# Add dependencies to develop your gem here.
|
9
7
|
# Include everything needed to run rake, tests, features, etc.
|
10
8
|
group :development do
|
11
|
-
gem 'simplecov', :require => false, :group => :test
|
12
|
-
|
13
|
-
gem "shoulda", ">= 0"
|
14
|
-
gem "rspec"
|
15
|
-
|
16
|
-
gem "bundler", "~> 1.0.0"
|
17
|
-
gem "watchr"
|
18
9
|
|
19
10
|
# There's a god example script stashed away in the repo
|
20
11
|
gem "god"
|
21
|
-
|
22
|
-
#
|
23
|
-
# gems used in examples and for development.
|
24
|
-
#
|
25
|
-
gem "weather-underground"
|
26
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.
|
data/examples/default_route.rb
CHANGED
File without changes
|
data/examples/figlet.rb
CHANGED
File without changes
|
data/examples/nyan.rb
CHANGED
File without changes
|
data/examples/simple.rb
CHANGED
File without changes
|
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,11 +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
31
|
s.add_runtime_dependency "artii", ">= 2.0.1"
|
34
|
-
s.add_runtime_dependency "eventmachine"
|
32
|
+
s.add_runtime_dependency "eventmachine", "~> 1.2.5"
|
35
33
|
s.add_runtime_dependency "logging"
|
34
|
+
s.add_runtime_dependency "mimemagic"
|
36
35
|
end
|
data/lib/gopher2000/base.rb
CHANGED
@@ -25,10 +25,19 @@ module Gopher
|
|
25
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
43
|
# @param [Request] request Request object to handle
|
@@ -96,7 +96,7 @@ module Gopher
|
|
96
96
|
# iterate through the contents of this directory.
|
97
97
|
# NOTE: we don't filter this, so we will ALWAYS list subdirectories of a mounted folder
|
98
98
|
#
|
99
|
-
Dir.glob("#{dir}
|
99
|
+
Dir.glob("#{dir}/*").each do |x|
|
100
100
|
# if this is a directory, then generate a directory link for it
|
101
101
|
if File.directory?(x)
|
102
102
|
m.directory File.basename(x), to_selector(x), @application.host, @application.port
|
@@ -5,12 +5,14 @@ module Gopher
|
|
5
5
|
#
|
6
6
|
module Rendering
|
7
7
|
|
8
|
-
|
8
|
+
require 'artii'
|
9
9
|
|
10
10
|
# "A CR LF denotes the end of the item." RFC 1436
|
11
11
|
# @see http://www.faqs.org/rfcs/rfc1436.html
|
12
12
|
LINE_ENDING = "\r\n"
|
13
13
|
|
14
|
+
DEFAULT_ENCODING = 'UTF-8'
|
15
|
+
|
14
16
|
#
|
15
17
|
# base class for rendering output. this class provides methods
|
16
18
|
# that can be used when rendering both text and gopher menus
|
@@ -42,7 +44,7 @@ module Gopher
|
|
42
44
|
# then adds any required spacing
|
43
45
|
#
|
44
46
|
def text(text)
|
45
|
-
self << text
|
47
|
+
self << text.force_encoding(DEFAULT_ENCODING)
|
46
48
|
add_spacing
|
47
49
|
end
|
48
50
|
|
@@ -96,31 +98,31 @@ module Gopher
|
|
96
98
|
self.to_s
|
97
99
|
end
|
98
100
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
124
126
|
|
125
127
|
#
|
126
128
|
# output a centered string with a nice underline below it,
|
@@ -147,16 +149,16 @@ module Gopher
|
|
147
149
|
underline(@width, under)
|
148
150
|
end
|
149
151
|
|
150
|
-
|
151
|
-
|
152
|
+
#
|
153
|
+
# output a 'small' header, just the text with an underline
|
152
154
|
# @param [String] str - the string to output
|
153
155
|
# @param [String] under - the desired underline character
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
156
|
+
#
|
157
|
+
def small_header(str, under = '=')
|
158
|
+
str = " " + str + " "
|
159
|
+
text(str)
|
160
|
+
underline(str.length, under)
|
161
|
+
end
|
160
162
|
|
161
163
|
#
|
162
164
|
# output a centered string in a box
|
@@ -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
|
|
@@ -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/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
|