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 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
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.1
5
+ - 2.3.3
6
+ - 2.4.2
7
+ # uncomment this line if your project needs to run something other than `rake`:
8
+ # script: bundle exec rspec spec
data/Gemfile CHANGED
@@ -1,6 +1,4 @@
1
- source "http://rubygems.org"
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.
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
@@ -385,7 +385,7 @@ module Gopher
385
385
  # Gopher servers in production)
386
386
  #
387
387
  def non_blocking?
388
- config[:non_blocking] ||= ! debug_mode?
388
+ config.key?(:non_blocking) ? config[:non_blocking] : ! debug_mode?
389
389
  end
390
390
 
391
391
 
@@ -25,10 +25,19 @@ module Gopher
25
25
  # @param [String] selector incoming selector
26
26
  # @return Response object
27
27
  #
28
- def receive_data(selector)
29
- call! Request.new(selector, remote_ip)
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}/*.*").each do |x|
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
- require 'artii'
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
- # output a figlet, which is a big ASCII art header like this:
101
- # _ _ _ _ _
102
- # | | | | | | | | |
103
- # | |__| | ___| | | ___ | |
104
- # | __ |/ _ \ | |/ _ \| |
105
- # | | | | __/ | | (_) |_|
106
- # |_| |_|\___|_|_|\___/(_)
107
- #
108
- # This method doesn't do any width checks, so you should be
109
- # careful with it.
110
- # You can get a list of fonts from the artii source code or
111
- # http://www.figlet.org/examples.html
112
- # https://github.com/miketierney/artii/tree/master/lib/figlet/fonts
113
-
114
- # @param [String] str the text you want to use for your figlet
115
- # @param [String] font name of the font. Defaults to 'big'.
116
- #
117
- def figlet(str, font = 'big')
118
- a = Artii::Base.new(:font => font)
119
- a.asciify(str).split("\n").each do |l|
120
- text l
121
- end
122
- self.to_s
123
- end
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
- # output a 'small' header, just the text with an underline
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
- def small_header(str, under = '=')
156
- str = " " + str + " "
157
- text(str)
158
- underline(str.length, under)
159
- end
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
- def link(text, selector, host=nil, port=nil)
96
- type = determine_type(selector)
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
- # extension. This is a pretty simple check based on the entities
113
- # list in http://www.ietf.org/rfc/rfc1436.txt
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(selector)
118
- ext = File.extname(selector).downcase
119
- case ext
120
- when '.zip', '.gz', '.bz2' then '5'
121
- when '.gif' then 'g'
122
- when '.jpg', '.png' then 'I'
123
- when '.mp3', '.wav' then 's'
124
- else '0'
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
@@ -1,4 +1,4 @@
1
1
  module Gopher
2
2
  # current version of the app
3
- VERSION = "0.4.0"
3
+ VERSION = "0.5.3"
4
4
  end
@@ -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.should == "0.0.0.0"
13
- @app.port.should == 70
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?.should == false
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.should be_nil
22
+ expect(@app.last_reload).to be_nil
23
23
  @app.scripts << "foo.rb"
24
- @app.should_reload?.should == false
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.stub!(:now).and_return(now)
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.should_receive(:mtime).with("foo.rb").and_return(now)
33
+ expect(File).to receive(:mtime).with("foo.rb").and_return(now)
34
34
 
35
- @app.should_reload?.should == true
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.stub!(:now).and_return(now)
42
+ allow(Time).to receive(:now).and_return(now)
43
43
 
44
- @app.should_receive(:should_reload?).and_return(true)
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.should_receive(:load).with("foo.rb")
48
+ expect(@app).to receive(:load).with("foo.rb")
49
49
  @app.reload_stale
50
50
 
51
- @app.last_reload.should == now
51
+ expect(@app.last_reload).to eq(now)
52
52
  end
53
53
  end
54
54
  end