rack-server-pages 0.0.1
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/.gitignore +11 -0
- data/.travis.yml +6 -0
- data/Gemfile +53 -0
- data/Gemfile.lock +127 -0
- data/Guardfile +16 -0
- data/README.md +401 -0
- data/Rakefile +11 -0
- data/config.ru +13 -0
- data/lib/rack-server-pages.rb +1 -0
- data/lib/rack/server_pages.rb +348 -0
- data/public/README.erb +3 -0
- data/public/_layout.html.erb +9 -0
- data/public/index.html +16 -0
- data/public/info.php +1 -0
- data/public/sample.erb +8 -0
- data/public/style.css +106 -0
- data/rack-server-pages.gemspec +22 -0
- data/spec/lib/rack/server_pages_spec.rb +69 -0
- data/spec/spec_helper.rb +40 -0
- data/views/about.html.slim +11 -0
- data/views/article.html.md +16 -0
- data/views/betty.css.sass +11 -0
- data/views/contact.xml.builder +5 -0
- data/views/examples/_layout.html.erb +14 -0
- data/views/examples/_time.html.erb +1 -0
- data/views/examples/builder.xml.builder +0 -0
- data/views/examples/coffee.js.coffee +0 -0
- data/views/examples/erb.html.erb +2 -0
- data/views/examples/haml.html.haml +6 -0
- data/views/examples/html.html +1 -0
- data/views/examples/index.html.erb +9 -0
- data/views/examples/less.css.less +0 -0
- data/views/examples/liquid.html.liquid +0 -0
- data/views/examples/markaby.html.mab +0 -0
- data/views/examples/markdown.html.markdown +6 -0
- data/views/examples/nokogiri.xml.nokogiri +0 -0
- data/views/examples/radius.html.radius +0 -0
- data/views/examples/rdoc.html.rdoc +0 -0
- data/views/examples/sass.css.sass +11 -0
- data/views/examples/scss.css.scss +0 -0
- data/views/examples/slim.html.slim +2 -0
- data/views/examples/source.html.slim +9 -0
- data/views/examples/textile.html.textile +0 -0
- data/views/examples/wiki.html.wiki +0 -0
- data/views/examples/yajl.json.yajl +0 -0
- data/views/script.js.coffee +13 -0
- metadata +106 -0
data/Rakefile
ADDED
data/config.ru
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'bundler/setup'
|
3
|
+
require './lib/rack/server_pages'
|
4
|
+
|
5
|
+
# Tilt settings
|
6
|
+
require 'tilt'
|
7
|
+
require 'slim'
|
8
|
+
|
9
|
+
# .php as ERB template :)
|
10
|
+
Rack::ServerPages::Template::ERBTemplate.extensions << 'php' # ERBTemplate
|
11
|
+
Tilt.register Tilt::ERBTemplate, 'php' # TiltTemplate
|
12
|
+
|
13
|
+
run Rack::ServerPages
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rack/server_pages"
|
@@ -0,0 +1,348 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'rack'
|
3
|
+
require 'time'
|
4
|
+
require 'rack/utils'
|
5
|
+
require 'rack/mime'
|
6
|
+
require 'rack/logger'
|
7
|
+
require 'forwardable'
|
8
|
+
|
9
|
+
module Rack
|
10
|
+
class ServerPages
|
11
|
+
VERSION = '0.0.1'
|
12
|
+
|
13
|
+
def self.call(env)
|
14
|
+
new.call(env)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.[](options={}, &block)
|
18
|
+
new(nil, options, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(app = nil, options = {})
|
22
|
+
@config = Config.new(*options)
|
23
|
+
yield @config if block_given?
|
24
|
+
@app = app || @config.failure_app || NotFound
|
25
|
+
end
|
26
|
+
|
27
|
+
def call(env)
|
28
|
+
serving(env)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def serving(env)
|
34
|
+
files = find_template_files *evalute_path_info(env['PATH_INFO']) rescue nil
|
35
|
+
|
36
|
+
unless files.nil? or files.empty?
|
37
|
+
file = select_template_file(files)
|
38
|
+
|
39
|
+
if template = Template[file]
|
40
|
+
scope = Binding.new(env)
|
41
|
+
scope.response.tap do |res|
|
42
|
+
catch(:halt) do
|
43
|
+
res.write template.render_with_layout(scope)
|
44
|
+
res['Last-Modified'] ||= ::File.mtime(file).httpdate
|
45
|
+
res['Content-Type'] ||= template.mime_type_with_charset(@config.default_charset)
|
46
|
+
res['Cache-Control'] ||= @config.cache_control if @config.cache_control
|
47
|
+
end
|
48
|
+
end.finish
|
49
|
+
else
|
50
|
+
StaticFile.new(file, @config.cache_control).call(env)
|
51
|
+
end
|
52
|
+
else
|
53
|
+
@app.call(env)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def evalute_path_info(path)
|
58
|
+
if m = path.match(%r!^#{@config.effective_path}/((?:[\w-]+/)+)?([a-zA-Z0-9]\w*)?(\.\w+)?$!)
|
59
|
+
m[1,3] # dir, file, ext
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def find_template_files(dir, file, ext)
|
64
|
+
#path = @config.view_paths.map{|root|"#{root}/#{dir}#{file||'index'}#{ext}{.*,}"}.join("\0") # Ruby 1.8
|
65
|
+
#path = @config.view_paths.map{|root|"#{root}/#{dir}#{file||'index'}#{ext}{.*,}"} # Ruby 1.9
|
66
|
+
#Dir[path].select{|s|s.include?('.')}
|
67
|
+
[].tap do |files| # universal way
|
68
|
+
@config.view_paths.each do |root|
|
69
|
+
files.concat Dir["#{root}/#{dir}#{file||'index'}#{ext}{.*,}"].select{|s|s.include?('.')}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def select_template_file(files)
|
75
|
+
files.first
|
76
|
+
end
|
77
|
+
|
78
|
+
class Config < Hash
|
79
|
+
def self.hash_accessor(*names)
|
80
|
+
names.each do |name|
|
81
|
+
define_method("#{name}=") { |v| self[name] = v }
|
82
|
+
define_method(name) { self[name] }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
hash_accessor :view_path, :effective_path, :cache_control, :default_charset, :failure_app
|
87
|
+
|
88
|
+
def initialize
|
89
|
+
super
|
90
|
+
self[:default_charset] ||= 'utf-8'
|
91
|
+
self[:view_path] ||= %w(views public)
|
92
|
+
end
|
93
|
+
|
94
|
+
def view_paths
|
95
|
+
(v = self[:view_path]).kind_of?(Enumerable) ? v : [v.to_s]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class NotFound
|
100
|
+
def self.call(env)
|
101
|
+
Rack::Response.new(["Not Found: #{env['REQUEST_PATH']}"], 404).finish
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Template
|
106
|
+
def self.[] file
|
107
|
+
engine.new(file).find_template
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.engine
|
111
|
+
defined?(Tilt) ? TiltTemplate : ERBTemplate
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.tilt?
|
115
|
+
engine == TiltTemplate
|
116
|
+
end
|
117
|
+
|
118
|
+
def initialize(file)
|
119
|
+
@file = file
|
120
|
+
end
|
121
|
+
|
122
|
+
def mime_type
|
123
|
+
ext = @file[/(\.\w+)?(?:\.\w+)$/, 1]
|
124
|
+
Mime.mime_type(ext, default_mime_type)
|
125
|
+
end
|
126
|
+
|
127
|
+
def mime_type_with_charset(charset)
|
128
|
+
if (m = mime_type) =~ %r!^(text/\w+|application/(?:javascript|(xhtml\+)?xml|json))$!
|
129
|
+
"#{m}; charset=#{charset}"
|
130
|
+
else
|
131
|
+
m
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def render_with_layout(scope, &block)
|
136
|
+
content = render(scope, &block)
|
137
|
+
if layout = scope.layout and layout_file = Dir["#{layout}{.*,}"].first
|
138
|
+
scope.layout(false)
|
139
|
+
Template[layout_file].render_with_layout(scope) { content }
|
140
|
+
else
|
141
|
+
content
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class TiltTemplate < Template
|
146
|
+
def find_template
|
147
|
+
(@tilt ||= Tilt[@file]) ? self : nil
|
148
|
+
end
|
149
|
+
|
150
|
+
def render(scope, &block)
|
151
|
+
@tilt.new(@file).render(scope, &block)
|
152
|
+
end
|
153
|
+
|
154
|
+
def default_mime_type
|
155
|
+
@tilt.default_mime_type || 'text/html'
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class ERBTemplate < Template
|
160
|
+
require 'erb'
|
161
|
+
|
162
|
+
def self.extensions(ext = nil)
|
163
|
+
@@extensions = ext if ext
|
164
|
+
@@extensions ||= %w(erb rhtml)
|
165
|
+
end
|
166
|
+
|
167
|
+
def find_template
|
168
|
+
(@file =~ /\.(#{@@extensions.join('|')})$/) and ::File.exist?(@file) ? self : nil
|
169
|
+
end
|
170
|
+
|
171
|
+
def render(scope, &block)
|
172
|
+
ERB.new(IO.read(@file)).result(scope._binding(&block))
|
173
|
+
end
|
174
|
+
|
175
|
+
def default_mime_type
|
176
|
+
"text/html"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
class StaticFile < File
|
182
|
+
def initialize(path, cache_control = nil)
|
183
|
+
@path = path
|
184
|
+
@cache_control = cache_control
|
185
|
+
end
|
186
|
+
|
187
|
+
def _call(env)
|
188
|
+
serving(env)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
module CoreHelper
|
193
|
+
def redirect(target, status=302)
|
194
|
+
response.redirect(target, status)
|
195
|
+
halt
|
196
|
+
end
|
197
|
+
|
198
|
+
def partial(file)
|
199
|
+
if tpl_file = Dir["#{file}{.*,}"].first and template = Template[tpl_file]
|
200
|
+
template.render(self)
|
201
|
+
else
|
202
|
+
IO.read(file)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def layout(file = nil)
|
207
|
+
@layout = file unless file.nil?
|
208
|
+
@layout
|
209
|
+
end
|
210
|
+
|
211
|
+
def halt(*args)
|
212
|
+
case args[0]
|
213
|
+
when String
|
214
|
+
response.body = [args[0]]
|
215
|
+
when Fixnum
|
216
|
+
response.status = args[0]
|
217
|
+
case args[1]
|
218
|
+
when Hash
|
219
|
+
response.headers.merge! args[1]
|
220
|
+
response.body = [args[2]]
|
221
|
+
else
|
222
|
+
response.body = [args[1]]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
throw :halt
|
226
|
+
end
|
227
|
+
|
228
|
+
def url(path = "")
|
229
|
+
env['SCRIPT_NAME'] + (path.to_s[0,1]!='/'?'/':'') + path.to_s
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
class Binding
|
234
|
+
extend Forwardable
|
235
|
+
include CoreHelper
|
236
|
+
include ERB::Util
|
237
|
+
|
238
|
+
attr_reader :request, :response
|
239
|
+
|
240
|
+
def_delegators :request, :env, :params, :session, :cookies, :logger
|
241
|
+
def_delegators :response, :headers, :set_cookies, :delete_cookie
|
242
|
+
|
243
|
+
def initialize(env)
|
244
|
+
@request = Rack::Request.new(env)
|
245
|
+
@response = Rack::Response.new
|
246
|
+
@response['Content-Type'] = nil
|
247
|
+
end
|
248
|
+
|
249
|
+
def _binding
|
250
|
+
binding
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
module Rack::ServerPages::Binding::Extra
|
258
|
+
require 'erb'
|
259
|
+
def rubyinfo
|
260
|
+
ERB.new(<<-RUBYINFO).result(binding)
|
261
|
+
<html><head>
|
262
|
+
<style type="text/css"><!--
|
263
|
+
body {background-color: #ffffff; color: #000000;}
|
264
|
+
body, td, th, h1, h2 {font-family: sans-serif;}
|
265
|
+
pre {margin: 0px; font-family: monospace;}
|
266
|
+
a:link {color: #000099; text-decoration: none; background-color: #ffffff;}
|
267
|
+
a:hover {text-decoration: underline;}
|
268
|
+
table {border-collapse: collapse;}
|
269
|
+
.center {text-align: center;}
|
270
|
+
.center table { margin-left: auto; margin-right: auto; text-align: left;}
|
271
|
+
.center th { text-align: center !important; }
|
272
|
+
td, th { border: 1px solid #000000; font-size: 75%; vertical-align: baseline;}
|
273
|
+
h1 {font-size: 150%;}
|
274
|
+
h2 {font-size: 125%;}
|
275
|
+
.p {text-align: left;}
|
276
|
+
.e {background-color: #ccccff; font-weight: bold; color: #000000;}
|
277
|
+
.h {background-color: #9999cc; font-weight: bold; color: #000000;}
|
278
|
+
.v {background-color: #cccccc; color: #000000;}
|
279
|
+
i {color: #666666; background-color: #cccccc;}
|
280
|
+
img {float: right; border: 0px;}
|
281
|
+
hr {width: 600px; background-color: #cccccc; border: 0px; height: 1px; color: #000000;}
|
282
|
+
//--></style>
|
283
|
+
<title>rubyinfo()</title>
|
284
|
+
</head>
|
285
|
+
<body>
|
286
|
+
<div class="center">
|
287
|
+
<table border="0" cellpadding="3" width="600">
|
288
|
+
<tr class="h">
|
289
|
+
<td>
|
290
|
+
<h1 class="p">Rack Server Pages Version <%= Rack::ServerPages::VERSION%></h1>
|
291
|
+
</td>
|
292
|
+
</tr>
|
293
|
+
</table>
|
294
|
+
<br />
|
295
|
+
<h2>Rack Environment</h2>
|
296
|
+
<table border="0" cellpadding="3" width="600">
|
297
|
+
<tr class="h"><th>Variable</th><th>Value</th></tr>
|
298
|
+
<% for key, value in env do %>
|
299
|
+
<tr><td class="e"><%= key %></td><td class="v"><%= value %></td></tr>
|
300
|
+
<% end %>
|
301
|
+
</table>
|
302
|
+
<h2>Ruby</h2>
|
303
|
+
<table border="0" cellpadding="3" width="600">
|
304
|
+
<tr><td class="e">RUBY_VERSION</td><td class="v"><%= RUBY_VERSION %></td></tr>
|
305
|
+
<tr><td class="e">RUBY_PATCHLEVEL</td><td class="v"><%= RUBY_PATCHLEVEL %></td></tr>
|
306
|
+
<tr><td class="e">RUBY_RELEASE_DATE</td><td class="v"><%= RUBY_RELEASE_DATE %></td></tr>
|
307
|
+
<tr><td class="e">RUBY_PLATFORM</td><td class="v"><%= RUBY_PLATFORM %></td></tr>
|
308
|
+
</table>
|
309
|
+
<h2>Environment</h2>
|
310
|
+
<table border="0" cellpadding="3" width="600">
|
311
|
+
<tr class="h"><th>Variable</th><th>Value</th></tr>
|
312
|
+
<% for key, value in ENV do %>
|
313
|
+
<tr><td class="e"><%= key %></td><td class="v"><%= value %></td></tr>
|
314
|
+
<% end %>
|
315
|
+
</table>
|
316
|
+
<% if defined?(Tilt) %>
|
317
|
+
<h2>Tilt</h2>
|
318
|
+
<table border="0" cellpadding="3" width="600">
|
319
|
+
<% for key, value in Tilt.mappings do %>
|
320
|
+
<tr><td class="e"><%= key %></td><td class="v"><%= value %></td></tr>
|
321
|
+
<% end %>
|
322
|
+
</table>
|
323
|
+
<% else %>
|
324
|
+
<h2>ERB Template</h2>
|
325
|
+
<table border="0" cellpadding="3" width="600">
|
326
|
+
<tr><td class="e">extensions</td><td class="v"><%=Rack::ServerPages::Template::ERBTemplate.extensions.join(', ')%></td></tr>
|
327
|
+
</table>
|
328
|
+
<% end %>
|
329
|
+
<h2>Binding</h2>
|
330
|
+
<table border="0" cellpadding="3" width="600">
|
331
|
+
<tr><td class="e">methods</td><td class="v"><%= (methods - Object.methods).join(', ') %></td></tr>
|
332
|
+
</table>
|
333
|
+
<h2>License</h2>
|
334
|
+
<table border="0" cellpadding="3" width="600">
|
335
|
+
<tr class="v"><td>
|
336
|
+
<p>
|
337
|
+
MIT License
|
338
|
+
</p>
|
339
|
+
</td></tr>
|
340
|
+
</table><br />
|
341
|
+
</div>
|
342
|
+
</body>
|
343
|
+
</html>
|
344
|
+
RUBYINFO
|
345
|
+
end
|
346
|
+
alias phpinfo rubyinfo # just a joke :)
|
347
|
+
end
|
348
|
+
Rack::ServerPages::Binding.send(:include, Rack::ServerPages::Binding::Extra)
|
data/public/README.erb
ADDED
data/public/index.html
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>rack-server-pages</title>
|
4
|
+
<link href="./style.css" media="screen" rel="stylesheet" type="text/css" />
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<h1>rack-server-pages</h1>
|
8
|
+
<ul>
|
9
|
+
<li><a href="./examples/">Tilt examples</a></li>
|
10
|
+
<li><a href="./sample">sample.erb</a></li>
|
11
|
+
<li><a href="./info">info.php</a></li>
|
12
|
+
<li><a href="./README">README</a></li>
|
13
|
+
</ul>
|
14
|
+
<a href="http://github.com/migrs/rack-server-pages">github</a>
|
15
|
+
</body>
|
16
|
+
</html>
|
data/public/info.php
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<%= phpinfo() %>
|
data/public/sample.erb
ADDED
data/public/style.css
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
body{
|
2
|
+
margin: 0 auto;
|
3
|
+
font-family: Georgia, Palatino, serif;
|
4
|
+
color: #444444;
|
5
|
+
line-height: 1;
|
6
|
+
max-width: 960px;
|
7
|
+
padding: 30px;
|
8
|
+
}
|
9
|
+
h1, h2, h3, h4 {
|
10
|
+
color: #111111;
|
11
|
+
font-weight: 400;
|
12
|
+
}
|
13
|
+
h1, h2, h3, h4, h5, p {
|
14
|
+
margin-bottom: 24px;
|
15
|
+
padding: 0;
|
16
|
+
}
|
17
|
+
h1 {
|
18
|
+
font-size: 48px;
|
19
|
+
}
|
20
|
+
h2 {
|
21
|
+
font-size: 36px;
|
22
|
+
margin: 24px 0 6px;
|
23
|
+
}
|
24
|
+
h3 {
|
25
|
+
font-size: 24px;
|
26
|
+
}
|
27
|
+
h4 {
|
28
|
+
font-size: 21px;
|
29
|
+
}
|
30
|
+
h5 {
|
31
|
+
font-size: 18px;
|
32
|
+
}
|
33
|
+
a {
|
34
|
+
color: #0099ff;
|
35
|
+
margin: 0;
|
36
|
+
padding: 0;
|
37
|
+
vertical-align: baseline;
|
38
|
+
}
|
39
|
+
a:hover {
|
40
|
+
text-decoration: none;
|
41
|
+
color: #ff6600;
|
42
|
+
}
|
43
|
+
a:visited {
|
44
|
+
color: purple;
|
45
|
+
}
|
46
|
+
/*ul, ol {
|
47
|
+
padding: 0;
|
48
|
+
margin: 0;
|
49
|
+
}*/
|
50
|
+
li {
|
51
|
+
line-height: 24px;
|
52
|
+
}
|
53
|
+
li ul, li ul {
|
54
|
+
margin-left: 24px;
|
55
|
+
}
|
56
|
+
p, ul, ol {
|
57
|
+
font-size: 16px;
|
58
|
+
line-height: 24px;
|
59
|
+
/*max-width: 540px;*/
|
60
|
+
}
|
61
|
+
pre {
|
62
|
+
padding: 5px 10px;
|
63
|
+
max-width: 800px;
|
64
|
+
white-space: pre-wrap;
|
65
|
+
background-color: #eee;
|
66
|
+
}
|
67
|
+
code {
|
68
|
+
font-family: Consolas, Monaco, Andale Mono, monospace;
|
69
|
+
line-height: 1.5;
|
70
|
+
font-size: 13px;
|
71
|
+
background-color: #eee;
|
72
|
+
}
|
73
|
+
p {
|
74
|
+
padding: 2px;
|
75
|
+
margin: 2px;
|
76
|
+
}
|
77
|
+
aside {
|
78
|
+
display: block;
|
79
|
+
float: right;
|
80
|
+
width: 390px;
|
81
|
+
}
|
82
|
+
blockquote {
|
83
|
+
border-left:.5em solid #eee;
|
84
|
+
padding: 0 2em;
|
85
|
+
margin-left:0;
|
86
|
+
max-width: 476px;
|
87
|
+
}
|
88
|
+
blockquote cite {
|
89
|
+
font-size:14px;
|
90
|
+
line-height:20px;
|
91
|
+
color:#bfbfbf;
|
92
|
+
}
|
93
|
+
blockquote cite:before {
|
94
|
+
content: '\2014 \00A0';
|
95
|
+
}
|
96
|
+
|
97
|
+
blockquote p {
|
98
|
+
color: #666;
|
99
|
+
max-width: 460px;
|
100
|
+
}
|
101
|
+
hr {
|
102
|
+
width: 540px;
|
103
|
+
text-align: left;
|
104
|
+
margin: 0 auto 0 0;
|
105
|
+
color: #999;
|
106
|
+
}
|