heel 2.0.0 → 3.0.0
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.
- data/CONTRIBUTING.md +46 -0
- data/{HISTORY → HISTORY.rdoc} +13 -0
- data/Manifest.txt +45 -0
- data/{README → README.rdoc} +2 -3
- data/Rakefile +20 -0
- data/TODO +2 -0
- data/bin/heel +1 -3
- data/data/css/coderay-alpha.css +120 -0
- data/lib/heel.rb +10 -15
- data/lib/heel/configuration.rb +6 -8
- data/lib/heel/directory_indexer.rb +9 -9
- data/lib/heel/error_response.rb +11 -10
- data/lib/heel/mime_map.rb +3 -3
- data/lib/heel/rackapp.rb +13 -26
- data/lib/heel/request.rb +3 -3
- data/lib/heel/server.rb +88 -75
- data/spec/configuration_spec.rb +9 -5
- data/spec/directory_indexer_spec.rb +8 -8
- data/spec/rackapp_spec.rb +16 -16
- data/spec/server_spec.rb +23 -22
- data/spec/spec_helper.rb +10 -9
- data/tasks/default.rake +212 -0
- data/tasks/this.rb +202 -0
- metadata +178 -110
- data/gemspec.rb +0 -42
- data/lib/heel/logger.rb +0 -42
- data/lib/heel/version.rb +0 -26
- data/tasks/announce.rake +0 -42
- data/tasks/config.rb +0 -103
- data/tasks/distribution.rake +0 -47
- data/tasks/documentation.rake +0 -36
- data/tasks/rspec.rb +0 -34
- data/tasks/rubyforge.rb +0 -67
- data/tasks/utils.rb +0 -85
data/lib/heel/mime_map.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2007
|
3
|
-
# All rights reserved. Licensed under the BSD license.
|
2
|
+
# Copyright (c) 2007 - 2013 Jeremy Hinegardner
|
3
|
+
# All rights reserved. Licensed under the BSD license. See LICENSE for details
|
4
4
|
#++
|
5
|
-
|
5
|
+
|
6
6
|
require 'mime/types'
|
7
7
|
|
8
8
|
module Heel
|
data/lib/heel/rackapp.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2007
|
3
|
-
# All rights reserved. Licensed under the BSD license.
|
2
|
+
# Copyright (c) 2007 - 2013 Jeremy Hinegardner
|
3
|
+
# All rights reserved. Licensed under the BSD license. See LICENSE for details
|
4
4
|
#++
|
5
5
|
|
6
|
-
require 'heel'
|
7
6
|
require 'rack'
|
8
7
|
require 'rack/utils'
|
9
8
|
require 'coderay'
|
@@ -20,7 +19,7 @@ module Heel
|
|
20
19
|
attr_reader :ignore_globs
|
21
20
|
|
22
21
|
|
23
|
-
def initialize(options = {})
|
22
|
+
def initialize(options = {})
|
24
23
|
@ignore_globs = options[:ignore_globs] ||= %w( *~ .htaccess . )
|
25
24
|
@document_root = options[:document_root] ||= Dir.pwd
|
26
25
|
@directory_listing_allowed = options[:directory_listing_allowed] ||= true
|
@@ -48,7 +47,6 @@ module Heel
|
|
48
47
|
end
|
49
48
|
|
50
49
|
def directory_indexer
|
51
|
-
indexer_ignore = ( ignore_globs + [ document_root] ).flatten
|
52
50
|
@directory_indexer ||= DirectoryIndexer.new( directory_index_template_file, @options )
|
53
51
|
end
|
54
52
|
|
@@ -67,13 +65,11 @@ module Heel
|
|
67
65
|
dir_index = File.join(req.request_path, directory_index_html)
|
68
66
|
if File.file?(dir_index) and File.readable?(dir_index) then
|
69
67
|
response['Content-Type'] = mime_map.mime_type_of(dir_index).to_s
|
70
|
-
response
|
71
|
-
response.body = File.open(dir_index)
|
68
|
+
response.write( File.read( dir_index ) )
|
72
69
|
elsif directory_listing_allowed? then
|
73
70
|
body = directory_indexer.index_page_for(req)
|
74
71
|
response['Content-Type'] = 'text/html'
|
75
|
-
response
|
76
|
-
response.body << body
|
72
|
+
response.write( body )
|
77
73
|
else
|
78
74
|
return ::Heel::ErrorResponse.new(req.path_info,"Directory index is forbidden", 403).finish
|
79
75
|
end
|
@@ -100,39 +96,30 @@ module Heel
|
|
100
96
|
<head>
|
101
97
|
<title>#{req.path_info}</title>
|
102
98
|
<!-- CodeRay syntax highlighting CSS -->
|
103
|
-
<link rel="stylesheet" href="/heel_css/coderay-
|
99
|
+
<link rel="stylesheet" href="/heel_css/coderay-alpha.css" type="text/css" />
|
104
100
|
</head>
|
105
101
|
<body>
|
106
|
-
|
107
|
-
<pre>
|
108
|
-
#{CodeRay.scan_file(req.request_path,:auto).html({:line_numbers => :inline})}
|
109
|
-
</pre>
|
110
|
-
</div>
|
102
|
+
#{CodeRay.scan_file(req.request_path,:auto).html({ :wrap => :div, :line_numbers => :inline })}
|
111
103
|
</body>
|
112
104
|
</html>
|
113
105
|
EOM
|
114
106
|
response['Content-Type'] = 'text/html'
|
115
107
|
response['Content-Length'] = body.length.to_s
|
116
|
-
response.body
|
108
|
+
response.write( body )
|
117
109
|
return response.finish
|
118
110
|
end
|
119
111
|
end
|
120
112
|
|
121
113
|
# fall through to a default file return
|
122
|
-
#
|
123
114
|
|
124
115
|
file_type = mime_map.mime_type_of(req.request_path)
|
125
116
|
response['Content-Type'] = file_type.to_s
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
File.open(req.request_path) do |f|
|
130
|
-
while p = f.read(8192)
|
131
|
-
response.write p
|
132
|
-
end
|
117
|
+
File.open( req.request_path ) do |f|
|
118
|
+
while p = f.read( 8192 ) do
|
119
|
+
response.write( p )
|
133
120
|
end
|
134
121
|
end
|
135
|
-
|
122
|
+
return response.finish
|
136
123
|
end
|
137
124
|
|
138
125
|
# interface to rack, env is a hash
|
@@ -145,7 +132,7 @@ module Heel
|
|
145
132
|
if req.forbidden? or should_ignore?(req.request_path) then
|
146
133
|
return ErrorResponse.new(req.path_info,"You do not have permissionto view #{req.path_info}",403).finish
|
147
134
|
end
|
148
|
-
return ErrorResponse.new(req.path_info, "File not found: #{req.path_info}",
|
135
|
+
return ErrorResponse.new(req.path_info, "File not found: #{req.path_info}",404).finish unless req.found?
|
149
136
|
return directory_index_response(req) if req.for_directory?
|
150
137
|
return file_response(req) if req.for_file?
|
151
138
|
else
|
data/lib/heel/request.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2007
|
3
|
-
# All rights reserved.
|
2
|
+
# Copyright (c) 2007 - 2013 Jeremy Hinegardner
|
3
|
+
# All rights reserved. Licensed under the BSD license. See LICENSE for details
|
4
4
|
#++
|
5
|
-
|
5
|
+
|
6
6
|
require 'rack'
|
7
7
|
module Heel
|
8
8
|
# nothing more than a rack request with some additional methods and overriding
|
data/lib/heel/server.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2007
|
3
|
-
# All rights reserved. Licensed under the BSD license.
|
2
|
+
# Copyright (c) 2007 - 2013 Jeremy Hinegardner
|
3
|
+
# All rights reserved. Licensed under the BSD license. See LICENSE for details
|
4
4
|
#++
|
5
5
|
|
6
|
-
require 'heel'
|
7
|
-
require 'thin'
|
8
6
|
require 'ostruct'
|
9
7
|
require 'launchy'
|
10
8
|
require 'fileutils'
|
11
9
|
require 'heel/rackapp'
|
10
|
+
require 'puma'
|
12
11
|
|
13
12
|
module Heel
|
14
13
|
class Server
|
@@ -39,34 +38,32 @@ module Heel
|
|
39
38
|
|
40
39
|
set_io
|
41
40
|
|
42
|
-
@options
|
43
|
-
@parsed_options
|
44
|
-
@parser
|
45
|
-
@error_message
|
41
|
+
@options = default_options
|
42
|
+
@parsed_options = ::OpenStruct.new
|
43
|
+
@parser = option_parser
|
44
|
+
@error_message = nil
|
46
45
|
|
47
46
|
begin
|
48
47
|
@parser.parse!(argv)
|
49
48
|
rescue ::OptionParser::ParseError => pe
|
50
49
|
msg = ["#{@parser.program_name}: #{pe}",
|
51
|
-
|
52
|
-
|
50
|
+
"Try `#{@parser.program_name} --help` for more information"]
|
51
|
+
@error_message = msg.join("\n")
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
56
55
|
def default_options
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
return @default_options
|
56
|
+
defaults = ::OpenStruct.new
|
57
|
+
defaults.show_version = false
|
58
|
+
defaults.show_help = false
|
59
|
+
defaults.address = "0.0.0.0"
|
60
|
+
defaults.port = 4331
|
61
|
+
defaults.document_root = Dir.pwd
|
62
|
+
defaults.daemonize = false
|
63
|
+
defaults.highlighting = false
|
64
|
+
defaults.kill = false
|
65
|
+
defaults.launch_browser = true
|
66
|
+
return defaults
|
70
67
|
end
|
71
68
|
|
72
69
|
def default_directory
|
@@ -81,6 +78,14 @@ module Heel
|
|
81
78
|
File.join(default_directory,"heel.log")
|
82
79
|
end
|
83
80
|
|
81
|
+
def win?
|
82
|
+
RUBY_PLATFORM =~ /mswin|mingw/
|
83
|
+
end
|
84
|
+
|
85
|
+
def java?
|
86
|
+
RUBY_PLATFORM =~ /java/
|
87
|
+
end
|
88
|
+
|
84
89
|
def option_parser
|
85
90
|
OptionParser.new do |op|
|
86
91
|
op.separator ""
|
@@ -88,10 +93,11 @@ module Heel
|
|
88
93
|
op.on("-a", "--address ADDRESS", "Address to bind to",
|
89
94
|
" (default: #{default_options.address})") do |add|
|
90
95
|
@parsed_options.address = add
|
91
|
-
|
96
|
+
end
|
92
97
|
|
93
98
|
op.on("-d", "--daemonize", "Run daemonized in the background") do
|
94
|
-
raise ::OptionParser::ParseError, "Daemonizing is not supported on windows" if
|
99
|
+
raise ::OptionParser::ParseError, "Daemonizing is not supported on windows" if win?
|
100
|
+
raise ::OptionParser::ParseError, "Daemonizing is not supported on java" if java?
|
95
101
|
@parsed_options.daemonize = true
|
96
102
|
end
|
97
103
|
|
@@ -106,23 +112,23 @@ module Heel
|
|
106
112
|
op.on("--[no-]highlighting", "Turn on or off syntax highlighting",
|
107
113
|
" (default: off)") do |highlighting|
|
108
114
|
@parsed_options.highlighting = highlighting
|
109
|
-
|
115
|
+
end
|
110
116
|
|
111
117
|
op.on("--[no-]launch-browser", "Turn on or off automatic browser launch",
|
112
118
|
" (default: on)") do |l|
|
113
119
|
@parsed_options.launch_browser = l
|
114
|
-
|
120
|
+
end
|
115
121
|
|
116
122
|
op.on("-p", "--port PORT", Integer, "Port to bind to",
|
117
123
|
" (default: #{default_options.port})") do |port|
|
118
124
|
@parsed_options.port = port
|
119
|
-
|
125
|
+
end
|
120
126
|
|
121
127
|
op.on("-r","--root ROOT",
|
122
128
|
"Set the document root"," (default: #{default_options.document_root})") do |document_root|
|
123
129
|
@parsed_options.document_root = File.expand_path(document_root)
|
124
130
|
raise ::OptionParser::ParseError, "#{@parsed_options.document_root} is not a valid directory" if not File.directory?(@parsed_options.document_root)
|
125
|
-
|
131
|
+
end
|
126
132
|
|
127
133
|
op.on("-v", "--version", "Show version") do
|
128
134
|
@parsed_options.show_version = true
|
@@ -132,9 +138,7 @@ module Heel
|
|
132
138
|
|
133
139
|
def merge_options
|
134
140
|
options = default_options.marshal_dump
|
135
|
-
@parsed_options.marshal_dump
|
136
|
-
options[key] = value
|
137
|
-
end
|
141
|
+
options.merge!( @parsed_options.marshal_dump )
|
138
142
|
|
139
143
|
@options = OpenStruct.new(options)
|
140
144
|
end
|
@@ -174,7 +178,7 @@ module Heel
|
|
174
178
|
rescue Errno::ESRCH
|
175
179
|
@stdout.puts "Unable to kill process with pid #{pid}. Process does not exist. Removing stale pid file."
|
176
180
|
File.unlink(pid_file)
|
177
|
-
rescue Errno::EPERM
|
181
|
+
rescue Errno::EPERM
|
178
182
|
@stdout.puts "Unable to kill process with pid #{pid}. No permissions to kill process."
|
179
183
|
end
|
180
184
|
else
|
@@ -197,7 +201,7 @@ module Heel
|
|
197
201
|
# make sure that if we are daemonizing the process is not running
|
198
202
|
def ensure_not_running
|
199
203
|
if options.daemonize and File.exist?(pid_file) then
|
200
|
-
@stdout.puts "ERROR: PID File #{pid_file} already exists.
|
204
|
+
@stdout.puts "ERROR: PID File #{pid_file} already exists. Heel may already be running."
|
201
205
|
@stdout.puts "ERROR: Check the Log file #{log_file}"
|
202
206
|
@stdout.puts "ERROR: Heel will not start until the .pid file is cleared (`heel --kill' to clean it up)."
|
203
207
|
exit 1
|
@@ -205,7 +209,7 @@ module Heel
|
|
205
209
|
end
|
206
210
|
|
207
211
|
def launch_browser
|
208
|
-
Thread.new do
|
212
|
+
Thread.new do
|
209
213
|
print "Launching your browser"
|
210
214
|
if options.daemonize then
|
211
215
|
puts " at http://#{options.address}:#{options.port}/"
|
@@ -216,24 +220,11 @@ module Heel
|
|
216
220
|
end
|
217
221
|
end
|
218
222
|
|
219
|
-
def
|
220
|
-
server = Thin::Server.new(options.address, options.port)
|
221
|
-
|
222
|
-
# overload the name of the process so it shows up as heel not thin
|
223
|
-
def server.name
|
224
|
-
"heel (v#{Heel::VERSION})"
|
225
|
-
end
|
226
|
-
|
227
|
-
server.pid_file = pid_file
|
228
|
-
server.log_file = log_file
|
229
|
-
|
223
|
+
def heel_app
|
230
224
|
app = Heel::RackApp.new({ :document_root => options.document_root,
|
231
225
|
:highlighting => options.highlighting})
|
232
|
-
|
233
|
-
|
234
|
-
server.app = Rack::Builder.new {
|
235
|
-
use Heel::Logger
|
236
|
-
map "/" do
|
226
|
+
stack = Rack::Builder.new {
|
227
|
+
map "/" do
|
237
228
|
run app
|
238
229
|
end
|
239
230
|
map "/heel_css" do
|
@@ -242,40 +233,62 @@ module Heel
|
|
242
233
|
map "/heel_icons" do
|
243
234
|
run Rack::File.new(Heel::Configuration.data_path("famfamfam", "icons"))
|
244
235
|
end
|
245
|
-
|
246
236
|
}
|
247
|
-
|
248
|
-
server.app = Thin::Stats::Adapter.new(server.app, "/heel_stats")
|
249
|
-
|
250
|
-
return server
|
237
|
+
return stack.to_app
|
251
238
|
end
|
252
239
|
|
253
|
-
def
|
254
|
-
|
240
|
+
def start_server
|
241
|
+
server_thread = Thread.new do
|
242
|
+
if options.daemonize then
|
243
|
+
if cpid = fork then
|
244
|
+
Process.waitpid( cpid )
|
245
|
+
else
|
246
|
+
server = Rack::Server.new( server_options )
|
247
|
+
server.start
|
248
|
+
end
|
249
|
+
else
|
250
|
+
server = Rack::Server.new( server_options )
|
251
|
+
server.start
|
252
|
+
end
|
253
|
+
end
|
254
|
+
return server_thread
|
255
|
+
end
|
255
256
|
|
257
|
+
def start_server_old
|
258
|
+
server = Rack::Server.new( server_options )
|
256
259
|
server_thread = Thread.new do
|
257
|
-
|
258
|
-
if
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
else
|
263
|
-
server.daemonize
|
264
|
-
server.start
|
265
|
-
end
|
260
|
+
if options.daemonize then
|
261
|
+
if cpid = fork then
|
262
|
+
# wait for the server to span and then move on to launching the
|
263
|
+
# browser
|
264
|
+
Process.waitpid( cpid )
|
266
265
|
else
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
266
|
+
server.start
|
267
|
+
end
|
268
|
+
else
|
269
|
+
begin
|
270
|
+
server.start
|
271
|
+
rescue RuntimeError
|
272
|
+
$stderr.puts "ERROR: Unable to start server. Heel may already be running. Please check running processes or run `heel --kill'"
|
273
|
+
exit 1
|
273
274
|
end
|
274
275
|
end
|
275
276
|
end
|
277
|
+
return server_thread
|
278
|
+
end
|
279
|
+
|
280
|
+
def server_options
|
281
|
+
{
|
282
|
+
:app => heel_app,
|
283
|
+
:pid => pid_file,
|
284
|
+
:Port => options.port,
|
285
|
+
:Host => options.address,
|
286
|
+
:environment => 'deployment',
|
287
|
+
:server => 'puma',
|
288
|
+
:daemonize => options.daemonize
|
289
|
+
}
|
276
290
|
end
|
277
291
|
|
278
|
-
|
279
292
|
# run the heel server with the current options.
|
280
293
|
def run
|
281
294
|
|
@@ -284,7 +297,7 @@ module Heel
|
|
284
297
|
setup_heel_dir
|
285
298
|
ensure_not_running
|
286
299
|
|
287
|
-
server_thread =
|
300
|
+
server_thread = start_server
|
288
301
|
|
289
302
|
if options.launch_browser then
|
290
303
|
launch_browser.join
|
data/spec/configuration_spec.rb
CHANGED
@@ -1,20 +1,24 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pathname'
|
2
3
|
|
3
4
|
describe Heel::Configuration do
|
5
|
+
before do
|
6
|
+
@proj_root = Pathname.new( __FILE__ ).parent.parent
|
7
|
+
end
|
4
8
|
it "finds files relative to root of gem" do
|
5
|
-
Heel::Configuration.root_dir.
|
9
|
+
Heel::Configuration.root_dir.must_equal @proj_root.expand_path.to_s + File::SEPARATOR
|
6
10
|
end
|
7
11
|
|
8
12
|
it "finds files in the config dir of the project" do
|
9
|
-
Heel::Configuration.config_path('config.rb').
|
13
|
+
Heel::Configuration.config_path('config.rb').must_equal @proj_root.join("config", "config.rb").to_s
|
10
14
|
end
|
11
15
|
|
12
16
|
it "finds files in the data dir of the project" do
|
13
|
-
Heel::Configuration.data_path('famfamfam', 'icons').
|
17
|
+
Heel::Configuration.data_path('famfamfam', 'icons').must_equal @proj_root.join( "data", "famfamfam", "icons" ).to_s
|
14
18
|
end
|
15
19
|
|
16
20
|
it "finds files in the lib dir of the project" do
|
17
|
-
Heel::Configuration.lib_path('heel.rb').
|
21
|
+
Heel::Configuration.lib_path('heel.rb').must_equal @proj_root.join("lib", "heel.rb").to_s
|
18
22
|
end
|
19
23
|
|
20
24
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Heel::DirectoryIndexer do
|
4
4
|
before(:each) do
|
@@ -7,28 +7,28 @@ describe Heel::DirectoryIndexer do
|
|
7
7
|
|
8
8
|
it "should ignore .htaccess files" do
|
9
9
|
@indexer.options[:ignore_globs] = %w( *~ .htaccess . )
|
10
|
-
@indexer.should_ignore?(".htaccess").
|
10
|
+
@indexer.should_ignore?(".htaccess").must_equal true
|
11
11
|
end
|
12
12
|
|
13
13
|
it "should not ignore .html files " do
|
14
14
|
@indexer.options[:ignore_globs] = %w( *~ .htaccess . )
|
15
|
-
@indexer.should_ignore?("something.html").
|
15
|
+
@indexer.should_ignore?("something.html").must_equal false
|
16
16
|
end
|
17
17
|
|
18
18
|
it "can tell if highlighting is to be performed" do
|
19
|
-
@indexer.
|
19
|
+
@indexer.must_be :highlighting?
|
20
20
|
end
|
21
21
|
|
22
22
|
it "knows if the template should be reloaded on changes" do
|
23
|
-
@indexer.
|
23
|
+
@indexer.reload_on_template_change?.must_equal false
|
24
24
|
end
|
25
25
|
|
26
|
-
it "
|
27
|
-
@indexer.
|
26
|
+
it "uses icons" do
|
27
|
+
@indexer.using_icons?.must_equal false
|
28
28
|
end
|
29
29
|
|
30
30
|
it "uses a mime map" do
|
31
|
-
@indexer.mime_map.
|
31
|
+
@indexer.mime_map.must_be_instance_of(Heel::MimeMap)
|
32
32
|
end
|
33
33
|
|
34
34
|
end
|