httpit 0.4 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +7 -0
- data/Gemfile.lock +30 -0
- data/README.md +1 -1
- data/bin/httpit +111 -90
- data/example/index.haml +9 -6
- data/example/testing_design/_header.haml +3 -0
- data/example/testing_design/index.haml +50 -0
- data/example/testing_design/layout.sass +56 -0
- data/httpit.gemspec +6 -6
- data/views/listing.haml +55 -86
- data/views/utils.js +13 -0
- metadata +47 -26
- data/lib/search.rb +0 -34
- data/lib/search/dystopia.rb +0 -65
- data/lib/search/find.rb +0 -16
- data/views/search.haml +0 -12
- data/views/search.js +0 -59
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
httpit (0.4.2)
|
5
|
+
RedCloth (~> 4.2.9)
|
6
|
+
haml (~> 4.0.2)
|
7
|
+
sass (~> 3.2.8)
|
8
|
+
sinatra (~> 1.4.2)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
RedCloth (4.2.9)
|
14
|
+
haml (4.0.2)
|
15
|
+
tilt
|
16
|
+
rack (1.5.2)
|
17
|
+
rack-protection (1.5.0)
|
18
|
+
rack
|
19
|
+
sass (3.2.8)
|
20
|
+
sinatra (1.4.2)
|
21
|
+
rack (~> 1.5, >= 1.5.2)
|
22
|
+
rack-protection (~> 1.4)
|
23
|
+
tilt (~> 1.3, >= 1.3.4)
|
24
|
+
tilt (1.3.7)
|
25
|
+
|
26
|
+
PLATFORMS
|
27
|
+
ruby
|
28
|
+
|
29
|
+
DEPENDENCIES
|
30
|
+
httpit!
|
data/README.md
CHANGED
data/bin/httpit
CHANGED
@@ -1,21 +1,23 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require "rubygems"
|
3
|
+
require "bundler/setup"
|
2
4
|
|
3
|
-
require '
|
4
|
-
require 'sinatra'
|
5
|
+
require 'sinatra/base'
|
5
6
|
require 'haml'
|
7
|
+
require 'sass'
|
6
8
|
require 'redcloth'
|
7
9
|
require "pathname"
|
10
|
+
require "fileutils"
|
8
11
|
|
9
12
|
GEM_ROOT = Pathname.new(__FILE__).dirname.join("..").expand_path
|
10
|
-
|
11
|
-
require GEM_ROOT + "lib/search"
|
12
|
-
|
13
13
|
ROOT = Pathname.pwd
|
14
14
|
|
15
|
+
TMP_DIR = File.expand_path("#{Dir.tmpdir}/#{Time.now.to_i}#{rand(1000)}/")
|
16
|
+
FileUtils.mkdir_p(TMP_DIR)
|
17
|
+
|
15
18
|
# this hack allow
|
16
19
|
# /some/folder/with/content + /subfolder => /some/folder/with/content/subfolder
|
17
|
-
|
18
|
-
class <<ROOT
|
20
|
+
class << ROOT
|
19
21
|
def join(*args)
|
20
22
|
super *args.map{|a| a.is_a?(String) && a[0] == ?/ ? a[1 .. a.size] : a }
|
21
23
|
end
|
@@ -25,105 +27,124 @@ class <<ROOT
|
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
28
|
-
set :views, ROOT
|
29
|
-
set :public_folder, ROOT
|
30
|
-
set :app_file, $0
|
31
|
-
|
32
|
-
set :static, false
|
33
|
-
|
34
30
|
# only one parametr - port number
|
35
31
|
if ARGV.size > 0
|
36
32
|
set :port, ARGV.first.to_i
|
37
33
|
end
|
38
34
|
|
35
|
+
class HttpIt < Sinatra::Base
|
36
|
+
set :views, ROOT
|
37
|
+
set :public_folder, ROOT
|
38
|
+
set :app_file, $0
|
39
|
+
set :static, false
|
40
|
+
set :sass, :cache => true, :cache_location => File.join(TMP_DIR, 'sass-cache')
|
39
41
|
|
40
|
-
# build array of contents and theris type for specified folder
|
41
|
-
def get_content(folder = nil, sort = nil)
|
42
|
-
|
43
|
-
|
44
|
-
# build array if pairs: [filename, :type, is_textfile]
|
45
|
-
sorter = case sort
|
46
|
-
when 'name' then '| sort -f'
|
47
|
-
when 'ctime' then '-c'
|
48
|
-
when 'mtime' then '--sort=time'
|
49
|
-
when 'size' then '--sort=size'
|
50
|
-
else ''
|
51
|
-
end
|
42
|
+
# build array of contents and theris type for specified folder
|
43
|
+
def get_content(folder = nil, sort = nil)
|
44
|
+
abs_path = folder ? ROOT + folder : ROOT
|
52
45
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
46
|
+
# build array if pairs: [filename, :type, is_textfile]
|
47
|
+
sorter = case sort
|
48
|
+
when 'name' then '| sort -f'
|
49
|
+
when 'ctime' then '-c'
|
50
|
+
when 'mtime' then '--sort=time'
|
51
|
+
when 'size' then '--sort=size'
|
52
|
+
else ''
|
53
|
+
end
|
54
|
+
|
55
|
+
`cd "#{abs_path.to_s.gsub(?", '\"')}" && ls -A #{sorter}`.split("\n").map do |obj|
|
56
|
+
file_path = abs_path + obj
|
57
|
+
[obj,
|
58
|
+
if file_path.file?; :file
|
59
|
+
elsif file_path.directory?; :dir
|
60
|
+
elsif file_path.symlink?; :link
|
61
|
+
end,
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
+
!!`file "#{file_path.to_s.gsub(?", '\"')}"`.sub(file_path.to_s, '').index(/text/i)
|
64
|
+
]
|
65
|
+
end
|
63
66
|
end
|
64
|
-
end
|
65
67
|
|
66
|
-
def view(tpl)
|
67
|
-
|
68
|
-
end
|
68
|
+
def view(tpl)
|
69
|
+
Pathname.new(__FILE__).dirname.join("../views/#{tpl}.haml").expand_path.read
|
70
|
+
end
|
69
71
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
elsif File.file?('./index.haml')
|
77
|
-
haml view(:index)
|
78
|
-
else
|
79
|
-
@path = ''
|
80
|
-
@files = get_content(nil, params[:sort]).select {|f| f[0] != '.' && f[0] != '..' }
|
81
|
-
haml view(:listing)
|
72
|
+
def folder_view(tpl, format)
|
73
|
+
if ROOT.join("#{tpl}.#{format}").file?
|
74
|
+
tpl.to_sym
|
75
|
+
else
|
76
|
+
nil
|
77
|
+
end
|
82
78
|
end
|
83
|
-
end
|
84
79
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
80
|
+
# shows index.html or folder contents if index.html does not exists
|
81
|
+
get '/' do
|
82
|
+
if ROOT.join('./index.html').file?
|
83
|
+
ROOT.join('./index.html').read
|
84
|
+
elsif folder_view(:index, :haml)
|
85
|
+
haml folder_view(:index, :haml)
|
86
|
+
else
|
87
|
+
@path = ''
|
88
|
+
@files = get_content(nil, params[:sort]).select {|f| f[0] != '.' && f[0] != '..' }
|
89
|
+
haml view(:listing)
|
90
|
+
end
|
91
|
+
end
|
94
92
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
content_type :css
|
105
|
-
sass @path.chomp('.sass.css').to_sym
|
106
|
-
|
107
|
-
elsif !abs_path.file? && !abs_path.directory?
|
108
|
-
halt 404
|
93
|
+
get '/__img_preview' do
|
94
|
+
params[:file] = params[:file].gsub(' ', '\ ')
|
95
|
+
tmppath = "/tmp/httpit_preview_#{Time.now.to_i}.jpeg"
|
96
|
+
`convert #{ROOT + params[:file]} -resize 1024 -quality 100% #{tmppath}`
|
97
|
+
content_type "image/jpeg"
|
98
|
+
content = File.open(tmppath, 'rb') { |f| f.read }
|
99
|
+
File.delete(tmppath)
|
100
|
+
content
|
101
|
+
end
|
109
102
|
|
110
|
-
|
111
|
-
|
112
|
-
return
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
103
|
+
# shows folder contents
|
104
|
+
get %r{.+} do
|
105
|
+
return nil if request.path == '/favicon.ico'
|
106
|
+
@path = URI.unescape(request.path)
|
107
|
+
|
108
|
+
abs_path = ROOT + @path
|
109
|
+
@dirname = abs_path.file? ? File.dirname(@path) : @path.chomp('/')
|
110
|
+
|
111
|
+
if @path =~ /.+\.sass\.css/
|
112
|
+
return halt(404) unless File.file?(abs_path.to_s.chomp('.css'))
|
113
|
+
content_type :css
|
114
|
+
sass @path.chomp('.sass.css').to_sym
|
115
|
+
|
116
|
+
elsif !abs_path.file? && !abs_path.directory?
|
117
|
+
halt 404
|
118
|
+
|
119
|
+
elsif @path =~ /.+\.md/
|
120
|
+
content_type :html
|
121
|
+
return RedCloth.new(abs_path.read).to_html
|
119
122
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
+
elsif @path =~ /.+\.haml/
|
124
|
+
haml @path.chomp('.haml').to_sym
|
125
|
+
|
126
|
+
elsif File.file?(abs_path)
|
127
|
+
send_file(abs_path)
|
128
|
+
|
129
|
+
elsif abs_path.join('./index.html').file?
|
130
|
+
content_type :html
|
131
|
+
abs_path.join('./index.html').read
|
132
|
+
|
133
|
+
elsif abs_path.join('./index.haml').file?
|
134
|
+
content_type :html
|
135
|
+
haml File.join(@path, 'index').to_sym
|
136
|
+
|
137
|
+
else
|
138
|
+
@files = get_content(@path, params[:sort])
|
139
|
+
haml view(:listing)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
error 404 do
|
144
|
+
@path = request.path
|
145
|
+
haml view(:not_found)
|
123
146
|
end
|
124
147
|
end
|
125
148
|
|
126
|
-
|
127
|
-
|
128
|
-
haml view(:not_found)
|
129
|
-
end
|
149
|
+
HttpIt.run!
|
150
|
+
at_exit { FileUtils.rm_rf(TMP_DIR) if File.exists?(TMP_DIR) }
|
data/example/index.haml
CHANGED
@@ -10,20 +10,23 @@
|
|
10
10
|
%body
|
11
11
|
#wrap
|
12
12
|
%h1 HttpIt is awesome
|
13
|
-
|
13
|
+
|
14
14
|
%pre.code.usage
|
15
15
|
:preserve
|
16
|
-
$
|
16
|
+
$ gem install httpit
|
17
17
|
$ cd /folder/for/server
|
18
18
|
$ httpit
|
19
19
|
# or you can set port
|
20
|
-
$ httpit
|
20
|
+
$ httpit 8889
|
21
21
|
|
22
22
|
%p
|
23
23
|
%a{ :href => "images/bird.jpg" } Static file
|
24
|
-
|
24
|
+
|
25
25
|
%p
|
26
26
|
%a{ :href => "readme.md" } MarkDown example
|
27
|
-
|
27
|
+
|
28
|
+
%p
|
29
|
+
%a{ :href => "images" } Gallery folder
|
30
|
+
|
28
31
|
%p
|
29
|
-
%a{ :href => "
|
32
|
+
%a{ :href => "testing_design" } Full-stack layout example
|
@@ -0,0 +1,50 @@
|
|
1
|
+
!!! 5
|
2
|
+
%html{:lang => "en"}
|
3
|
+
%head
|
4
|
+
%meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/
|
5
|
+
%title Testing layout
|
6
|
+
%link{:rel => "stylesheet", :type => "text/css", :href => "#{@dirname}/layout.sass.css"}
|
7
|
+
|
8
|
+
%body
|
9
|
+
#wrapper
|
10
|
+
= haml :"#{@dirname}/_header"
|
11
|
+
.content
|
12
|
+
.top-line
|
13
|
+
This is example layout to show how gem "#{"<b>httpit</b>"}" in action
|
14
|
+
|
15
|
+
%aside>
|
16
|
+
%h4 For example:
|
17
|
+
%ul
|
18
|
+
%li 2/1 = 2.0
|
19
|
+
%li 3/2 = 1.5
|
20
|
+
%li 5/3 = 1.67
|
21
|
+
%li 8/5 = 1.6
|
22
|
+
%li 13/8 = 1.625
|
23
|
+
%li 21/13 = 1.615
|
24
|
+
%li 34/21 = 1.619
|
25
|
+
%li 55/34 = 1.6176
|
26
|
+
|
27
|
+
.main-column>
|
28
|
+
%h3 The Fibonacci Sequence
|
29
|
+
%p
|
30
|
+
The mathematics behind the golden ratio is heavily connected to the
|
31
|
+
= succeed "." do
|
32
|
+
%a{:href => "http://en.wikipedia.org/wiki/Fibonacci_sequence"} Fibonacci Sequence
|
33
|
+
If you’re unfamiliar with the fibonacci sequence,
|
34
|
+
it begins by definition with the numbers 0, 1 and then each successive number
|
35
|
+
in the sequence is the sum of the previous two numbers.
|
36
|
+
|
37
|
+
%p 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55…
|
38
|
+
|
39
|
+
%p
|
40
|
+
I’ll spare you the deep mathematics talk (we’ll just do a bit of division),
|
41
|
+
since what we’re mainly interested in is how the sequence relates to the
|
42
|
+
= succeed "." do
|
43
|
+
%a{:href => "http://freemasonry.bcy.ca/symbolism/golden_ratio/index.html"} golden section
|
44
|
+
|
45
|
+
%p
|
46
|
+
If you take any number in the sequence and divide it by the previous
|
47
|
+
number the result approximates Phi or the golden ratio.
|
48
|
+
%p
|
49
|
+
With early numbers in the sequence this may not appear to be true,
|
50
|
+
but as we continue along the sequence the division approaches 1.618 rather quickly.
|
@@ -0,0 +1,56 @@
|
|
1
|
+
$line: 20px
|
2
|
+
$pageWidth: 800px
|
3
|
+
$asideRation: 5 / 21
|
4
|
+
body
|
5
|
+
:margin 0
|
6
|
+
:padding 0
|
7
|
+
:font
|
8
|
+
:size 14px
|
9
|
+
:family Arial, sans-serif
|
10
|
+
a
|
11
|
+
:color #2468a5
|
12
|
+
> #wrapper
|
13
|
+
:width $pageWidth
|
14
|
+
:margin $line auto
|
15
|
+
> header
|
16
|
+
:border-bottom 1px solid #ccc
|
17
|
+
:margin-bottom $line
|
18
|
+
h1
|
19
|
+
:color #36333e
|
20
|
+
:margin-bottom $line / -2
|
21
|
+
:font-family serif
|
22
|
+
h2
|
23
|
+
:color #393e4d
|
24
|
+
:font-size 1.3em
|
25
|
+
|
26
|
+
> .content
|
27
|
+
.top-line
|
28
|
+
:text-align center
|
29
|
+
:font-style italic
|
30
|
+
:background #f6e5e4
|
31
|
+
:padding $line / 2 0
|
32
|
+
:margin-bottom $line
|
33
|
+
> aside, > .main-column
|
34
|
+
:display inline-block
|
35
|
+
:vertical-align top
|
36
|
+
:line-height 23px
|
37
|
+
h3
|
38
|
+
:margin
|
39
|
+
:bottom 23px
|
40
|
+
:top 0
|
41
|
+
p
|
42
|
+
:margin-bottom 23px
|
43
|
+
> aside
|
44
|
+
:margin-top 46px
|
45
|
+
:width $asideRation * $pageWidth
|
46
|
+
:line-height 20px
|
47
|
+
h4
|
48
|
+
:margin
|
49
|
+
:bottom 11px
|
50
|
+
:top 0px
|
51
|
+
:color #393e4d
|
52
|
+
ul
|
53
|
+
:margin 0
|
54
|
+
:padding-left 17px
|
55
|
+
> .main-column
|
56
|
+
:width $pageWidth - $asideRation * $pageWidth
|
data/httpit.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "httpit"
|
3
|
-
s.version = "0.4"
|
3
|
+
s.version = "0.4.2"
|
4
4
|
s.summary = "Web server for static files"
|
5
|
-
s.description = "Just go to folder and run `httpit`"
|
5
|
+
s.description = "Just go to folder and run `httpit` to make it avaliable as web-server"
|
6
6
|
s.author = "Pavel Evstigneev"
|
7
7
|
s.email = "pavel.evst@gmail.com"
|
8
8
|
s.homepage = "http://github.com/Paxa/httpit"
|
@@ -11,8 +11,8 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.rubyforge_project = "httpit"
|
12
12
|
s.files = `git ls-files`.split("\n")
|
13
13
|
|
14
|
-
s.add_runtime_dependency 'sinatra', "
|
15
|
-
s.add_runtime_dependency 'haml', '
|
16
|
-
s.add_runtime_dependency 'RedCloth', "
|
17
|
-
s.add_runtime_dependency '
|
14
|
+
s.add_runtime_dependency 'sinatra', "~> 1.4.2"
|
15
|
+
s.add_runtime_dependency 'haml', '~> 4.0.2'
|
16
|
+
s.add_runtime_dependency 'RedCloth', "~> 4.2.9"
|
17
|
+
s.add_runtime_dependency 'sass', "~> 3.2.8"
|
18
18
|
end
|
data/views/listing.haml
CHANGED
@@ -1,93 +1,62 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
:
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
ul, li
|
11
|
-
:list-style-type none
|
12
|
-
|
13
|
-
ul > header
|
14
|
-
:font-style italic
|
15
|
-
:margin-bottom 11px
|
16
|
-
|
17
|
-
.preview_link
|
18
|
-
:color #55a075
|
19
|
-
:margin-left 20px
|
20
|
-
|
21
|
-
input[type=search]
|
22
|
-
:width 300px
|
23
|
-
input[type=submit]
|
24
|
-
:display none
|
25
|
-
|
26
|
-
= box-shadow($value)
|
27
|
-
:box-shadow $value
|
28
|
-
:-moz-box-shadow $value
|
29
|
-
:-webkit-box-shadow $value
|
30
|
-
|
31
|
-
#files_search
|
32
|
-
> .results
|
33
|
-
:display none
|
34
|
-
:background #fff
|
35
|
-
+box-shadow(1px 1px 5px rgba(125, 125, 125, 0.7))
|
36
|
-
:width 620px
|
37
|
-
:position relative
|
38
|
-
:top 7px
|
39
|
-
:padding 5px 15px
|
40
|
-
em
|
41
|
-
:background-color yellow
|
42
|
-
ul
|
43
|
-
:padding 0
|
44
|
-
:margin 0
|
45
|
-
li
|
46
|
-
:margin 3px 0
|
47
|
-
:font-size 13px
|
48
|
-
&:hover
|
49
|
-
:background-color #def
|
50
|
-
&.loading
|
51
|
-
> .results
|
52
|
-
:display block
|
53
|
-
</style>
|
1
|
+
!!! 5
|
2
|
+
%html(lang="en")
|
3
|
+
%head
|
4
|
+
<style type="text/css">
|
5
|
+
:sass
|
6
|
+
#wrap
|
7
|
+
:width 800px
|
8
|
+
:margin 30 auto 50px
|
54
9
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
10
|
+
span
|
11
|
+
:color #777
|
12
|
+
|
13
|
+
ul, li
|
14
|
+
:list-style-type none
|
15
|
+
|
16
|
+
ul > header
|
17
|
+
:font-style italic
|
18
|
+
:margin-bottom 11px
|
19
|
+
|
20
|
+
.preview_link
|
21
|
+
:color #55a075
|
22
|
+
:margin-left 20px
|
23
|
+
|
24
|
+
input[type=search]
|
25
|
+
:width 300px
|
26
|
+
input[type=submit]
|
27
|
+
:display none
|
28
|
+
</style>
|
29
|
+
|
30
|
+
%body
|
31
|
+
#wrap
|
32
|
+
%h1
|
33
|
+
%span Folder:
|
34
|
+
= @path == '' ? '/' : @path
|
35
|
+
- if @path != ''
|
36
|
+
%a{:href => @path.gsub(%r{/[^/]+/?$}, '') + '/'} ←
|
68
37
|
|
69
38
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
39
|
+
%ul
|
40
|
+
%header
|
41
|
+
Sort
|
42
|
+
%select.sorting
|
43
|
+
- for key in %w{name size ctime mtime}
|
44
|
+
%option{params[:sort] == key ? {:selected => "selected"} : {}}= key
|
76
45
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
46
|
+
- for file in @files
|
47
|
+
%li
|
48
|
+
- if file[1] == :file
|
49
|
+
%span= "–"
|
50
|
+
- elsif file[1] == :dir
|
51
|
+
%span= "+"
|
52
|
+
- elsif file[1] == :link
|
53
|
+
%span= "→"
|
85
54
|
|
86
|
-
|
55
|
+
%a{:href => "#{@path}/#{file[0]}"}= file[0]
|
87
56
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
57
|
+
- if %w{.jpg .jpeg .png .gif}.include?(File.extname(file[0]).downcase)
|
58
|
+
%a{:href => "/__img_preview?file=#{@path}/#{file[0]}", :class => "preview_link"} #1024
|
59
|
+
- if file[2]
|
60
|
+
%a{:href => "/__view?file=#{@path}/#{file[0]}", :class => "preview_link"} view
|
92
61
|
|
93
|
-
%script{:type => "text/javascript"}= GEM_ROOT.join('views/
|
62
|
+
%script{:type => "text/javascript"}= GEM_ROOT.join('views/utils.js').read
|
data/views/utils.js
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
function $ (selector) {
|
2
|
+
return document.querySelector(selector);
|
3
|
+
};
|
4
|
+
|
5
|
+
function $$ (selector) {
|
6
|
+
return document.querySelectorAll(selector);
|
7
|
+
};
|
8
|
+
|
9
|
+
$('.sorting').addEventListener('change', function(e) {
|
10
|
+
var clean_path = (window.location + '').replace(/(\?|&)sort=[^=]*/, '');
|
11
|
+
clean_path += (clean_path.indexOf('?') == -1 ? '?' : '&') + 'sort=' + e.target.value
|
12
|
+
window.location = clean_path;
|
13
|
+
}, false);
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httpit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,53 +9,73 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-04-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 1.4.2
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.4.2
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: haml
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
|
-
- -
|
35
|
+
- - ~>
|
31
36
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
37
|
+
version: 4.0.2
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 4.0.2
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: RedCloth
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
|
-
- -
|
51
|
+
- - ~>
|
42
52
|
- !ruby/object:Gem::Version
|
43
|
-
version: 4.2.
|
53
|
+
version: 4.2.9
|
44
54
|
type: :runtime
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 4.2.9
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
49
|
-
requirement:
|
63
|
+
name: sass
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
|
-
- -
|
67
|
+
- - ~>
|
53
68
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
69
|
+
version: 3.2.8
|
55
70
|
type: :runtime
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
58
|
-
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 3.2.8
|
78
|
+
description: Just go to folder and run `httpit` to make it avaliable as web-server
|
59
79
|
email: pavel.evst@gmail.com
|
60
80
|
executables:
|
61
81
|
- httpit
|
@@ -63,20 +83,21 @@ extensions: []
|
|
63
83
|
extra_rdoc_files: []
|
64
84
|
files:
|
65
85
|
- .gitignore
|
86
|
+
- Gemfile
|
87
|
+
- Gemfile.lock
|
66
88
|
- README.md
|
67
89
|
- bin/httpit
|
68
90
|
- example/images/bird.jpg
|
69
91
|
- example/index.haml
|
70
92
|
- example/main.sass
|
71
93
|
- example/readme.md
|
94
|
+
- example/testing_design/_header.haml
|
95
|
+
- example/testing_design/index.haml
|
96
|
+
- example/testing_design/layout.sass
|
72
97
|
- httpit.gemspec
|
73
|
-
- lib/search.rb
|
74
|
-
- lib/search/dystopia.rb
|
75
|
-
- lib/search/find.rb
|
76
98
|
- views/listing.haml
|
77
99
|
- views/not_found.haml
|
78
|
-
- views/
|
79
|
-
- views/search.js
|
100
|
+
- views/utils.js
|
80
101
|
- views/view.haml
|
81
102
|
homepage: http://github.com/Paxa/httpit
|
82
103
|
licenses: []
|
@@ -98,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
119
|
version: '0'
|
99
120
|
requirements: []
|
100
121
|
rubyforge_project: httpit
|
101
|
-
rubygems_version: 1.8.
|
122
|
+
rubygems_version: 1.8.24
|
102
123
|
signing_key:
|
103
124
|
specification_version: 3
|
104
125
|
summary: Web server for static files
|
data/lib/search.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
module Search
|
2
|
-
def engine=(value)
|
3
|
-
@engine = value
|
4
|
-
end
|
5
|
-
|
6
|
-
def engine; @engine; end
|
7
|
-
|
8
|
-
def self.included(base)
|
9
|
-
base.class_eval do
|
10
|
-
Search.engine = Search::Find #Dystopia
|
11
|
-
|
12
|
-
get '/__search' do
|
13
|
-
@path = ROOT + params[:path].to_s
|
14
|
-
s_time = Time.now.to_f
|
15
|
-
@found = Search.engine.find_in_folder(ROOT, @path, params[:q])
|
16
|
-
@total_time = Time.now.to_f - s_time
|
17
|
-
|
18
|
-
haml view(:search)
|
19
|
-
end
|
20
|
-
|
21
|
-
get '/__view' do
|
22
|
-
if !`file "#{ROOT.join(params[:file])}"`.index('text')
|
23
|
-
redirect params[:file]
|
24
|
-
return
|
25
|
-
end
|
26
|
-
@content = ROOT.join(params[:file]).read
|
27
|
-
haml view(:view)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
require GEM_ROOT + "lib/search/find"
|
34
|
-
require GEM_ROOT + "lib/search/dystopia"
|
data/lib/search/dystopia.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
require 'rufus/tokyo/dystopia'
|
4
|
-
require 'digest'
|
5
|
-
|
6
|
-
=begin
|
7
|
-
A B : searches for records including the two tokens.
|
8
|
-
A && B : searches for records including the two tokens.
|
9
|
-
A || B : searches for records including the one or both of the two tokens.
|
10
|
-
"A B..." : searches for records including the phrase.
|
11
|
-
[[A]] : searches for records including words exactly matching the token.
|
12
|
-
[[A*]] : searches for records including words beginning with the token.
|
13
|
-
[[*A]] : searches for records including words ending with the token.
|
14
|
-
[[[[A : searches for records beginning with the token.
|
15
|
-
A]]]] : searches for records ending with the token.
|
16
|
-
Note that the priority of "||" is higher than the one of "&&".
|
17
|
-
=end
|
18
|
-
|
19
|
-
module Search::Dystopia
|
20
|
-
extend self
|
21
|
-
|
22
|
-
CMD = "find . -type d \\( -name '*.git*' \\) -prune -o -print"
|
23
|
-
|
24
|
-
def find_in_folder(root, path, needle)
|
25
|
-
files = inst.search(needle).map do |id|
|
26
|
-
doc = inst.fetch(id)
|
27
|
-
doc[0, doc.index("\n")]
|
28
|
-
end
|
29
|
-
|
30
|
-
if path != root
|
31
|
-
subdir = path.to_s.sub(root.to_s + '/', '')
|
32
|
-
files.select {|f| f[0, subdir.size] == subdir }.map {|f| f.sub(subdir + '/', '') }
|
33
|
-
else
|
34
|
-
files
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# return instance of searcher. and make indexing on first search
|
39
|
-
def inst
|
40
|
-
return @inst if @inst
|
41
|
-
db_file = "/tmp/httpit_index_#{Digest::MD5.hexdigest ROOT.to_s}"
|
42
|
-
@inst ||= Rufus::Tokyo::Dystopia::Core.new(db_file)
|
43
|
-
at_exit{ puts("removing #{db_file}"); `rm -r "#{db_file}"` }
|
44
|
-
index_dir()
|
45
|
-
@inst
|
46
|
-
end
|
47
|
-
|
48
|
-
def index_dir()
|
49
|
-
files = `cd #{ROOT.to_s} && #{CMD}`.split("\n")
|
50
|
-
inst.clear
|
51
|
-
|
52
|
-
puts "Indexing #{files.size} files"
|
53
|
-
files.each_with_index do |file, i|
|
54
|
-
next if file[0, 3] == './.'
|
55
|
-
|
56
|
-
# if its a text file store its content
|
57
|
-
content = if `file "#{ROOT.join(file).to_s}"`.index('text')
|
58
|
-
(ROOT + file).read
|
59
|
-
else ""; end
|
60
|
-
inst.store(i, file.sub('./', '') + "\n" + content)
|
61
|
-
end
|
62
|
-
|
63
|
-
inst
|
64
|
-
end
|
65
|
-
end
|
data/lib/search/find.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
module Search::Find
|
2
|
-
extend self
|
3
|
-
CMD = "find . -type d \\( -name '*.git*' \\) -prune -o -exec file -F '&' {} \\; | grep text | cut -d\\& -f1 | sed 's/./\\\\&/g' | xargs -n 1 grep -i -l '###'"
|
4
|
-
CMD_LIST = "find . -type d \\( -name '*.git*' \\) -prune -o -print | grep -i '###'"
|
5
|
-
|
6
|
-
def find_in_folder(root, path, needle)
|
7
|
-
in_filenames = `cd #{path} && #{CMD_LIST.sub('###', needle)}`.split("\n")
|
8
|
-
in_text_files = `cd #{path} && #{CMD.sub('###', needle)}`.split("\n")
|
9
|
-
|
10
|
-
(in_filenames + in_text_files.select {|f| !in_filenames.include?(f) }).map {|f| f.sub('./', '') }
|
11
|
-
end
|
12
|
-
|
13
|
-
#def find_in_file(file, needle)
|
14
|
-
# `cat #{file} | grep -n -B 1 -A 1 '#{needle}'`
|
15
|
-
#end
|
16
|
-
end
|
data/views/search.haml
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
%ul
|
2
|
-
- for file in @found
|
3
|
-
%li<>
|
4
|
-
- if @path.join(file).file?
|
5
|
-
%a{:href => "/__view?file=#{File.join(params[:path], file)}" }= file.gsub(/#{params[:q]}/i) {|m| "<em>#{m}</em>" }
|
6
|
-
- else
|
7
|
-
%a{:href => File.join(params[:path], file)}= file.gsub(/#{params[:q]}/i) {|m| "<em>#{m}</em>" }
|
8
|
-
|
9
|
-
- if @found.size == 0
|
10
|
-
%i Nothing
|
11
|
-
|
12
|
-
%footer= "Complete in #{"%4.3fs" % @total_time}"
|
data/views/search.js
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
Xhr = function (url, data, callback) {
|
2
|
-
var xhr = new XMLHttpRequest();
|
3
|
-
|
4
|
-
xhr.open("GET", url + '?' + data, true);
|
5
|
-
|
6
|
-
xhr.onreadystatechange = function() {
|
7
|
-
if (xhr.readyState == 4 && xhr.status == 200) {
|
8
|
-
callback(xhr.responseText);
|
9
|
-
}
|
10
|
-
};
|
11
|
-
|
12
|
-
xhr.send();
|
13
|
-
};
|
14
|
-
|
15
|
-
// get forms data for xhr request
|
16
|
-
Xhr.formData = function (form) {
|
17
|
-
var results = [];
|
18
|
-
var elements = form.querySelectorAll('input, select, textarea');
|
19
|
-
|
20
|
-
for(k in elements)
|
21
|
-
if (elements.hasOwnProperty(k) && elements[k].name)
|
22
|
-
results.push(elements[k].name + '=' + encodeURIComponent(elements[k].value))
|
23
|
-
|
24
|
-
return results.join('&')
|
25
|
-
};
|
26
|
-
|
27
|
-
function $ (selector) {
|
28
|
-
return document.querySelector(selector);
|
29
|
-
};
|
30
|
-
|
31
|
-
function $$ (selector) {
|
32
|
-
return document.querySelectorAll(selector);
|
33
|
-
};
|
34
|
-
|
35
|
-
$('#files_search').addEventListener('submit', function (e) {
|
36
|
-
var form = e.target;
|
37
|
-
e.preventDefault();
|
38
|
-
|
39
|
-
form.querySelector('.results').innerHTML = 'Finding...';
|
40
|
-
form.className = 'loading';
|
41
|
-
|
42
|
-
new Xhr(form.action, Xhr.formData(form), function(data) {
|
43
|
-
form.querySelector('.results').innerHTML = data;
|
44
|
-
});
|
45
|
-
}, true);
|
46
|
-
|
47
|
-
// hide results when erase search field
|
48
|
-
function hideResults (e) {
|
49
|
-
if (e.target.value == '') $('#files_search').className = '';
|
50
|
-
}
|
51
|
-
$('input[type=search]').addEventListener('change', hideResults, false);
|
52
|
-
$('input[type=search]').addEventListener('keyup', hideResults, false);
|
53
|
-
$('input[type=search]').addEventListener('click', hideResults, false);
|
54
|
-
|
55
|
-
$('.sorting').addEventListener('change', function(e) {
|
56
|
-
var clean_path = (window.location + '').replace(/(\?|&)sort=[^=]*/, '');
|
57
|
-
clean_path += (clean_path.indexOf('?') == -1 ? '?' : '&') + 'sort=' + e.target.value
|
58
|
-
window.location = clean_path;
|
59
|
-
}, false);
|