gopher2000 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +4 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +27 -0
  4. data/LICENSE.txt +14 -0
  5. data/README.markdown +344 -0
  6. data/Rakefile +38 -0
  7. data/bin/gopher2000 +51 -0
  8. data/examples/default_route.rb +22 -0
  9. data/examples/nyan.rb +62 -0
  10. data/examples/simple.rb +147 -0
  11. data/examples/twitter.rb +61 -0
  12. data/examples/weather.rb +69 -0
  13. data/gopher2000.gemspec +35 -0
  14. data/lib/gopher2000/base.rb +552 -0
  15. data/lib/gopher2000/dispatcher.rb +81 -0
  16. data/lib/gopher2000/dsl.rb +128 -0
  17. data/lib/gopher2000/errors.rb +14 -0
  18. data/lib/gopher2000/handlers/base_handler.rb +18 -0
  19. data/lib/gopher2000/handlers/directory_handler.rb +125 -0
  20. data/lib/gopher2000/rendering/abstract_renderer.rb +10 -0
  21. data/lib/gopher2000/rendering/base.rb +174 -0
  22. data/lib/gopher2000/rendering/menu.rb +129 -0
  23. data/lib/gopher2000/rendering/text.rb +10 -0
  24. data/lib/gopher2000/request.rb +21 -0
  25. data/lib/gopher2000/response.rb +25 -0
  26. data/lib/gopher2000/server.rb +85 -0
  27. data/lib/gopher2000/version.rb +4 -0
  28. data/lib/gopher2000.rb +33 -0
  29. data/scripts/god.rb +8 -0
  30. data/spec/application_spec.rb +54 -0
  31. data/spec/dispatching_spec.rb +144 -0
  32. data/spec/dsl_spec.rb +116 -0
  33. data/spec/gopher_spec.rb +1 -0
  34. data/spec/handlers/directory_handler_spec.rb +116 -0
  35. data/spec/helpers_spec.rb +16 -0
  36. data/spec/rendering/base_spec.rb +59 -0
  37. data/spec/rendering/menu_spec.rb +109 -0
  38. data/spec/rendering_spec.rb +84 -0
  39. data/spec/request_spec.rb +30 -0
  40. data/spec/response_spec.rb +33 -0
  41. data/spec/routing_spec.rb +92 -0
  42. data/spec/sandbox/old/socks.txt +0 -0
  43. data/spec/sandbox/socks.txt +0 -0
  44. data/spec/server_spec.rb +127 -0
  45. data/spec/spec_helper.rb +52 -0
  46. data/specs.watchr +60 -0
  47. metadata +211 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2-head@gopherpedia
