directory_listing 0.0.7 → 0.1.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/lib/sinatra/directory_listing.rb +166 -0
- metadata +43 -46
- data/lib/directory_listing.rb +0 -181
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
require 'sinatra/base'
|
|
2
|
+
|
|
3
|
+
require 'truncate'
|
|
4
|
+
require 'filesize'
|
|
5
|
+
require 'pathname'
|
|
6
|
+
|
|
7
|
+
# = Easy, CSS-styled, Apache-like directory listings for Sinatra.
|
|
8
|
+
#
|
|
9
|
+
# == Usage
|
|
10
|
+
#
|
|
11
|
+
# list() will return HTML, so the following is a complete Sinatra
|
|
12
|
+
# app that will provide a directory listing of whatever path you navigate to
|
|
13
|
+
# and let you view any file that is served directly:
|
|
14
|
+
#
|
|
15
|
+
# require 'sinatra'
|
|
16
|
+
# require 'sinatra/directory_listing'
|
|
17
|
+
#
|
|
18
|
+
# get '*' do |path|
|
|
19
|
+
# if File.exist?(File.join(settings.public_folder, path))
|
|
20
|
+
# if File.directory?(File.join(settings.public_folder, path))
|
|
21
|
+
# list()
|
|
22
|
+
# else
|
|
23
|
+
# send_file File.join(settings.public_folder, path)
|
|
24
|
+
# end
|
|
25
|
+
# else
|
|
26
|
+
# not_found
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# not_found do
|
|
31
|
+
# 'Try again.'
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# == Options
|
|
35
|
+
#
|
|
36
|
+
# stylesheet # a stylesheet that will be added to the <head> of the generated directory listing
|
|
37
|
+
# readme # an HTML string that will be appended at the footer of the generated directory listing
|
|
38
|
+
# should_list_invisibles # whether the directory listing should include invisibles (dotfiles) - "yes" or "no"
|
|
39
|
+
# last_modified_format # format for last modified date (http://www.ruby-doc.org/core-2.0/Time.html) - defaults to "%Y-%m-%d %H:%M:%S"
|
|
40
|
+
# filename_truncate_length # (integer) length to truncate file names to - defaults to 40
|
|
41
|
+
#
|
|
42
|
+
# == Styling
|
|
43
|
+
#
|
|
44
|
+
# It's pretty easy to figure out how to style directory_listing by looking at the source, but here are some gotchas:
|
|
45
|
+
#
|
|
46
|
+
# Every item listed is a <td> element in a table. Directories will have a class of "dir" and regular files will have a class of "file".
|
|
47
|
+
#
|
|
48
|
+
# You can style the "File" column with this CSS:
|
|
49
|
+
#
|
|
50
|
+
# table tr > td:first-child {
|
|
51
|
+
# text-align: left;
|
|
52
|
+
# }
|
|
53
|
+
#
|
|
54
|
+
# Second column:
|
|
55
|
+
# table tr > td:first-child + td {
|
|
56
|
+
# text-align: left;
|
|
57
|
+
# }
|
|
58
|
+
#
|
|
59
|
+
# Third column:
|
|
60
|
+
# table tr > td:first-child + td + td {
|
|
61
|
+
# text-align: left;
|
|
62
|
+
# }
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
module Sinatra
|
|
66
|
+
module Directory_listing
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def m_time(file)
|
|
71
|
+
file = File.join(settings.public_folder, request.fullpath)
|
|
72
|
+
time = "\t<td>#{File.mtime(file).strftime $last_modified_format}</td>"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def size(file)
|
|
76
|
+
dir = request.path
|
|
77
|
+
if File.directory?(File.join(dir, file))
|
|
78
|
+
"\t<td>-</td>"
|
|
79
|
+
else
|
|
80
|
+
file = File.join(settings.public_folder, request.fullpath)
|
|
81
|
+
size = Filesize.from("#{File.stat(file).size} B").pretty
|
|
82
|
+
"\t<td>#{size}</td>"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def name(file)
|
|
87
|
+
tfile = file.truncate($filename_truncate_length, '...')
|
|
88
|
+
if (Pathname.new(request.path).cleanpath).eql?((Pathname.new(settings.public_folder)).cleanpath)
|
|
89
|
+
link = file
|
|
90
|
+
else
|
|
91
|
+
link = File.join(request.fullpath, file)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
html = ""
|
|
95
|
+
if File.directory?(File.join(settings.public_folder, link))
|
|
96
|
+
html << "\t<td class='dir'><a href='#{link}'>#{tfile}</a></td>"
|
|
97
|
+
else
|
|
98
|
+
html << "\t<td class='file'><a href='#{link}'>#{tfile}</a></td>"
|
|
99
|
+
end
|
|
100
|
+
"#{html}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def wrap(file)
|
|
104
|
+
wrapped = ""
|
|
105
|
+
if $should_list_invisibles == "yes"
|
|
106
|
+
wrapped << "\n\t<tr>
|
|
107
|
+
#{name(file)}
|
|
108
|
+
#{m_time(file)}
|
|
109
|
+
#{size(file)}\n\t</tr>"
|
|
110
|
+
else
|
|
111
|
+
if file[0] != "."
|
|
112
|
+
wrapped << "\n\t<tr>
|
|
113
|
+
#{name(file)}
|
|
114
|
+
#{m_time(file)}
|
|
115
|
+
#{size(file)}\n\t</tr>"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
"#{wrapped}"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def list(o={})
|
|
122
|
+
options = {
|
|
123
|
+
:should_list_invisibles => "no",
|
|
124
|
+
:last_modified_format => "%Y-%m-%d %H:%M:%S",
|
|
125
|
+
:filename_truncate_length => 40,
|
|
126
|
+
:stylesheet => "",
|
|
127
|
+
:readme => ""
|
|
128
|
+
}.merge(o)
|
|
129
|
+
|
|
130
|
+
$should_list_invisibles = options[:should_list_invisibles]
|
|
131
|
+
$last_modified_format = options[:last_modified_format]
|
|
132
|
+
$filename_truncate_length = options[:filename_truncate_length]
|
|
133
|
+
|
|
134
|
+
html = "<html>\n<head>\n"
|
|
135
|
+
html << "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n"
|
|
136
|
+
if options[:stylesheet]
|
|
137
|
+
html << "<link rel=\"stylesheet\" type=\"text/css\" href=\"/#{options[:stylesheet].sub(/^[\/]*/,"")}\">\n"
|
|
138
|
+
end
|
|
139
|
+
html << "</head>\n<body>\n"
|
|
140
|
+
html << "<h1>Index of #{request.path}</h1>\n"
|
|
141
|
+
if request.path != "/"
|
|
142
|
+
html << "<a href='#{Pathname.new(request.path).parent}'>← Parent directory</a><br><br>"
|
|
143
|
+
else
|
|
144
|
+
html << "<a>Root directory</a><br><br>"
|
|
145
|
+
end
|
|
146
|
+
html << "<table>\n"
|
|
147
|
+
html << "\t<tr>\n\t\t<th>File</th>\n\t\t<th>Last modified</th>\n\t\t<th>Size</th>\n\t</tr>\n"
|
|
148
|
+
files = Array.new
|
|
149
|
+
Dir.foreach(File.join(settings.public_folder, request.path), &files.method(:push))
|
|
150
|
+
if files == [".", ".."]
|
|
151
|
+
html << "\t<tr>\n\t\t<th>No files.</th>\n\t\t<th>-</th>\n\t\t<th>-</th>\n\t</tr>"
|
|
152
|
+
else
|
|
153
|
+
files.sort.each do |file|
|
|
154
|
+
html << wrap(file)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
html << "\n</table>\n"
|
|
158
|
+
html << "<br>\n#{options[:readme]}\n" if options[:readme]
|
|
159
|
+
html << "</body>\n</html>\n"
|
|
160
|
+
"#{html}"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
helpers Directory_listing
|
|
166
|
+
end
|
metadata
CHANGED
|
@@ -1,78 +1,75 @@
|
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: directory_listing
|
|
3
|
-
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.7
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
5
4
|
prerelease:
|
|
5
|
+
version: 0.1.0
|
|
6
6
|
platform: ruby
|
|
7
|
-
authors:
|
|
7
|
+
authors:
|
|
8
8
|
- Richard Myers
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
|
|
13
|
+
date: 2013-06-27 00:00:00 Z
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
15
16
|
name: filesize
|
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
|
17
|
-
none: false
|
|
18
|
-
requirements:
|
|
19
|
-
- - ! '>='
|
|
20
|
-
- !ruby/object:Gem::Version
|
|
21
|
-
version: 0.0.2
|
|
22
|
-
type: :runtime
|
|
23
17
|
prerelease: false
|
|
24
|
-
|
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
25
19
|
none: false
|
|
26
|
-
requirements:
|
|
27
|
-
- -
|
|
28
|
-
- !ruby/object:Gem::Version
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
29
23
|
version: 0.0.2
|
|
30
|
-
- !ruby/object:Gem::Dependency
|
|
31
|
-
name: truncate
|
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
|
33
|
-
none: false
|
|
34
|
-
requirements:
|
|
35
|
-
- - ! '>='
|
|
36
|
-
- !ruby/object:Gem::Version
|
|
37
|
-
version: 0.0.4
|
|
38
24
|
type: :runtime
|
|
25
|
+
version_requirements: *id001
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: truncate
|
|
39
28
|
prerelease: false
|
|
40
|
-
|
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
41
30
|
none: false
|
|
42
|
-
requirements:
|
|
43
|
-
- -
|
|
44
|
-
- !ruby/object:Gem::Version
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
45
34
|
version: 0.0.4
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
type: :runtime
|
|
36
|
+
version_requirements: *id002
|
|
37
|
+
description: A Sinatra extension for generating easy, CSS-styled, Apache-like directory listings.
|
|
48
38
|
email: rick.myers@me.com
|
|
49
39
|
executables: []
|
|
40
|
+
|
|
50
41
|
extensions: []
|
|
42
|
+
|
|
51
43
|
extra_rdoc_files: []
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
|
|
45
|
+
files:
|
|
46
|
+
- lib/sinatra/directory_listing.rb
|
|
54
47
|
homepage: https://rubygems.org/gems/directory_listing
|
|
55
48
|
licenses: []
|
|
49
|
+
|
|
56
50
|
post_install_message:
|
|
57
51
|
rdoc_options: []
|
|
58
|
-
|
|
52
|
+
|
|
53
|
+
require_paths:
|
|
59
54
|
- lib
|
|
60
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
61
56
|
none: false
|
|
62
|
-
requirements:
|
|
63
|
-
- -
|
|
64
|
-
- !ruby/object:Gem::Version
|
|
65
|
-
version:
|
|
66
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: "0"
|
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
62
|
none: false
|
|
68
|
-
requirements:
|
|
69
|
-
- -
|
|
70
|
-
- !ruby/object:Gem::Version
|
|
71
|
-
version:
|
|
63
|
+
requirements:
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: "0"
|
|
72
67
|
requirements: []
|
|
68
|
+
|
|
73
69
|
rubyforge_project:
|
|
74
|
-
rubygems_version: 1.8.
|
|
70
|
+
rubygems_version: 1.8.23
|
|
75
71
|
signing_key:
|
|
76
72
|
specification_version: 3
|
|
77
73
|
summary: Easy, CSS-styled, Apache-like directory listings for Sinatra.
|
|
78
74
|
test_files: []
|
|
75
|
+
|
data/lib/directory_listing.rb
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
require 'truncate'
|
|
2
|
-
require 'filesize'
|
|
3
|
-
require 'pathname'
|
|
4
|
-
|
|
5
|
-
# = Easy, CSS-styled, Apache-like directory listings for Sinatra.
|
|
6
|
-
#
|
|
7
|
-
# == Usage
|
|
8
|
-
#
|
|
9
|
-
# Directory_listing.list will return HTML, so the following is a complete Sinatra
|
|
10
|
-
# app that will provide a directory listing of whatever path you navigate to
|
|
11
|
-
# and let you view any file that is served directly:
|
|
12
|
-
#
|
|
13
|
-
# require 'directory_listing'
|
|
14
|
-
#
|
|
15
|
-
# get '*' do |path|
|
|
16
|
-
# if File.exist?(File.join(settings.public_folder, path))
|
|
17
|
-
# if File.directory?(File.join(settings.public_folder, path))
|
|
18
|
-
# "#{Directory_listing.list(
|
|
19
|
-
# :directory => path,
|
|
20
|
-
# :sinatra_public => settings.public_folder
|
|
21
|
-
# )}"
|
|
22
|
-
# else
|
|
23
|
-
# send_file File.join(settings.public_folder, path)
|
|
24
|
-
# end
|
|
25
|
-
# else
|
|
26
|
-
# not_found
|
|
27
|
-
# end
|
|
28
|
-
# end
|
|
29
|
-
#
|
|
30
|
-
# not_found do
|
|
31
|
-
# 'Try again.'
|
|
32
|
-
# end
|
|
33
|
-
#
|
|
34
|
-
# Any option key may be omitted except for :directory and :sinatra_public. Explanations of options are below.
|
|
35
|
-
#
|
|
36
|
-
# == Options
|
|
37
|
-
#
|
|
38
|
-
# directory # the directory to list
|
|
39
|
-
# sinatra_public # sinatra's public folder - your public folder (and the default) is likely "settings.public_folder"
|
|
40
|
-
# stylesheet # a stylesheet that will be added to the <head> of the generated directory listing
|
|
41
|
-
# readme # an HTML string that will be appended at the footer of the generated directory listing
|
|
42
|
-
# should_list_invisibles # whether the directory listing should include invisibles (dotfiles) - "yes" or "no"
|
|
43
|
-
# last_modified_format # format for last modified date (http://www.ruby-doc.org/core-2.0/Time.html) - defaults to "%Y-%m-%d %H:%M:%S"
|
|
44
|
-
# filename_truncate_length # (integer) length to truncate file names to - defaults to 40
|
|
45
|
-
#
|
|
46
|
-
# == Styling
|
|
47
|
-
#
|
|
48
|
-
# It's pretty easy to figure out how to style directory_listing by looking at the source, but here are some gotchas:
|
|
49
|
-
#
|
|
50
|
-
# Every item listed is a <td> element in a table. Directories will have a class of "dir" and regular files will have a class of "file".
|
|
51
|
-
#
|
|
52
|
-
# You can style the "File" column with this CSS:
|
|
53
|
-
#
|
|
54
|
-
# table tr > td:first-child {
|
|
55
|
-
# text-align: left;
|
|
56
|
-
# }
|
|
57
|
-
#
|
|
58
|
-
# Second column:
|
|
59
|
-
# table tr > td:first-child + td {
|
|
60
|
-
# text-align: left;
|
|
61
|
-
# }
|
|
62
|
-
#
|
|
63
|
-
# Third column:
|
|
64
|
-
# table tr > td:first-child + td + td {
|
|
65
|
-
# text-align: left;
|
|
66
|
-
# }
|
|
67
|
-
|
|
68
|
-
module Directory_listing
|
|
69
|
-
@@options = {}
|
|
70
|
-
|
|
71
|
-
def self.options=(value)
|
|
72
|
-
@@options = value
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def self.options()
|
|
76
|
-
@@options
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def self.list(options)
|
|
80
|
-
options = @@options.merge options
|
|
81
|
-
raise(ArgumentError, ":directory is required") unless options[:directory]
|
|
82
|
-
raise(ArgumentError, ":sinatra_public is required") unless options[:sinatra_public]
|
|
83
|
-
pub = options[:sinatra_public]
|
|
84
|
-
dir = File.join(pub, options[:directory])
|
|
85
|
-
|
|
86
|
-
if options[:should_list_invisibles]
|
|
87
|
-
$should_list_invisibles = options[:should_list_invisibles]
|
|
88
|
-
else
|
|
89
|
-
$should_list_invisibles = "no"
|
|
90
|
-
end
|
|
91
|
-
if options[:last_modified_format]
|
|
92
|
-
$last_modified_format = options[:last_modified_format]
|
|
93
|
-
else
|
|
94
|
-
$last_modified_format = "%Y-%m-%d %H:%M:%S"
|
|
95
|
-
end
|
|
96
|
-
if options[:filename_truncate_length]
|
|
97
|
-
$filename_truncate_length = options[:filename_truncate_length]
|
|
98
|
-
else
|
|
99
|
-
$filename_truncate_length = 40
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
html = "<html>\n<head>\n"
|
|
103
|
-
html << "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n"
|
|
104
|
-
if options[:stylesheet]
|
|
105
|
-
html << "<link rel=\"stylesheet\" type=\"text/css\" href=\"/#{options[:stylesheet].sub(/^[\/]*/,"")}\">\n"
|
|
106
|
-
end
|
|
107
|
-
html << "</head>\n<body>\n"
|
|
108
|
-
html << "<h1>Index of #{options[:directory]}</h1>\n"
|
|
109
|
-
if options[:directory] != "/"
|
|
110
|
-
html << "<a href='#{Pathname.new(options[:directory]).parent}'>← Parent directory</a><br><br>"
|
|
111
|
-
else
|
|
112
|
-
html << "<a>Root directory</a><br><br>"
|
|
113
|
-
end
|
|
114
|
-
html << "<table>\n"
|
|
115
|
-
html << "\t<tr>\n\t\t<th>File</th>\n\t\t<th>Last modified</th>\n\t\t<th>Size</th>\n\t</tr>\n"
|
|
116
|
-
files = Array.new
|
|
117
|
-
Dir.foreach(dir, &files.method(:push))
|
|
118
|
-
if files == [".", ".."]
|
|
119
|
-
html << "\t<tr>\n\t\t<th>No files.</th>\n\t\t<th>-</th>\n\t\t<th>-</th>\n\t</tr>"
|
|
120
|
-
else
|
|
121
|
-
files.sort.each do |file|
|
|
122
|
-
html << wrap(file, dir, pub)
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
html << "\n</table>\n"
|
|
126
|
-
html << "<br>\n#{options[:readme]}\n" if options[:readme]
|
|
127
|
-
html << "</body>\n</html>\n"
|
|
128
|
-
"#{html}"
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
private
|
|
132
|
-
|
|
133
|
-
def self.m_time(file, dir)
|
|
134
|
-
time = "\t<td>#{File.mtime(File.join(dir, file)).strftime $last_modified_format}</td>"
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def self.size(file, dir)
|
|
138
|
-
if File.directory?(File.join(dir, file))
|
|
139
|
-
"\t<td>-</td>"
|
|
140
|
-
else
|
|
141
|
-
size = Filesize.from("#{File.stat(File.join(dir, file)).size} B").pretty
|
|
142
|
-
"\t<td>#{size}</td>"
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def self.name(file, dir, pub)
|
|
147
|
-
tfile = file.truncate($filename_truncate_length, '...')
|
|
148
|
-
if (Pathname.new(dir).cleanpath).eql?((Pathname.new(pub)).cleanpath)
|
|
149
|
-
link = file
|
|
150
|
-
else
|
|
151
|
-
link = File.join(dir.split("/").last, file)
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
html = ""
|
|
155
|
-
if File.directory?(File.join(dir, file))
|
|
156
|
-
html << "\t<td class='dir'><a href='#{link}'>#{tfile}</a></td>"
|
|
157
|
-
else
|
|
158
|
-
html << "\t<td class='file'><a href='#{link}'>#{tfile}</a></td>"
|
|
159
|
-
end
|
|
160
|
-
"#{html}"
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def self.wrap(file, dir, pub)
|
|
164
|
-
wrapped = ""
|
|
165
|
-
if $should_list_invisibles == "yes"
|
|
166
|
-
wrapped << "\n\t<tr>
|
|
167
|
-
#{name(file, dir, pub)}
|
|
168
|
-
#{m_time(file, dir)}
|
|
169
|
-
#{size(file, dir)}\n\t</tr>"
|
|
170
|
-
else
|
|
171
|
-
if file[0] != "."
|
|
172
|
-
wrapped << "\n\t<tr>
|
|
173
|
-
#{name(file, dir, pub)}
|
|
174
|
-
#{m_time(file, dir)}
|
|
175
|
-
#{size(file, dir)}\n\t</tr>"
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
"#{wrapped}"
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
end
|