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.
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
+ }