data/Gemfile ADDED
@@ -0,0 +1,27 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gopher.gemspec
4
+ gemspec
5
+
6
+ gem "rake"
7
+ gem "logging"
8
+
9
+ # Add dependencies to develop your gem here.
10
+ # Include everything needed to run rake, tests, features, etc.
11
+ 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
+
20
+ # There's a god example script stashed away in the repo
21
+ gem "god"
22
+
23
+ #
24
+ # gems used in examples and for development.
25
+ #
26
+ gem "weather-underground"
27
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,14 @@
1
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ Version 2, December 2004
3
+
4
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5
+
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
+
13
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
14
+
data/README.markdown ADDED
@@ -0,0 +1,344 @@
1
+ It's...
2
+
3
+ _____ _ _____ _____ _____ _____
4
+ | __ \ | | / __ \| _ || _ || _ |
5
+ | | \/ ___ _ __ | |__ ___ _ __ `' / /'| |/' || |/' || |/' |
6
+ | | __ / _ \| '_ \| '_ \ / _ \ '__| / / | /| || /| || /| |
7
+ | |_\ \ (_) | |_) | | | | __/ | ./ /___\ |_/ /\ |_/ /\ |_/ /
8
+ \____/\___/| .__/|_| |_|\___|_| \_____/ \___/ \___/ \___/
9
+ | |
10
+ |_|
11
+
12
+
13
+ Gopher2000 - A Gopher server for the next millenium
14
+ ===================================================
15
+
16
+ Gopher2000 is a ruby-based Gopher server. It is built for speedy, enjoyable development of
17
+ all sorts of gopher sites.
18
+
19
+ Features
20
+ --------
21
+ * Simple, Sintra-inspired routing DSL.
22
+ * Dynamic requests via named parameters on request paths.
23
+ * built on Event Machine.
24
+ * Easy to mount directories and serve up files.
25
+ * built in logging and stats.
26
+ * Runs on Ruby 1.9.2 with all the modern conveniences.
27
+
28
+ Requirements
29
+ ------------
30
+ * Ruby 1.9.2 or greater
31
+ * Nerves of steel
32
+
33
+ Examples
34
+ --------
35
+
36
+ Writing a functional Gopher app is as simple as:
37
+
38
+ ```rb
39
+ route '/simple' do
40
+ "hi" # You can output any text you want here
41
+ end
42
+ ```
43
+
44
+
45
+ Or, if you want to provide more interactivity, you can do something like:
46
+
47
+ ```rb
48
+ route '/' do
49
+ render :index
50
+ end
51
+
52
+ menu :index do
53
+ # output a text entry in the menu
54
+ text 'simple gopher example'
55
+
56
+ # use br(x) to add x space between lines
57
+ br(2)
58
+
59
+ # link somewhere
60
+ link 'current time', '/time'
61
+ br
62
+ end
63
+
64
+ route '/time' do
65
+ "It is currently #{Time.now}"
66
+ end
67
+ ```
68
+
69
+ You can see more working examples in the examples/ folder
70
+
71
+ Running a script
72
+ ----------------
73
+
74
+ You can use the supplied wrapper script
75
+
76
+ ```
77
+ gopher2000 -d examples/simple.rb
78
+
79
+ ==> *start server at 0.0.0.0 7070*
80
+ ```
81
+
82
+ Or, if you include gopher in your file, you can just run the script itself:
83
+
84
+ ```rb
85
+ # scriptname.rb
86
+ require 'gopher2000'
87
+
88
+ # ...
89
+ # write some code here
90
+ # ...
91
+
92
+ # Then, run 'ruby scriptname.rb'
93
+
94
+ ==> *start server at 0.0.0.0 7070*
95
+ ```
96
+ There are several command-line options:
97
+
98
+ * -d -- run in debug mode
99
+ * -p [port] -- which port to listen on
100
+ * -o [addr] -- what IP/host to listen on
101
+ * -e [env] -- what 'environment' to use -- this isn't really used by
102
+ Gopher2000, but you could use it when writing your app to determine
103
+ how you behave in production vs development, etc.
104
+
105
+ Command line options will override defaults specified in your script
106
+ -- so you can try out things on a different port/address if needed.
107
+
108
+
109
+ Developing Gopher Sites
110
+ -----------------------
111
+
112
+ Gopher2000 makes developing sites easy! Any time you change your
113
+ script, Gopher2000 will reload it. This way, you can make tweaks and
114
+ your site will be refreshed immediately. NOTE -- this is an
115
+ experimental feature, and might need some work.
116
+
117
+ Serving Files and Directories
118
+ -----------------------------
119
+
120
+ If you just want to serve up some files, there's a command for that:
121
+
122
+ ```rb
123
+ mount '/files' => '/home/username/files', :filter => '*.jpg'
124
+ ```
125
+
126
+ This will display a list of all the JPGs in the files directory.
127
+
128
+ Outputting Gopher Menus
129
+ -----------------------
130
+
131
+ There are a collection of commands to output Gopher menus (see
132
+ rendering/menu.rb for the code). The commands are:
133
+
134
+ **line(type, text, selector)** - output a line of type 'type' -- see
135
+ the RFC for the different types of links you can have.
136
+
137
+ **text** - output a line of text with no action on it.
138
+
139
+ **br(x)** - output x blank lines.
140
+
141
+ **error** - output an error message.
142
+
143
+ **directory** - (aliased as menu) output a link to a 'directory' -- this could be an
144
+ actual directory if you're building some sort of filesystem tree, or
145
+ a sub-menu for other actions in your app.
146
+
147
+ **link(text, selector)** - output a menu link to to the /selector path.
148
+
149
+ **search(text, selector)** -- output a link to a search action at
150
+ /selector.
151
+
152
+ Outputting Text
153
+ ---------------
154
+
155
+ If you would like to output text, but have the ability to format it
156
+ nicely, you can use a 'text' block like this:
157
+
158
+ ```rb
159
+ route '/prettytext' do
160
+ render :prettytext
161
+ end
162
+
163
+ #
164
+ # special text output rendering
165
+ #
166
+ text :prettytext do
167
+ @text = "A really long chunk of text. Lorem ipsum dolor sit amet ... nec massa."
168
+
169
+ # nicely wrapped text
170
+ block @text
171
+
172
+ # spacing
173
+ br(2)
174
+
175
+ # smaller line-width
176
+ block @text, 30
177
+ end
178
+
179
+ ```
180
+
181
+ A call to:
182
+
183
+ ```
184
+ echo "/prettytext" | ncat -C localhost 7070
185
+ ```
186
+
187
+ Will return your text, but with nice wrapping, etc.
188
+
189
+ @todo headers, etc.
190
+
191
+
192
+ Making It Pretty
193
+ ----------------
194
+
195
+ There are several helpers which you can call within render blocks to
196
+ help make your output a little shinier:
197
+
198
+ **width(x)** will set the width of your output. The default is 80
199
+ characters. You can change this to make your output wider or
200
+ thinner. This setting is used by **block** and also by the methods
201
+ described below.
202
+
203
+ **header(text, style='=')** will generate a very simple 'header', which is
204
+ basically the text you specify with an underline of the character
205
+ you specify. It will be centered in your output width, and will look
206
+ something like this:
207
+
208
+ Hello There!
209
+ =====================
210
+
211
+ **big_header** is the same as header, except it is bigger and better!
212
+
213
+ =====================
214
+ = Hello There! =
215
+ =====================
216
+
217
+ **underline** can be used to just output plain old lines, if you're
218
+ into that sort of thing.
219
+
220
+
221
+ Testing
222
+ -------
223
+
224
+ Here's some simple ways to test your server. First, you can always
225
+ just install a
226
+ [gopher client](http://lmgtfy.com/?q=gopher+clients). Or, if you like
227
+ to live on the edge, there's a few commands worth learning. First, you
228
+ can use [netcat](http://netcat.sourceforge.net/) to achieve
229
+ awesomeness. Here's some examples, assuming you're running the example
230
+ script on port 7070:
231
+
232
+
233
+ ```
234
+ #
235
+ # getting a menu listing
236
+ #
237
+
238
+ ~/Projects/gopher2000: echo "/" | nc localhost 7070
239
+ isimple gopher example null (FALSE) 0
240
+ i null (FALSE) 0
241
+ i null (FALSE) 0
242
+ 0current time /time 0.0.0.0 7070
243
+ i null (FALSE) 0
244
+ 0about /about 0.0.0.0 7070
245
+ i null (FALSE) 0
246
+ 7Hey, what is your name? /hello 0.0.0.0 7070
247
+ i null (FALSE) 0
248
+ 7echo test /echo_test 0.0.0.0 7070
249
+ i null (FALSE) 0
250
+ 1filez /files 0.0.0.0 7070
251
+
252
+ #
253
+ # getting a simple text response
254
+ #
255
+ ~/Projects/gopher2000: echo "/about" | nc localhost 7070
256
+ Gopher 2000 -- World Domination via Text Protocols
257
+ .
258
+ ```
259
+
260
+
261
+ Or, you can use the equally awesome [ncat](http://nmap.org/ncat/),
262
+ which is basically the successor to netcat. In general, I find that
263
+ ncat works better, particularly if you're using non-blocking
264
+ operations. Here's an example of it in operation:
265
+
266
+
267
+ ```
268
+ #
269
+ # Testing text output
270
+ #
271
+
272
+ ~/Projects/gopher2000: echo "/about" | ncat -C localhost 7070
273
+ Gopher 2000 -- World Domination via Text Protocols
274
+ .
275
+
276
+ #
277
+ # testing a route with some input
278
+ #
279
+
280
+ ~/Projects/gopher2000: echo "/hello\tcolin" | ncat -C localhost 7070
281
+ iHello, colin! null (FALSE) 0
282
+
283
+ .
284
+
285
+ ```
286
+
287
+
288
+
289
+ Logging
290
+ -------
291
+
292
+ Logging is pretty basic at the moment. Right now debug messages are
293
+ dumped to stderr. There's also an apache-esque access log, which can
294
+ be written to a file specified like this:
295
+
296
+ ```rb
297
+ set :access_log, "/tmp/access.log"
298
+ ```
299
+
300
+ The log will rollover daily, so your million hits per day won't
301
+ accumulate into an unmanageable file.
302
+
303
+ The format is a pretty basic tab-delimited file:
304
+
305
+ timestamp ip_address request_url result_code response_size
306
+ 2012-04-05 19:14:01 127.0.0.1 /lookup success 46
307
+
308
+ Non-Blocking Requests
309
+ ---------------------
310
+
311
+ When not running in debug mode, Gopher2000 will handle requests
312
+ without blocking -- this way, if you have an app that handles slow
313
+ requests, your users aren't held up waiting for other requests to
314
+ finish. However, this is somewhat experimental, so you can turn it off
315
+ by setting :non_blocking to be false in your script:
316
+
317
+ ```rb
318
+ set :non_blocking, false
319
+ ```
320
+
321
+ Also, non-blocking is always off in debug mode.
322
+
323
+ You probably need to be wary of this feature if you're actually
324
+ running a Gopher server that needs to be non-blocking. Read up on
325
+ EventMachine's defer feature if you need to learn more.
326
+
327
+
328
+ TODO
329
+ ----
330
+ * More examples
331
+ * Work on putting routing/rendering/etc into same context, and making
332
+ instance variables/methods generally available.
333
+ * Documentation
334
+ * clean up/improve EventMachine usage
335
+ * stats generation
336
+
337
+ References
338
+ ----------
339
+
340
+ * http://www.ietf.org/rfc/rfc1436.txt -- the original RFC for the
341
+ Gopher Protocol
342
+ * https://github.com/sinatra/sinatra -- almost everything good in this
343
+ library was taken or influenced by something in Sinatra. RUN don't
344
+ walk to the code and take a look.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ require 'bundler'
2
+ Bundler.setup :default, :test, :development
3
+
4
+ require "bundler/gem_tasks"
5
+ require 'rdoc/task'
6
+
7
+ require "gopher2000/version"
8
+
9
+ require 'rspec/core'
10
+ require 'rspec/core/rake_task'
11
+ RSpec::Core::RakeTask.new(:spec) do |spec|
12
+ spec.pattern = FileList['spec/**/*_spec.rb']
13
+ end
14
+
15
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
16
+ spec.pattern = 'spec/**/*_spec.rb'
17
+ spec.rcov_opts = %w{--exclude .bundler,.rvm}
18
+ spec.rcov = true
19
+ end
20
+
21
+ task :default => :spec
22
+
23
+ Bundler::GemHelper.install_tasks
24
+
25
+ begin
26
+ require 'yard'
27
+ YARD_OPTS = ['-m', 'markdown', '-M', 'redcarpet']
28
+ DOC_FILES = ['lib/**/*.rb', 'README.markdown']
29
+
30
+ YARD::Rake::YardocTask.new(:doc) do |t|
31
+ t.files = DOC_FILES
32
+ #t.options = YARD_OPTS
33
+
34
+ puts t.inspect
35
+ end
36
+ rescue LoadError
37
+ puts "You need to install YARD."
38
+ end
data/bin/gopher2000 ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # get rid of errors when running via bundle
5
+ # @see https://github.com/ddollar/foreman/issues/94
6
+ #
7
+ $stdout.sync = true
8
+
9
+ require 'optparse'
10
+ require 'gopher2000'
11
+
12
+ #
13
+ # pull in any arguments and set them as env variables
14
+ #
15
+ opts = OptionParser.new
16
+ opts.banner = <<-EOS
17
+
18
+ Run a gopher server!
19
+
20
+ Usage: #{File.basename($0)} [options] [scriptname]
21
+
22
+ EOS
23
+
24
+ opts.separator ""
25
+ opts.separator "Options:"
26
+
27
+ params = {
28
+ :debug => false,
29
+ :env => :production
30
+ }
31
+
32
+ opts.on('-d', '--debug', "run in debug mode") { params[:debug] = true }
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 }
35
+ opts.on('-e env', 'set the environment (default is development)') { |val| params[:env] = val.to_sym }
36
+
37
+ opts.on_tail("-h", "--help", "Show this message") do
38
+ puts opts
39
+ exit!
40
+ end
41
+
42
+ extra = opts.parse!(ARGV)
43
+
44
+ script = extra.shift
45
+
46
+ if script.nil?
47
+ puts "Sorry, you need to specify a script to run"
48
+ exit!
49
+ end
50
+
51
+ run script, params
@@ -0,0 +1,22 @@
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
+ # you can specify a destination for access log, for stats/etc
14
+ set :access_log, "/tmp/access.log"
15
+
16
+ route '/gopher' do
17
+ "Greetings from Gopher 2000!" # You can output any text you want here
18
+ end
19
+
20
+ default_route do
21
+ "I AM HERE"
22
+ end
data/examples/nyan.rb ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ #
5
+ # NYAN cat in gopherspace
6
+ #
7
+
8
+ require 'gopher2000'
9
+
10
+ set :host, '0.0.0.0'
11
+ set :port, 7070
12
+
13
+ route '/nyan' do
14
+
15
+ @cats = [
16
+ " + o + o
17
+ + o + +
18
+ o +
19
+ o + + +
20
+ + o o + o
21
+ -_-_-_-_-_-_-_,------, o
22
+ _-_-_-_-_-_-_-| /\\_/\\
23
+ -_-_-_-_-_-_-~|__( ^ .^) + +
24
+ _-_-_-_-_-_-_-\"\" \"\"
25
+ + o o + o
26
+ + +
27
+ o o o o +
28
+ o +
29
+ + + o o + ",
30
+
31
+ " o + + +
32
+ o + o
33
+ o +
34
+ + o + o
35
+ o + o +
36
+ _-_-_-_-_-_-_-,------, o +
37
+ -_-_-_-_-_-_-_| /\\_/\\ +
38
+ _-_-_-_-_-_-_~|__( ^ .^) o
39
+ -_-_-_-_-_-_-_ \"\" \"\"
40
+ + + o o +
41
+ o + o +
42
+ + o + + o
43
+ + +
44
+ + o + ",
45
+
46
+ "░░▓▓░░░░░░░░▓▓░░
47
+ ░▓▒▒▓░░░░░░▓▒▒▓░
48
+ ░▓▒▒▒▓░░░░▓▒▒▒▓░
49
+ ░▓▒▒▒▒▓▓▓▓▒▒▒▒▓░
50
+ ░▓▒▒▒▒▒▒▒▒▒▒▒▒▒▓
51
+ ▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓
52
+ ▓▒▒▒░▓▒▒▒▒▒░▓▒▒▓
53
+ ▓▒▒▒▓▓▒▒▒▓▒▓▓▒▒▓
54
+ ▓▒░░▒▒▒▒▒▒▒▒▒░░▓
55
+ ▓▒░░▒▓▒▒▓▒▒▓▒░░▓
56
+ ░▓▒▒▒▓▓▓▓▓▓▓▒▒▓░
57
+ ░░▓▒▒▒▒▒▒▒▒▒▒▓░░
58
+ ░░░▓▓▓▓▓▓▓▓▓▓░░░"
59
+ ]
60
+
61
+ @cats.sample
62
+ end