heel 0.6.0 → 1.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/{CHANGES → HISTORY} +3 -3
- data/LICENSE +1 -1
- data/README +28 -26
- data/bin/heel +5 -1
- data/data/error.rhtml +1 -1
- data/data/listing.rhtml +2 -2
- data/gemspec.rb +42 -0
- data/lib/heel.rb +18 -13
- data/lib/heel/configuration.rb +64 -0
- data/lib/heel/directory_indexer.rb +114 -0
- data/lib/heel/error_response.rb +43 -0
- data/lib/heel/logger.rb +42 -0
- data/lib/heel/mime_map.rb +87 -0
- data/lib/heel/rackapp.rb +142 -0
- data/lib/heel/request.rb +66 -0
- data/lib/heel/server.rb +253 -219
- data/lib/heel/version.rb +21 -16
- data/spec/configuration_spec.rb +20 -0
- data/spec/directory_indexer_spec.rb +34 -0
- data/spec/rackapp_spec.rb +43 -0
- data/spec/server_spec.rb +107 -108
- data/tasks/announce.rake +42 -0
- data/tasks/config.rb +103 -0
- data/tasks/distribution.rake +52 -0
- data/tasks/documentation.rake +35 -0
- data/tasks/rspec.rb +33 -0
- data/tasks/rubyforge.rb +52 -0
- data/tasks/utils.rb +85 -0
- metadata +52 -44
- data/lib/heel/dir_handler.rb +0 -310
- data/lib/heel/error_handler.rb +0 -30
- data/lib/heel/gemspec.rb +0 -56
- data/lib/heel/specification.rb +0 -128
- data/spec/dir_handler_spec.rb +0 -128
- data/spec/error_handler_spec.rb +0 -29
data/{CHANGES → HISTORY}
RENAMED
@@ -1,4 +1,7 @@
|
|
1
1
|
= Changelog
|
2
|
+
== Version 1.0.0 - 2008-04-20
|
3
|
+
|
4
|
+
* Convert Heel to a Rack and Thin application
|
2
5
|
|
3
6
|
== Version 0.6.0 - 2007-11-21
|
4
7
|
|
@@ -6,9 +9,6 @@
|
|
6
9
|
* Changed change 'resources' directory to 'data'
|
7
10
|
* Renamed internal constants
|
8
11
|
* Changed operating URL's to avoid conflict with directories heel may be serving
|
9
|
-
** /css -> /heel_css
|
10
|
-
** /icons -> /heel_icons
|
11
|
-
** /status -> /heel_status
|
12
12
|
|
13
13
|
== Version 0.5.0 - 2007-11-19
|
14
14
|
|
data/LICENSE
CHANGED
data/README
CHANGED
@@ -6,44 +6,45 @@
|
|
6
6
|
|
7
7
|
== DESCRIPTION:
|
8
8
|
|
9
|
-
Heel is a small static
|
10
|
-
|
11
|
-
{launchy}[http://copiousfreetime.rubyforge.org/launchy/] to open your browser at
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
9
|
+
Heel is a small static web server for use when you need a quick web server for a
|
10
|
+
directory. Once the server is running, heel will use
|
11
|
+
{launchy}[http://copiousfreetime.rubyforge.org/launchy/] to open your browser at
|
12
|
+
the URL of your document root.
|
13
|
+
|
14
|
+
Heel is built using {Rack}[http://rack.rubyforge.org] and
|
15
|
+
{Thin}[http://code.macournoyer.com/thin/]
|
16
|
+
|
17
|
+
% heel
|
18
|
+
>> Thin web server (v0.8.1 codename Rebel Porpoise)
|
19
|
+
>> Threaded mode OFF
|
20
|
+
>> Maximum connections set to 1024
|
21
|
+
>> Listening on 0.0.0.0:4331, CTRL+C to stop
|
22
|
+
Launching your browser...
|
23
23
|
|
24
24
|
Or run it in the background
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
% heel --daemonize
|
27
|
+
Created /Users/jeremy/.heel
|
28
|
+
heel's PID (/Users/jeremy/.heel/heel.pid) and log file (/Users/jeremy/.heel/heel.log) are stored here
|
29
|
+
Launching your browser at http://0.0.0.0:4331/
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
% heel --kill
|
32
|
+
Sending TERM to process 3304
|
33
|
+
Done.
|
33
34
|
|
34
35
|
== FEATURES
|
35
36
|
|
36
37
|
* Automatic launching of your browser to the URL it is serving with {launchy}[http://copiousfreetime.rubyforge.org/launchy/]
|
37
38
|
* Automatic syntax highlighting of source code files with {coderay}[http://coderay.rubychan.de/]
|
38
39
|
* Run in the foreground or daemonized
|
39
|
-
* Bind to any address and port (default is
|
40
|
+
* Bind to any address and port (default is 0.0.0.0:4331)
|
40
41
|
|
41
42
|
== SYNOPSIS:
|
42
43
|
|
43
44
|
Usage: heel [options]
|
44
45
|
|
45
46
|
-a, --address ADDRESS Address to bind to
|
46
|
-
(default:
|
47
|
+
(default: 0.0.0.0)
|
47
48
|
-d, --daemonize Run daemonized in the background
|
48
49
|
-h, --help Display this text
|
49
50
|
-k, --kill Kill an existing daemonized heel process
|
@@ -65,13 +66,13 @@ Or run it in the background
|
|
65
66
|
* {coderay}[http://coderay.rubychan.de/]
|
66
67
|
* {launchy}[http://copiousfreetime.rubyforge.org/launchy/] >= 0.1.1
|
67
68
|
* {mime-types}[http://mime-types.rubyforge.org/]
|
68
|
-
* {
|
69
|
-
* {rake}[http://rake.rubyforge.org/] >= 0.7.1
|
69
|
+
* {thin}[http://thin.rubyforge.org/]
|
70
70
|
|
71
71
|
=== For development:
|
72
72
|
|
73
73
|
* {rcov}[http://eigenclass.org/hiki.rb?rcov] >= 0.7.0.1
|
74
74
|
* {rspec}[http://rspec.rubyforge.org/] >= 0.7.3
|
75
|
+
* {rake}[http://rake.rubyforge.org/] >= 0.7.1
|
75
76
|
|
76
77
|
== INSTALL:
|
77
78
|
|
@@ -79,12 +80,13 @@ Or run it in the background
|
|
79
80
|
|
80
81
|
== CREDITS:
|
81
82
|
|
82
|
-
*
|
83
|
+
* {Thin}[http://code.macournoyer.com/thin/]
|
84
|
+
* {Rack}[http://rack.rubyforge.org/]
|
83
85
|
* http://www.famfamfam.com/ for amazing icons
|
84
86
|
|
85
87
|
== BSD LICENSE:
|
86
88
|
|
87
|
-
Copyright (c) 2007, Jeremy Hinegardner
|
89
|
+
Copyright (c) 2007, 2008, Jeremy Hinegardner
|
88
90
|
|
89
91
|
All rights reserved.
|
90
92
|
|
data/bin/heel
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
#--
|
4
|
+
# Copyright (c) 2007, 2008 Jeremy Hinegardner
|
5
|
+
# All rights reserved. Licensed under the BSD license. See LICENSE for details
|
6
|
+
#++
|
7
|
+
|
3
8
|
$: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
|
4
9
|
|
5
10
|
require 'rubygems'
|
6
|
-
require 'mongrel'
|
7
11
|
require 'heel'
|
8
12
|
|
9
13
|
Heel::Server.new(ARGV).run
|
data/data/error.rhtml
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
<b class="c4"></b><b class="c3"></b><b class="c2"></b><b class="c1"></b>
|
23
23
|
</div>
|
24
24
|
<div class="footer">
|
25
|
-
<a href="<%=
|
25
|
+
<a href="<%= homepage %>">heel</a>/v<%= ::Heel::VERSION %>
|
26
26
|
</div>
|
27
27
|
</div>
|
28
28
|
</body>
|
data/data/listing.rhtml
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
<img src="<%= entry.icon_url %>" width="16" height="16" alt="icon for type <%= entry.content_type %>" />
|
23
23
|
<% end %>
|
24
24
|
<a href="<%= "#{base_uri.chomp('/')}/#{entry.link}" %>"><%= entry.name %></a>
|
25
|
-
<% if highlighting and entry.content_type != 'Directory' then %>
|
25
|
+
<% if highlighting? and entry.content_type != 'Directory' then %>
|
26
26
|
(<a href="<%= "#{base_uri.chomp('/')}/#{entry.link}?highlighting=false" %>">download</a>)
|
27
27
|
<% end %>
|
28
28
|
</td>
|
@@ -35,7 +35,7 @@
|
|
35
35
|
</table>
|
36
36
|
</div>
|
37
37
|
<div class="footer">
|
38
|
-
<a href="
|
38
|
+
<a href="http://copiousfreetime.rubyforge.org/heel/">heel</a>/v<%= Heel::VERSION %>
|
39
39
|
</div>
|
40
40
|
</body>
|
41
41
|
</html>
|
data/gemspec.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'heel/version'
|
3
|
+
require 'tasks/config'
|
4
|
+
|
5
|
+
Heel::GEM_SPEC = Gem::Specification.new do |spec|
|
6
|
+
proj = Configuration.for('project')
|
7
|
+
spec.name = proj.name
|
8
|
+
spec.version = Heel::VERSION
|
9
|
+
|
10
|
+
spec.author = proj.author
|
11
|
+
spec.email = proj.email
|
12
|
+
spec.homepage = proj.homepage
|
13
|
+
spec.summary = proj.summary
|
14
|
+
spec.description = proj.description
|
15
|
+
spec.platform = Gem::Platform::RUBY
|
16
|
+
|
17
|
+
|
18
|
+
pkg = Configuration.for('packaging')
|
19
|
+
spec.files = pkg.files.all
|
20
|
+
spec.executables = pkg.files.bin.collect { |b| File.basename(b) }
|
21
|
+
spec.add_dependency("thin", ">= 0.7.0")
|
22
|
+
spec.add_dependency("mime-types", ">= 1.15")
|
23
|
+
spec.add_dependency("launchy", ">= 0.3.1")
|
24
|
+
spec.add_dependency("coderay", ">= 0.7.4.215")
|
25
|
+
|
26
|
+
if rdoc = Configuration.for_if_exist?('rdoc') then
|
27
|
+
spec.has_rdoc = true
|
28
|
+
spec.extra_rdoc_files = pkg.files.rdoc
|
29
|
+
spec.rdoc_options = rdoc.options + [ "--main" , rdoc.main ]
|
30
|
+
else
|
31
|
+
spec.has_rdoc = false
|
32
|
+
end
|
33
|
+
|
34
|
+
if test = Configuration.for_if_exist?('testing') then
|
35
|
+
spec.test_files = test.files
|
36
|
+
end
|
37
|
+
|
38
|
+
if rf = Configuration.for_if_exist?('rubyforge') then
|
39
|
+
spec.rubyforge_project = rf.project
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/heel.rb
CHANGED
@@ -1,16 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
end
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007, 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. Licensed under the BSD license. See LICENSE for details
|
4
|
+
#++
|
6
5
|
|
7
|
-
|
8
|
-
|
6
|
+
module Heel
|
7
|
+
# recursively descend the directory with the same name as this file and do a
|
8
|
+
# require 'heel/path/to/file'
|
9
|
+
#
|
10
|
+
def self.require_all_libs_relative_to_me
|
11
|
+
remove_parent = File.dirname(File.expand_path(__FILE__)) + File::SEPARATOR
|
12
|
+
descend_dir = File.join(remove_parent,File.basename(__FILE__, ".rb"))
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
require
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
Dir.glob("#{descend_dir}/**/*.rb").each do |rb|
|
15
|
+
lib = rb.gsub(remove_parent,'')
|
16
|
+
require lib
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
16
20
|
|
21
|
+
Heel.require_all_libs_relative_to_me
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007, 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. Licensed under BSD license. See LICENSE for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module Heel
|
7
|
+
|
8
|
+
# Configuration module used by all the other modules and classes for
|
9
|
+
# determining paths and default values.
|
10
|
+
#
|
11
|
+
module Configuration
|
12
|
+
|
13
|
+
# The root directory of the project is considered to be the parent directory
|
14
|
+
# of the 'lib' directory.
|
15
|
+
#
|
16
|
+
# returns:: [String] The full expanded path of the parent directory of 'lib'
|
17
|
+
# going up the path from the current file. Trailing
|
18
|
+
# File::SEPARATOR is guaranteed.
|
19
|
+
#
|
20
|
+
def self.root_dir
|
21
|
+
unless @root_dir
|
22
|
+
path_parts = ::File.expand_path(__FILE__).split(::File::SEPARATOR)
|
23
|
+
lib_index = path_parts.rindex("lib")
|
24
|
+
@root_dir = path_parts[0...lib_index].join(::File::SEPARATOR) + ::File::SEPARATOR
|
25
|
+
end
|
26
|
+
return @root_dir
|
27
|
+
end
|
28
|
+
|
29
|
+
# returns:: [String] The full expanded path of the +config+ directory
|
30
|
+
# below _root_dir_. All parameters passed in are joined onto the
|
31
|
+
# result. Trailing File::SEPARATOR is guaranteed if _args_ are
|
32
|
+
# *not* present.
|
33
|
+
#
|
34
|
+
def self.config_path(*args)
|
35
|
+
self.sub_path("config", *args)
|
36
|
+
end
|
37
|
+
|
38
|
+
# returns:: [String] The full expanded path of the +data+ directory below
|
39
|
+
# _root_dir_. All parameters passed in are joined onto the
|
40
|
+
# result. Trailing File::SEPARATOR is guaranteed if
|
41
|
+
# _*args_ are *not* present.
|
42
|
+
#
|
43
|
+
def self.data_path(*args)
|
44
|
+
self.sub_path("data", *args)
|
45
|
+
end
|
46
|
+
|
47
|
+
# returns:: [String] The full expanded path of the +lib+ directory below
|
48
|
+
# _root_dir_. All parameters passed in are joined onto the
|
49
|
+
# result. Trailing File::SEPARATOR is guaranteed if
|
50
|
+
# _*args_ are *not* present.
|
51
|
+
#
|
52
|
+
def self.lib_path(*args)
|
53
|
+
self.sub_path("lib", *args)
|
54
|
+
end
|
55
|
+
|
56
|
+
HOMEPAGE = "http://copiousfreetime.rubyforge.org/heel/"
|
57
|
+
|
58
|
+
private
|
59
|
+
def self.sub_path(sub,*args)
|
60
|
+
sp = ::File.join(root_dir, sub) + File::SEPARATOR
|
61
|
+
sp = ::File.join(sp, *args) if args
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007, 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. Licensed under the BSD license. See LICENSE for details
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'heel'
|
7
|
+
require 'erb'
|
8
|
+
|
9
|
+
module Heel
|
10
|
+
# generate html index pages of a directory
|
11
|
+
#
|
12
|
+
class DirectoryIndexer
|
13
|
+
|
14
|
+
attr_reader :options
|
15
|
+
attr_reader :template_file
|
16
|
+
attr_reader :template
|
17
|
+
|
18
|
+
def initialize( template_file, options )
|
19
|
+
@template_file = template_file
|
20
|
+
@options = options
|
21
|
+
reload_template
|
22
|
+
end
|
23
|
+
|
24
|
+
def should_ignore?(fname)
|
25
|
+
options[:ignore_globs].each do |glob|
|
26
|
+
return true if ::File.fnmatch(glob,fname)
|
27
|
+
end
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def mime_map
|
32
|
+
@mime_map ||= Heel::MimeMap.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def highlighting?
|
36
|
+
@options[:highlighting]
|
37
|
+
end
|
38
|
+
|
39
|
+
def reload_on_template_change?
|
40
|
+
@options[:reload_template_on_change]
|
41
|
+
end
|
42
|
+
|
43
|
+
def using_icons?
|
44
|
+
@options[:using_icons]
|
45
|
+
end
|
46
|
+
|
47
|
+
def reload_template
|
48
|
+
fstat = File.stat(@template_file)
|
49
|
+
@template_mtime ||= fstat.mtime
|
50
|
+
if @template.nil? or fstat.mtime > @template_mtime then
|
51
|
+
@template = ::ERB.new(File.read(@template_file))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# generate the directory index html page of a directory
|
56
|
+
#
|
57
|
+
def index_page_for(req)
|
58
|
+
reload_template if reload_on_template_change?
|
59
|
+
dir = req.request_path
|
60
|
+
base_uri = req.path_info
|
61
|
+
entries = []
|
62
|
+
Dir.entries(dir).each do |entry|
|
63
|
+
next if should_ignore?(entry)
|
64
|
+
next if dir == @options[:document_root] and entry == ".."
|
65
|
+
|
66
|
+
stat = File.stat(File.join(dir,entry))
|
67
|
+
entry_data = OpenStruct.new
|
68
|
+
|
69
|
+
entry_data.name = entry == ".." ? "Parent Directory" : entry
|
70
|
+
entry_data.link = entry
|
71
|
+
entry_data.size = num_to_bytes(stat.size)
|
72
|
+
entry_data.last_modified = stat.mtime.strftime("%Y-%m-%d %H:%M:%S")
|
73
|
+
|
74
|
+
if stat.directory? then
|
75
|
+
entry_data.content_type = "Directory"
|
76
|
+
entry_data.size = "-"
|
77
|
+
entry_data.name += "/"
|
78
|
+
if using_icons? then
|
79
|
+
entry_data.icon_url = File.join(options[:icon_url], MimeMap.icons_by_mime_type[:directory])
|
80
|
+
end
|
81
|
+
else
|
82
|
+
entry_data.mime_type = mime_map.mime_type_of(entry)
|
83
|
+
entry_data.content_type = entry_data.mime_type.content_type
|
84
|
+
if using_icons? then
|
85
|
+
entry_data.icon_url = File.join(options[:icon_url], mime_map.icon_for(entry_data.mime_type))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
entries << entry_data
|
89
|
+
end
|
90
|
+
|
91
|
+
entries = entries.sort_by { |e| e.link }
|
92
|
+
return template.result(binding)
|
93
|
+
end
|
94
|
+
|
95
|
+
# essentially this is strfbytes from facets
|
96
|
+
#
|
97
|
+
def num_to_bytes(num,fmt="%.2f")
|
98
|
+
case
|
99
|
+
when num < 1024
|
100
|
+
"#{num} bytes"
|
101
|
+
when num < 1024**2
|
102
|
+
"#{fmt % (num.to_f / 1024)} KB"
|
103
|
+
when num < 1024**3
|
104
|
+
"#{fmt % (num.to_f / 1024**2)} MB"
|
105
|
+
when num < 1024**4
|
106
|
+
"#{fmt % (num.to_f / 1024**3)} GB"
|
107
|
+
when num < 1024**5
|
108
|
+
"#{fmt % (num.to_f / 1024**4)} TB"
|
109
|
+
else
|
110
|
+
"#{num} bytes"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007, 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. Licensed under the BSD license. See LICENSE for details
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'heel'
|
7
|
+
require 'rack'
|
8
|
+
require 'erb'
|
9
|
+
|
10
|
+
module Heel
|
11
|
+
|
12
|
+
class ErrorResponse < ::Rack::Response
|
13
|
+
|
14
|
+
attr_reader :base_uri
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def template_file
|
18
|
+
@template_file ||= Heel::Configuration.data_path("error.rhtml")
|
19
|
+
end
|
20
|
+
|
21
|
+
def template
|
22
|
+
@template ||= ::ERB.new(File.read(template_file))
|
23
|
+
end
|
24
|
+
|
25
|
+
def homepage
|
26
|
+
@homepage ||= Heel::Configuration::HOMEPAGE
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(base_uri, body, status = 404, header = {})
|
31
|
+
super(body, status, header)
|
32
|
+
self['Content-type'] = 'text/html'
|
33
|
+
@base_uri = base_uri
|
34
|
+
end
|
35
|
+
|
36
|
+
def finish
|
37
|
+
message = ::Rack::Utils::HTTP_STATUS_CODES[status]
|
38
|
+
homepage = ErrorResponse.homepage
|
39
|
+
|
40
|
+
return [ status, header.to_hash, ErrorResponse.template.result(binding) ]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|