gopher 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +5 -0
- data/README +34 -0
- data/bin/gopher +20 -4
- data/lib/ext/module.rb~ +14 -0
- data/lib/gopher.rb +51 -40
- data/lib/gopher.rb~ +297 -0
- metadata +80 -48
- data/lib/ext/object.rb +0 -17
- data/spec/application_spec.rb +0 -42
- data/spec/ext_spec.rb +0 -1
- data/spec/gopher_spec.rb +0 -1
- data/spec/handler_spec.rb +0 -45
- data/spec/sandbox/indexed/cake.txt +0 -0
- data/spec/sandbox/recipe.txt +0 -0
- data/spec/spec_helper.rb +0 -2
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b61e25f16a3e9ce60e827a065bfdd71345856b6f0eda25852b90d4d2d9186163
|
4
|
+
data.tar.gz: f297cf6b2f0b6198ef0e8bc0f3b19f78c92bcd3ca477b0b61013b4d699c49cee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2bd00e1620cd8ad3cc5ef3a6a885bad5ac6b9ca8809ee308031dbc5bfad68f99d48c688712254d4e4e191913e3791cb6cd958bb093ca3d62a7c66853e30a0369
|
7
|
+
data.tar.gz: a6a9ad35dd09825214acf723eb572f8e3539ff3fe94335c9497a9069a611f3d501886e3e910b6a41fc1eb56c5127acc6c56a920bcd468f41f07159298c35ae6f
|
data/LICENSE
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
Copyright 2009 umeldt
|
2
|
+
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
4
|
+
|
5
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# gopher
|
2
|
+
|
3
|
+
a gopher server and a simple DSL for setting up servers
|
4
|
+
|
5
|
+
## installation
|
6
|
+
|
7
|
+
```bash
|
8
|
+
gem install foobar
|
9
|
+
```
|
10
|
+
|
11
|
+
## usage
|
12
|
+
|
13
|
+
set up a server using ruby
|
14
|
+
```ruby
|
15
|
+
gopher = Gopher.application do
|
16
|
+
host '0.0.0.0'
|
17
|
+
port 70
|
18
|
+
|
19
|
+
text '/time' do
|
20
|
+
line Time.now.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
mount '/', '/srv/gopher'
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
serve the current directory over gopher
|
28
|
+
```bash
|
29
|
+
gopher -p 70 -a 127.0.0.1
|
30
|
+
```
|
31
|
+
|
32
|
+
## license
|
33
|
+
[ISC](https://choosealicense.com/licenses/isc/)
|
34
|
+
|
data/bin/gopher
CHANGED
@@ -3,12 +3,28 @@
|
|
3
3
|
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
4
4
|
|
5
5
|
require 'gopher'
|
6
|
+
require 'optparse'
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
options = {}
|
9
|
+
OptionParser.new do |opts|
|
10
|
+
opts.banner = "usage: gopher [options]"
|
11
|
+
|
12
|
+
opts.on("-a=ADDRESS", "bind to address") { |v| options[:address] = v }
|
13
|
+
opts.on("-p=PORT", "port") { |v| options[:port] = v }
|
14
|
+
end.parse!
|
15
|
+
|
16
|
+
gopher = Gopher.application do
|
17
|
+
host options[:address] || '0.0.0.0'
|
18
|
+
port options[:port] || 70
|
10
19
|
|
11
20
|
mount '/', '.'
|
12
21
|
end
|
13
22
|
|
14
|
-
|
23
|
+
begin
|
24
|
+
STDERR.puts "Launching gopher server on #{gopher.host}:#{gopher.port}"
|
25
|
+
Gopher.run
|
26
|
+
rescue SystemExit, Interrupt
|
27
|
+
STDERR.puts "Stopping server"
|
28
|
+
Gopher.stop
|
29
|
+
end
|
30
|
+
|
data/lib/ext/module.rb~
ADDED
data/lib/gopher.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'ext/object'
|
4
|
-
require 'ext/module'
|
1
|
+
require 'yaml'
|
5
2
|
|
6
3
|
require 'textwrap'
|
7
|
-
require 'yaml'
|
8
4
|
require 'eventmachine'
|
9
5
|
|
6
|
+
require_relative 'ext/module'
|
7
|
+
|
10
8
|
module Gopher
|
11
|
-
VERSION = '0.
|
9
|
+
VERSION = '0.6.0'
|
12
10
|
|
13
11
|
class Application
|
14
12
|
dsl_accessor :host, :port
|
@@ -26,15 +24,18 @@ module Gopher
|
|
26
24
|
end
|
27
25
|
|
28
26
|
def mount(selector, path)
|
29
|
-
add_handler "#{selector}/?(.*)",
|
27
|
+
add_handler "#{selector}/?(.*)",
|
28
|
+
DirectoryHandler.new(path, selector).with(self)
|
30
29
|
end
|
31
30
|
|
32
31
|
def map(selector, &block)
|
33
|
-
add_handler selector.gsub(/:(.+)/, '(.+)'),
|
32
|
+
add_handler selector.gsub(/:(.+)/, '(.+)'),
|
33
|
+
MapHandler.new(&block).with(self)
|
34
34
|
end
|
35
35
|
|
36
36
|
def text(selector, &block)
|
37
|
-
add_handler selector.gsub(/:(.+)/, '(.+)'),
|
37
|
+
add_handler selector.gsub(/:(.+)/, '(.+)'),
|
38
|
+
TextHandler.new(&block).with(self)
|
38
39
|
end
|
39
40
|
|
40
41
|
def helpers(&block)
|
@@ -42,9 +43,10 @@ module Gopher
|
|
42
43
|
TextContext.class_eval(&block)
|
43
44
|
end
|
44
45
|
|
45
|
-
def
|
46
|
+
def app(selector, handler)
|
46
47
|
add_handler selector, handler
|
47
48
|
end
|
49
|
+
alias_method :application, :app
|
48
50
|
|
49
51
|
def request(selector)
|
50
52
|
handler, *args = lookup(selector)
|
@@ -71,15 +73,15 @@ module Gopher
|
|
71
73
|
end
|
72
74
|
|
73
75
|
class Handler
|
74
|
-
attr_accessor :
|
76
|
+
attr_accessor :app
|
75
77
|
|
76
|
-
def with(
|
77
|
-
@
|
78
|
+
def with(app)
|
79
|
+
@app = app
|
78
80
|
self
|
79
81
|
end
|
80
82
|
|
81
|
-
def host;
|
82
|
-
def port;
|
83
|
+
def host; app.respond_to?(:host) ? app.host : '0.0.0.0' end
|
84
|
+
def port; app.respond_to?(:port) ? app.port : 70 end
|
83
85
|
|
84
86
|
def call(*args); end
|
85
87
|
end
|
@@ -125,9 +127,9 @@ module Gopher
|
|
125
127
|
def call(*args)
|
126
128
|
path = File.join(base, *args)
|
127
129
|
if File.directory? path
|
128
|
-
|
130
|
+
DirectoryHandler.new(path, File.join(selector, args)).with(app).to_map
|
129
131
|
elsif File.file? path
|
130
|
-
|
132
|
+
File.open(path)
|
131
133
|
else
|
132
134
|
raise NotFound
|
133
135
|
end
|
@@ -195,7 +197,7 @@ module Gopher
|
|
195
197
|
new(host, port).instance_exec(*args, &block)
|
196
198
|
end
|
197
199
|
|
198
|
-
def line(type, txt, selector, host = host, port = port)
|
200
|
+
def line(type, txt, selector, host = self.host, port = self.port)
|
199
201
|
result << ["#{type}#{txt}", selector, host, port].join("\t")
|
200
202
|
result << "\r\n"
|
201
203
|
end
|
@@ -245,12 +247,12 @@ module Gopher
|
|
245
247
|
end
|
246
248
|
|
247
249
|
class Connection < EM::Connection
|
248
|
-
attr_accessor :
|
250
|
+
attr_accessor :app
|
249
251
|
|
250
252
|
def receive_data(data)
|
251
253
|
begin
|
252
254
|
raise InvalidRequest if data.length > 255
|
253
|
-
response =
|
255
|
+
response = app.request(data)
|
254
256
|
case response
|
255
257
|
when String then send_data(response)
|
256
258
|
when StringIO then send_data(response.read)
|
@@ -270,29 +272,38 @@ module Gopher
|
|
270
272
|
end
|
271
273
|
end
|
272
274
|
|
273
|
-
|
274
|
-
|
275
|
-
|
275
|
+
class <<self
|
276
|
+
def app(&block)
|
277
|
+
@app = Application.new(&block)
|
278
|
+
end
|
279
|
+
alias_method :application, :app
|
276
280
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
+
def reload(*files)
|
282
|
+
@last_reload = Time.now
|
283
|
+
@reloadables = files
|
284
|
+
end
|
281
285
|
|
282
|
-
|
283
|
-
|
284
|
-
|
286
|
+
def reloadables
|
287
|
+
@reloadables ||= []
|
288
|
+
end
|
285
289
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
290
|
+
def run
|
291
|
+
return if EM.reactor_running?
|
292
|
+
EM.run do
|
293
|
+
EM.start_server(@app.host, @app.port, Gopher::Connection) do |c|
|
294
|
+
c.app = @app
|
295
|
+
reloadables.each do |f|
|
296
|
+
load f if File.mtime(f) > @last_reload
|
297
|
+
end
|
298
|
+
@last_reload = Time.now
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def stop
|
304
|
+
return unless EM.reactor_running?
|
305
|
+
EM.stop_server
|
296
306
|
end
|
297
307
|
end
|
298
308
|
end
|
309
|
+
|
data/lib/gopher.rb~
ADDED
@@ -0,0 +1,297 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'ext/module'
|
4
|
+
|
5
|
+
require 'yaml'
|
6
|
+
require 'textwrap'
|
7
|
+
require 'eventmachine'
|
8
|
+
|
9
|
+
module Gopher
|
10
|
+
VERSION = '0.5.2'
|
11
|
+
|
12
|
+
class Application
|
13
|
+
dsl_accessor :host, :port
|
14
|
+
attr_accessor :selectors, :root
|
15
|
+
|
16
|
+
def initialize(&block)
|
17
|
+
reset!
|
18
|
+
self.instance_eval(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def reload(*f); Gopher.reload(*f) end
|
22
|
+
|
23
|
+
def use(mod)
|
24
|
+
extend(mod)
|
25
|
+
end
|
26
|
+
|
27
|
+
def mount(selector, path)
|
28
|
+
add_handler "#{selector}/?(.*)", DirectoryHandler.new(path, selector).with(self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def map(selector, &block)
|
32
|
+
add_handler selector.gsub(/:(.+)/, '(.+)'), MapHandler.new(&block).with(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
def text(selector, &block)
|
36
|
+
add_handler selector.gsub(/:(.+)/, '(.+)'), TextHandler.new(&block).with(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def helpers(&block)
|
40
|
+
MapContext.class_eval(&block)
|
41
|
+
TextContext.class_eval(&block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def application(selector, handler)
|
45
|
+
add_handler selector, handler
|
46
|
+
end
|
47
|
+
|
48
|
+
def request(selector)
|
49
|
+
handler, *args = lookup(selector)
|
50
|
+
handler.call(*args)
|
51
|
+
end
|
52
|
+
|
53
|
+
def lookup(selector)
|
54
|
+
selectors.find do |k, v|
|
55
|
+
return v, *$~[1..-1] if k =~ Gopher.sanitize_selector(selector)
|
56
|
+
end
|
57
|
+
raise NotFound
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_handler(selector, handler)
|
61
|
+
selector = Gopher.sanitize_selector(selector)
|
62
|
+
selector.sub!(/^\/*/, '')
|
63
|
+
selectors[/^\/?#{selector}$/] = handler
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def reset!
|
68
|
+
@selectors = {}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Handler
|
73
|
+
attr_accessor :application
|
74
|
+
|
75
|
+
def with(application)
|
76
|
+
@application = application
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def host; application.respond_to?(:host) ? application.host : '0.0.0.0' end
|
81
|
+
def port; application.respond_to?(:port) ? application.port : 70 end
|
82
|
+
|
83
|
+
def call(*args); end
|
84
|
+
end
|
85
|
+
|
86
|
+
class MapHandler < Handler
|
87
|
+
attr_accessor :block, :result
|
88
|
+
|
89
|
+
def initialize(&block)
|
90
|
+
@block = block
|
91
|
+
end
|
92
|
+
|
93
|
+
def call(*args)
|
94
|
+
context = MapContext.new(host, port)
|
95
|
+
context.instance_exec(*args, &block)
|
96
|
+
context.result
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class TextHandler < Handler
|
101
|
+
attr_accessor :block, :result
|
102
|
+
|
103
|
+
def initialize(&block)
|
104
|
+
@block = block
|
105
|
+
end
|
106
|
+
|
107
|
+
def call(*args)
|
108
|
+
context = TextContext.new
|
109
|
+
context.instance_exec(*args, &block)
|
110
|
+
context.result
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class DirectoryHandler < Handler
|
115
|
+
attr_accessor :base, :selector, :index
|
116
|
+
|
117
|
+
def initialize(path, selector = '')
|
118
|
+
raise DirectoryNotFound unless File.directory? path
|
119
|
+
@selector = selector
|
120
|
+
@base = File.expand_path(path)
|
121
|
+
@index = YAML.load_file(index_file) if File.exist?(index_file)
|
122
|
+
end
|
123
|
+
|
124
|
+
def call(*args)
|
125
|
+
path = File.join(base, *args)
|
126
|
+
if File.directory? path
|
127
|
+
return DirectoryHandler.new(path, File.join(selector, args)).with(application).to_map
|
128
|
+
elsif File.file? path
|
129
|
+
return File.open(path)
|
130
|
+
else
|
131
|
+
raise NotFound
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_map
|
136
|
+
MapContext.with_block(host, port, self) do |handler|
|
137
|
+
if handler.index
|
138
|
+
paragraph handler.index['description']
|
139
|
+
handler.index['entries'].each do |txt, path|
|
140
|
+
link txt, File.join(handler.selector, path)
|
141
|
+
end
|
142
|
+
else
|
143
|
+
Dir["#{handler.base}/*"].each do |path|
|
144
|
+
basename = File.basename(path)
|
145
|
+
if File.directory? path
|
146
|
+
map basename, File.join(handler.selector, basename)
|
147
|
+
else
|
148
|
+
link basename, File.join(handler.selector, basename)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
text Time.now
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
def index_file
|
158
|
+
File.join(base, '.gopher')
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class TextContext
|
163
|
+
attr_accessor :result
|
164
|
+
|
165
|
+
def line(text)
|
166
|
+
result << text
|
167
|
+
result << "\r\n"
|
168
|
+
end
|
169
|
+
|
170
|
+
def text(text)
|
171
|
+
line text
|
172
|
+
end
|
173
|
+
|
174
|
+
def paragraph(txt, width=70)
|
175
|
+
txt.each_line do |line|
|
176
|
+
Textwrap.wrap(line, width).each { |chunk| text chunk }
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def initialize
|
181
|
+
@result = ""
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class MapContext
|
186
|
+
attr_accessor :host, :port, :result
|
187
|
+
|
188
|
+
def initialize(host, port)
|
189
|
+
@host, @port = host, port
|
190
|
+
@result = ""
|
191
|
+
end
|
192
|
+
|
193
|
+
def self.with_block(host, port, *args, &block)
|
194
|
+
new(host, port).instance_exec(*args, &block)
|
195
|
+
end
|
196
|
+
|
197
|
+
def line(type, txt, selector, host = self.host, port = self.port)
|
198
|
+
result << ["#{type}#{txt}", selector, host, port].join("\t")
|
199
|
+
result << "\r\n"
|
200
|
+
end
|
201
|
+
|
202
|
+
def link(text, selector, *args)
|
203
|
+
type = Gopher.determine_type(selector)
|
204
|
+
line type, text, scrub(selector), *args
|
205
|
+
end
|
206
|
+
|
207
|
+
def map(text, selector, *args)
|
208
|
+
line '1', text, scrub(selector), *args
|
209
|
+
end
|
210
|
+
|
211
|
+
def text(text)
|
212
|
+
line 'i', text, 'false', '(NULL)', 0
|
213
|
+
end
|
214
|
+
|
215
|
+
def paragraph(txt, width=70)
|
216
|
+
txt.each_line do |line|
|
217
|
+
Textwrap.wrap(line, width).each { |chunk| text chunk }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
private
|
222
|
+
def scrub(s)
|
223
|
+
"/#{s.sub(/^\/+/,'')}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
class GopherError < StandardError; end
|
228
|
+
class DirectoryNotFound < GopherError; end
|
229
|
+
class NotFound < GopherError; end
|
230
|
+
class InvalidRequest < GopherError; end
|
231
|
+
|
232
|
+
def self.sanitize_selector(selector)
|
233
|
+
selector = selector.dup
|
234
|
+
selector.strip!
|
235
|
+
selector.gsub!(/\.+/, '.')
|
236
|
+
selector
|
237
|
+
end
|
238
|
+
def self.determine_type(selector)
|
239
|
+
case File.extname(selector).downcase
|
240
|
+
when '.jpg', '.png' then 'I'
|
241
|
+
when '.mp3' then 's'
|
242
|
+
else '0'
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
class Connection < EM::Connection
|
247
|
+
attr_accessor :application
|
248
|
+
|
249
|
+
def receive_data(data)
|
250
|
+
begin
|
251
|
+
raise InvalidRequest if data.length > 255
|
252
|
+
response = application.request(data)
|
253
|
+
case response
|
254
|
+
when String then send_data(response)
|
255
|
+
when StringIO then send_data(response.read)
|
256
|
+
when File
|
257
|
+
while chunk = response.read(8192) do
|
258
|
+
send_data(chunk)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
close_connection_after_writing
|
262
|
+
rescue Gopher::NotFound
|
263
|
+
send_data "not found"
|
264
|
+
close_connection_after_writing
|
265
|
+
rescue => e
|
266
|
+
close_connection
|
267
|
+
raise e
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def self.application(&block)
|
273
|
+
@application = Application.new(&block)
|
274
|
+
end
|
275
|
+
|
276
|
+
def self.reload(*files)
|
277
|
+
@last_reload = Time.now
|
278
|
+
@reloadables = files
|
279
|
+
end
|
280
|
+
|
281
|
+
def self.reloadables
|
282
|
+
@reloadables ||= []
|
283
|
+
end
|
284
|
+
|
285
|
+
def self.run
|
286
|
+
return if EM.reactor_running?
|
287
|
+
EM.run do
|
288
|
+
EM.start_server(@application.host, @application.port, Gopher::Connection) do |c|
|
289
|
+
c.application = @application
|
290
|
+
reloadables.each do |f|
|
291
|
+
load f if File.mtime(f) > @last_reload
|
292
|
+
end
|
293
|
+
@last_reload = Time.now
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
metadata
CHANGED
@@ -1,69 +1,101 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: gopher
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
|
-
authors:
|
7
|
-
-
|
6
|
+
authors:
|
7
|
+
- umeldt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
date: 2019-05-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: textwrap
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.1.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: eventmachine
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.2.0
|
34
|
+
- - "~>"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '1.2'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.2.0
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.2'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 10.4.2
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - '='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 10.4.2
|
61
|
+
description: ''
|
62
|
+
email: chris@svindseth.jp
|
63
|
+
executables:
|
19
64
|
- gopher
|
20
65
|
extensions: []
|
21
|
-
|
22
66
|
extra_rdoc_files: []
|
23
|
-
|
24
|
-
|
67
|
+
files:
|
68
|
+
- LICENSE
|
69
|
+
- README
|
25
70
|
- bin/gopher
|
26
|
-
- lib/ext
|
27
71
|
- lib/ext/module.rb
|
28
|
-
- lib/ext/
|
29
|
-
- lib/gopher
|
72
|
+
- lib/ext/module.rb~
|
73
|
+
- lib/gopher.rb
|
74
|
+
- lib/gopher.rb~
|
30
75
|
- lib/gopher/redirect.erb
|
31
76
|
- lib/gopher/redirect.rb
|
32
|
-
|
33
|
-
|
34
|
-
-
|
35
|
-
|
36
|
-
- spec/handler_spec.rb
|
37
|
-
- spec/sandbox
|
38
|
-
- spec/sandbox/indexed
|
39
|
-
- spec/sandbox/indexed/cake.txt
|
40
|
-
- spec/sandbox/recipe.txt
|
41
|
-
- spec/spec_helper.rb
|
42
|
-
has_rdoc: false
|
43
|
-
homepage: http://raspberry-style.net/
|
77
|
+
homepage: https://svindseth.jp/gopher
|
78
|
+
licenses:
|
79
|
+
- ISC
|
80
|
+
metadata: {}
|
44
81
|
post_install_message:
|
45
82
|
rdoc_options: []
|
46
|
-
|
47
|
-
require_paths:
|
83
|
+
require_paths:
|
48
84
|
- lib
|
49
|
-
|
50
|
-
|
85
|
+
- bin
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
51
88
|
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version:
|
54
|
-
|
55
|
-
|
56
|
-
requirements:
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
57
93
|
- - ">="
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version:
|
60
|
-
version:
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
61
96
|
requirements: []
|
62
|
-
|
63
|
-
rubyforge_project:
|
64
|
-
rubygems_version: 1.1.1
|
97
|
+
rubygems_version: 3.0.3
|
65
98
|
signing_key:
|
66
|
-
specification_version:
|
99
|
+
specification_version: 4
|
67
100
|
summary: gopher server and dsl
|
68
101
|
test_files: []
|
69
|
-
|
data/lib/ext/object.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# instance_exec for 1.8
|
2
|
-
# Grabbed from Mauricio Fernandez (thanks!)
|
3
|
-
# For more information, see http://eigenclass.org/hiki.rb?instance_exec
|
4
|
-
class Object
|
5
|
-
module InstanceExecHelper; end
|
6
|
-
include InstanceExecHelper
|
7
|
-
def instance_exec(*args, &block) # !> method redefined; discarding old instance_exec
|
8
|
-
mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
|
9
|
-
InstanceExecHelper.module_eval{ define_method(mname, &block) }
|
10
|
-
begin
|
11
|
-
ret = send(mname, *args)
|
12
|
-
ensure
|
13
|
-
InstanceExecHelper.module_eval{ undef_method(mname) } rescue nil
|
14
|
-
end
|
15
|
-
ret
|
16
|
-
end
|
17
|
-
end
|
data/spec/application_spec.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
-
|
3
|
-
describe Gopher::Application do
|
4
|
-
before(:all) do
|
5
|
-
@app = Gopher::Application.new do
|
6
|
-
host 'pha.hk'
|
7
|
-
port 7000
|
8
|
-
|
9
|
-
helpers do
|
10
|
-
def ruler
|
11
|
-
text ("=-" * 40)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
mount 'documents', File.dirname(__FILE__)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'should set the host' do
|
20
|
-
@app.host.should == 'pha.hk'
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'should set the port' do
|
24
|
-
@app.port.should == 7000
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'should mount directories' do
|
28
|
-
@app.lookup('/documents').should be_instance_of(Array)
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'should route properly to directories and their children' do
|
32
|
-
@app.lookup('/documents/tasty').should include("tasty")
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'should sanitize lookups' do
|
36
|
-
@app.lookup('/documents/.././tasty...html').should include("././tasty.html")
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'should add helpers' do
|
40
|
-
Gopher::MapContext.public_instance_methods.should include('ruler')
|
41
|
-
end
|
42
|
-
end
|
data/spec/ext_spec.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '/spec_helper')
|
data/spec/gopher_spec.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '/spec_helper')
|
data/spec/handler_spec.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '/spec_helper')
|
2
|
-
|
3
|
-
describe Gopher::DirectoryHandler do
|
4
|
-
before(:all) do
|
5
|
-
path = File.join(File.dirname(__FILE__), 'sandbox')
|
6
|
-
@handler = Gopher::DirectoryHandler.new(path)
|
7
|
-
end
|
8
|
-
|
9
|
-
it 'should barf on non-existent directories' do
|
10
|
-
proc { Gopher::DirectoryHandler.new(__FILE__) }.should raise_error(Gopher::DirectoryNotFound)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'should serve files under the directory' do
|
14
|
-
@handler.call('recipe.txt').should be_instance_of(File)
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'should raise a NotFound when files do not exist' do
|
18
|
-
proc { @handler.call('recipe.tx') }.should raise_error(Gopher::NotFound)
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'should serve generated directory maps' do
|
22
|
-
@handler.call('indexed').should include("An indexed directory")
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should serve directory indexes when applicable' do
|
26
|
-
@handler.call.should include("0recipe.txt\t/recipe.txt\t0.0.0.0\t70\r\n")
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe Gopher::MapHandler do
|
31
|
-
before(:all) do
|
32
|
-
@handler = Gopher::MapHandler.new do
|
33
|
-
text 'Cake recipes'
|
34
|
-
link 'Image', 'cake.jpg'
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'should add text' do
|
39
|
-
@handler.call.should include "iCake recipes\tfalse\t(NULL)\t0\r\n"
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'should add links and figure out the types' do
|
43
|
-
@handler.call.should include "IImage\t/cake.jpg\t0.0.0.0\t70\r\n"
|
44
|
-
end
|
45
|
-
end
|
File without changes
|
data/spec/sandbox/recipe.txt
DELETED
File without changes
|
data/spec/spec_helper.rb
DELETED