rack-server-pages 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +11 -0
  2. data/.travis.yml +6 -0
  3. data/Gemfile +53 -0
  4. data/Gemfile.lock +127 -0
  5. data/Guardfile +16 -0
  6. data/README.md +401 -0
  7. data/Rakefile +11 -0
  8. data/config.ru +13 -0
  9. data/lib/rack-server-pages.rb +1 -0
  10. data/lib/rack/server_pages.rb +348 -0
  11. data/public/README.erb +3 -0
  12. data/public/_layout.html.erb +9 -0
  13. data/public/index.html +16 -0
  14. data/public/info.php +1 -0
  15. data/public/sample.erb +8 -0
  16. data/public/style.css +106 -0
  17. data/rack-server-pages.gemspec +22 -0
  18. data/spec/lib/rack/server_pages_spec.rb +69 -0
  19. data/spec/spec_helper.rb +40 -0
  20. data/views/about.html.slim +11 -0
  21. data/views/article.html.md +16 -0
  22. data/views/betty.css.sass +11 -0
  23. data/views/contact.xml.builder +5 -0
  24. data/views/examples/_layout.html.erb +14 -0
  25. data/views/examples/_time.html.erb +1 -0
  26. data/views/examples/builder.xml.builder +0 -0
  27. data/views/examples/coffee.js.coffee +0 -0
  28. data/views/examples/erb.html.erb +2 -0
  29. data/views/examples/haml.html.haml +6 -0
  30. data/views/examples/html.html +1 -0
  31. data/views/examples/index.html.erb +9 -0
  32. data/views/examples/less.css.less +0 -0
  33. data/views/examples/liquid.html.liquid +0 -0
  34. data/views/examples/markaby.html.mab +0 -0
  35. data/views/examples/markdown.html.markdown +6 -0
  36. data/views/examples/nokogiri.xml.nokogiri +0 -0
  37. data/views/examples/radius.html.radius +0 -0
  38. data/views/examples/rdoc.html.rdoc +0 -0
  39. data/views/examples/sass.css.sass +11 -0
  40. data/views/examples/scss.css.scss +0 -0
  41. data/views/examples/slim.html.slim +2 -0
  42. data/views/examples/source.html.slim +9 -0
  43. data/views/examples/textile.html.textile +0 -0
  44. data/views/examples/wiki.html.wiki +0 -0
  45. data/views/examples/yajl.json.yajl +0 -0
  46. data/views/script.js.coffee +13 -0
  47. metadata +106 -0
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require "bundler/gem_tasks"
4
+ require 'rspec/core/rake_task'
5
+
6
+ task :default => :spec
7
+
8
+ desc "Run all specs in spec directory"
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ t.rspec_opts = %w(-fs --color)
11
+ end
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
@@ -0,0 +1,3 @@
1
+ <% layout('public/_layout.html') %>
2
+ <%# Rack::ServerPages::Template.tilt? ? layout('_layout.html') : headers['Content-Type'] = 'text/plain' %>
3
+ <%= partial 'README.md' %>
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head>
3
+ <title>README.md</title>
4
+ <link href="<%=url("/style.css")%>" media="screen" rel="stylesheet" type="text/css" />
5
+ </head>
6
+ <body>
7
+ <%=yield%>
8
+ </body>
9
+ </html>
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
@@ -0,0 +1,8 @@
1
+ <h1>Hello <%=h(params["name"] || "Rack")%>!!</h1>
2
+ <p>Current Time: <%= Time.now %></p>
3
+ What's your name?:
4
+ <form>
5
+ <input type="text" name="name" value="<%=h params["name"]%>" />
6
+ <input type="submit" />
7
+ </form>
8
+
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
+ }