gopher2000 0.4.0 → 0.5.3
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 -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
|
+
[](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
|