rack-server-pages 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.md ADDED
@@ -0,0 +1,60 @@
1
+ CHANGES
2
+ =======
3
+
4
+ ### [0.0.4](https://github.com/migrs/rack-server-pages/tree/v0.0.4) / 2012-01-15
5
+
6
+ * [Changes](https://github.com/migrs/rack-server-pages/compare/v0.0.3...v0.0.4)
7
+
8
+ * Enhancement
9
+ - Thread safety
10
+ - Add instance variables info in `rubyinfo`
11
+ - Better PATH\_INFO parsing
12
+
13
+ * Bufix
14
+ - Didn't work `Rack::ServerPages::Template.tilt=`
15
+ - and rename to `Rack::ServerPages::Template.use_tilt`
16
+
17
+ * Refactor
18
+ - Create Filter class
19
+ - Binding setup in own class method
20
+
21
+ * Documents
22
+ - Filters and Helpers
23
+ - Add [CHAMGES.md](https://github.com/migrs/rack-server-pages/blob/master/CHAMGES.md) (this document)
24
+
25
+
26
+ ### [0.0.3](https://github.com/migrs/rack-server-pages/tree/v0.0.3) / 2012-01-06
27
+
28
+ * [Changes](https://github.com/migrs/rack-server-pages/compare/v0.0.2...v0.0.3)
29
+
30
+ * Feature
31
+ - Before/After Filters
32
+ - Include Helpers
33
+
34
+ * Enhancement
35
+ - Binding class initialized at boot
36
+ - `partial` accepts block
37
+ - bundle update
38
+
39
+ * Refactor
40
+ - Move rubyinfo helper to other file
41
+
42
+
43
+ ### [0.0.2](https://github.com/migrs/rack-server-pages/tree/v0.0.2) / 2012-01-01
44
+
45
+ * [Changes](https://github.com/migrs/rack-server-pages/compare/v0.0.1...v0.0.2)
46
+
47
+ * Bugfix
48
+ - Didn't launch with ERBTemplate
49
+
50
+
51
+ ### [0.0.1](https://github.com/migrs/rack-server-pages/tree/v0.0.1) / 2012-01-01
52
+
53
+ * Initial Release
54
+
55
+ * Feature
56
+ - Serving dynamic pages (default: ERB)
57
+ - Serving static files
58
+ - Tilt support (optional)
59
+ - Include a partial template
60
+ - Layout template
data/README.md CHANGED
@@ -141,6 +141,93 @@ with block
141
141
  - failure\_app
142
142
  - default: nil
143
143
 
144
+ ### Helpers
145
+
146
+ with helpers block
147
+
148
+ use Rack::ServerPages do |config|
149
+ config.helpers do
150
+ def three_times(name)
151
+ "#{([name.to_s]*3).join(' ')}!!"
152
+ end
153
+ end
154
+ end
155
+
156
+ in view file (erb)
157
+
158
+ <%= three_times('blah') %>
159
+
160
+ with helper module
161
+
162
+ module SampleHelper
163
+ def three_times(name)
164
+ "#{([name.to_s]*3).join(' ')}!!"
165
+ end
166
+ end
167
+
168
+ use Rack::ServerPages do |config|
169
+ config.helpers SampleHelper
170
+ end
171
+
172
+ with procs
173
+
174
+ help1 = proc do
175
+ def three_times(name)
176
+ "#{([name.to_s]*3).join(' ')}!!"
177
+ end
178
+ end
179
+
180
+ help2 = proc {...}
181
+
182
+ use Rack::ServerPages do |config|
183
+ config.helpers help1, help2
184
+ end
185
+
186
+ ### Filters
187
+
188
+ with before/after block
189
+
190
+ use Rack::ServerPages do |config|
191
+ config.before do
192
+ @title = 'Hello!'
193
+ end
194
+
195
+ config.after do
196
+ logger.debug 'xxxx'
197
+ end
198
+ end
199
+
200
+ with procs
201
+
202
+ proc1 = proc { @name = 'Jonny' }
203
+ proc2 = proc { @age = 24 }
204
+ proc3 = proc { logger.debug 'xxxx' }
205
+
206
+ use Rack::ServerPages do |config|
207
+ config.before proc1, proc2
208
+ config.after proc3
209
+ end
210
+
211
+ if you define before/after method in helper module, it will be treated as filters
212
+
213
+ module SampleHelper
214
+ def before
215
+ @title = 'Hello!'
216
+ end
217
+
218
+ def three_times(name)
219
+ "#{([name.to_s]*3).join(' ')}!!"
220
+ end
221
+ end
222
+
223
+ use Rack::ServerPages do |config|
224
+ config.helpers SampleHelper
225
+ end
226
+
227
+ in view file
228
+
229
+ <%= three_times(@title) %>
230
+
144
231
  ## Tilt support
145
232
  [Tilt](http://github.com/rtomayko/tilt) is generic interface to multiple Ruby template engines.
146
233
  If you want to use Tilt, just `require 'tilt'` and require template engine libraries that you want.
@@ -403,4 +490,4 @@ And create `public/info.php` :)
403
490
  - Benchmark
404
491
 
405
492
  ## License
406
- [rack-server-pages](http://github.com/migrs/rack-server-pages) is Copyright (c) 2011 [Masato Igarashi](http://github.com/migrs)(@[migrs](http://twitter.com/migrs)) and distributed under the [MIT license](http://www.opensource.org/licenses/mit-license).
493
+ [rack-server-pages](http://github.com/migrs/rack-server-pages) is Copyright (c) 2012 [Masato Igarashi](http://github.com/migrs)(@[migrs](http://twitter.com/migrs)) and distributed under the [MIT license](http://www.opensource.org/licenses/mit-license).
data/config.ru CHANGED
@@ -8,6 +8,7 @@ require 'slim'
8
8
 
9
9
  # .php as ERB template :)
10
10
  Rack::ServerPages::Template::ERBTemplate.extensions << 'php' # ERBTemplate
11
+ #Rack::ServerPages::Template.use_tilt false
11
12
  Tilt.register Tilt::ERBTemplate, 'php' # TiltTemplate
12
13
 
13
14
  module SampleHelper
@@ -1,98 +1,137 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  require 'rack'
3
- require 'time'
4
3
  require 'rack/utils'
5
4
  require 'rack/mime'
6
5
  require 'rack/logger'
6
+ require 'time'
7
7
  require 'forwardable'
8
8
 
9
9
  module Rack
10
10
  class ServerPages
11
- VERSION = '0.0.3'
11
+ VERSION = '0.0.4'
12
12
 
13
- def self.call(env)
14
- new.call(env)
15
- end
13
+ class << self
14
+ def call(env)
15
+ new.call(env)
16
+ end
16
17
 
17
- def self.[](options={}, &block)
18
- new(nil, options, &block)
18
+ def [](options={}, &block)
19
+ new(nil, options, &block)
20
+ end
19
21
  end
20
22
 
21
23
  def initialize(app = nil, options = {})
22
24
  @config = Config.new(*options)
23
25
  yield @config if block_given?
24
26
  @app = app || @config.failure_app || NotFound
25
- @binding = Class.new(Binding)
26
27
 
27
28
  require ::File.dirname(__FILE__) + "/server_pages/sample_helper"
28
29
  @config.helpers Rack::ServerPages::SampleHelper
29
30
 
30
- @binding.setup(@config.helpers, @config.filters)
31
+ @config.filter.merge_from_helpers(@config.helpers)
32
+ @binding = Binding.extended_class(@config.helpers)
33
+
34
+ @path_regex = %r!^#{@config.effective_path}/((?:[\w-]+/)+)?([A-z0-9][\w\.\-]*?\w)?(\.\w+)?$!
31
35
  end
32
36
 
33
37
  def call(env)
34
- serving(env)
38
+ dup.serving(env)
35
39
  end
36
40
 
37
- private
38
-
39
41
  def serving(env)
40
- files = find_template_files *evalute_path_info(env['PATH_INFO']) rescue nil
41
-
42
+ files = find_template_files(env['PATH_INFO'])
42
43
  unless files.nil? or files.empty?
43
44
  file = select_template_file(files)
45
+ (tpl = Template[file]) ? server_page(tpl) : StaticFile.new(file, @config.cache_control)
46
+ else
47
+ @app
48
+ end.call(env)
49
+ end
44
50
 
45
- if template = Template[file]
46
- render(template, @binding.new(env))
47
- else
48
- StaticFile.new(file, @config.cache_control).call(env)
51
+ def find_template_files(path_info)
52
+ if m = path_info.match(@path_regex)
53
+ @config.view_paths.inject([]) do |files, path|
54
+ files.concat Dir["#{path}/#{m[1]}#{m[2]||'index'}#{m[3]}{.*,}"].select{|s|s.include?('.')}
49
55
  end
50
- else
51
- @app.call(env)
52
56
  end
53
57
  end
54
58
 
55
- def render(template, scope)
56
- scope.response.tap do |res|
57
- catch(:halt) do
58
- invoke_filter(:before, scope)
59
- res.write template.render_with_layout(scope)
60
- res['Last-Modified'] ||= ::File.mtime(template.file).httpdate
61
- res['Content-Type'] ||= template.mime_type_with_charset(@config.default_charset)
62
- res['Cache-Control'] ||= @config.cache_control if @config.cache_control
63
- invoke_filter(:after, scope)
64
- end
65
- end.finish
59
+ def select_template_file(files)
60
+ files.first
66
61
  end
67
62
 
68
- def invoke_filter(type, scope)
69
- @config.filters[type].each do |filter|
70
- filter.respond_to?(:bind) ? filter.bind(scope).call : scope.instance_exec(&filter)
63
+ def build_response(template, scope)
64
+ scope.response.tap do |response|
65
+ response.write template.render_with_layout(scope)
66
+ response['Last-Modified'] ||= ::File.mtime(template.file).httpdate
67
+ response['Content-Type'] ||= template.mime_type_with_charset(@config.default_charset)
68
+ response['Cache-Control'] ||= @config.cache_control if @config.cache_control
71
69
  end
72
70
  end
73
71
 
74
- def evalute_path_info(path)
75
- if m = path.match(%r!^#{@config.effective_path}/((?:[\w-]+/)+)?([A-z0-9]\w*)?(\.\w+)?(\.\w+)?$!)
76
- m[1,3] # dir, file, ext
72
+ def server_page(template)
73
+ lambda do |env|
74
+ @binding.new(env).tap do |scope|
75
+ catch(:halt) { @config.filter.invoke(scope) { build_response(template, scope) }}
76
+ end.response.finish
77
77
  end
78
78
  end
79
79
 
80
- def find_template_files(dir, file, ext)
81
- #path = @config.view_paths.map{|root|"#{root}/#{dir}#{file||'index'}#{ext}{.*,}"}.join("\0") # Ruby 1.8
82
- #path = @config.view_paths.map{|root|"#{root}/#{dir}#{file||'index'}#{ext}{.*,}"} # Ruby 1.9
83
- #Dir[path].select{|s|s.include?('.')}
84
- [].tap do |files| # universal way
85
- @config.view_paths.each do |root|
86
- files.concat Dir["#{root}/#{dir}#{file||'index'}#{ext}{.*,}"].select{|s|s.include?('.')}
80
+ class Filter
81
+ TYPES = [:before, :after]
82
+ DEFAULT = Hash[[TYPES, [[]]*TYPES.size].transpose]
83
+
84
+ TYPES.each do |type|
85
+ define_method(type) {|*fn, &block| add(type, *fn, &block) }
86
+ end
87
+
88
+ def initialize(filters = DEFAULT)
89
+ @filters = filters
90
+ end
91
+
92
+ def [] type
93
+ @filters[type]
94
+ end
95
+
96
+ def merge(other)
97
+ TYPES.each { |type| self[type].concat other[type] }
98
+ end
99
+
100
+ def merge_from_helpers(helpers)
101
+ merge(self.class.extract_filters_from_helpers(helpers))
102
+ end
103
+
104
+ def add(type, *args, &block)
105
+ self[type] << block if block_given?
106
+ self[type].concat args unless args.empty?
107
+ end
108
+
109
+ def invoke(scope, type = nil)
110
+ if block_given?
111
+ invoke(scope, TYPES.first); yield scope; invoke(scope, TYPES.last)
112
+ else
113
+ self[type].each { |f| f.respond_to?(:bind) ? f.bind(scope).call : scope.instance_exec(&f) }
87
114
  end
88
115
  end
89
- end
90
116
 
91
- def select_template_file(files)
92
- files.first
117
+ def self.extract_filters_from_helpers(helpers)
118
+ new.tap do |filter|
119
+ helpers.each do |helper|
120
+ next unless helper.is_a? Module
121
+ TYPES.each do |type|
122
+ if helper.method_defined?(type)
123
+ filter[type] << helper.instance_method(type)
124
+ helper.class_eval { undef :"#{type}" }
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
93
130
  end
94
131
 
95
132
  class Config < Hash
133
+ extend Forwardable
134
+
96
135
  def self.hash_accessor(*names)
97
136
  names.each do |name|
98
137
  define_method("#{name}=") { |v| self[name] = v }
@@ -101,33 +140,21 @@ module Rack
101
140
  end
102
141
 
103
142
  hash_accessor :view_path, :effective_path, :cache_control, :default_charset, :failure_app
104
- attr_reader :filters
143
+ attr_reader :filter
144
+ def_delegators :filter, *Filter::TYPES
105
145
 
106
146
  def initialize
107
147
  super
108
148
  self[:default_charset] ||= 'utf-8'
109
149
  self[:view_path] ||= %w(views public)
110
150
  @helpers = []
111
- @filters = { :before => [], :after => [] }
151
+ @filter = Filter.new
112
152
  end
113
153
 
114
154
  def view_paths
115
155
  (v = self[:view_path]).kind_of?(Enumerable) ? v : [v.to_s]
116
156
  end
117
157
 
118
- def before(*fn, &block)
119
- add_filter(:before, *fn, &block)
120
- end
121
-
122
- def after(*fn, &block)
123
- add_filter(:after, *fn, &block)
124
- end
125
-
126
- def add_filter(type, *args, &block)
127
- @filters[type] << block if block_given?
128
- @filters[type].concat args unless args.empty?
129
- end
130
-
131
158
  def helpers(*args, &block)
132
159
  @helpers << block if block_given?
133
160
  @helpers.concat args unless args.empty?
@@ -135,28 +162,24 @@ module Rack
135
162
  end
136
163
  end
137
164
 
138
- class NotFound
139
- def self.call(env)
140
- Rack::Response.new(["Not Found: #{env['REQUEST_PATH']}"], 404).finish
141
- end
142
- end
143
-
144
165
  class Template
145
166
 
146
- def self.[] file
147
- engine.new(file).find_template
148
- end
167
+ class << self
168
+ def [] file
169
+ engine.new(file).find_template
170
+ end
149
171
 
150
- def self.engine
151
- tilt? ? TiltTemplate : ERBTemplate
152
- end
172
+ def engine
173
+ tilt? ? TiltTemplate : ERBTemplate
174
+ end
153
175
 
154
- def self.tilt?
155
- (@@use_tilt ||= defined?(Tilt)) and defined?(Tilt)
156
- end
176
+ def tilt?
177
+ @use_tilt.nil? ? (@use_tilt ||= !!defined?(Tilt)) : @use_tilt and defined?(Tilt)
178
+ end
157
179
 
158
- def self.tilt= bool
159
- @@use_tilt = !!bool
180
+ def use_tilt bool = true
181
+ @use_tilt = !!bool
182
+ end
160
183
  end
161
184
 
162
185
  attr_reader :file
@@ -235,6 +258,12 @@ module Rack
235
258
  end
236
259
  end
237
260
 
261
+ class NotFound
262
+ def self.call(env)
263
+ Rack::Response.new(["Not Found: #{env['REQUEST_PATH']}"], 404).finish
264
+ end
265
+ end
266
+
238
267
  module CoreHelper
239
268
  def redirect(target, status=302)
240
269
  response.redirect(target, status)
@@ -255,18 +284,12 @@ module Rack
255
284
  end
256
285
 
257
286
  def halt(*args)
258
- case args[0]
259
- when String
260
- response.body = [args[0]]
261
- when Fixnum
287
+ if args[0].kind_of? Fixnum
288
+ response.headers.merge! args[1] if (a1_is_h = args[1].kind_of? Hash)
289
+ response.body = [(a1_is_h) ? args[2] : args[1]]
262
290
  response.status = args[0]
263
- case args[1]
264
- when Hash
265
- response.headers.merge! args[1]
266
- response.body = [args[2]]
267
- else
268
- response.body = [args[1]]
269
- end
291
+ else
292
+ response.body = [args[0]]
270
293
  end
271
294
  throw :halt
272
295
  end
@@ -286,18 +309,14 @@ module Rack
286
309
  def_delegators :request, :env, :params, :session, :cookies, :logger
287
310
  def_delegators :response, :headers, :set_cookies, :delete_cookie
288
311
 
289
- def self.setup(helpers, filters)
290
- helpers.each do |helper|
291
- if helper.kind_of? Proc
292
- class_eval(&helper)
293
- else
294
- class_eval { include helper }
295
- [:before, :after].each do |type|
296
- if helper.method_defined?(type)
297
- filters[type] << helper.instance_method(type)
298
- class_eval { undef :"#{type}" }
299
- end
300
- end
312
+ class << self
313
+ def extended_class(helpers)
314
+ Class.new(self).tap { |k| k.setup(helpers) }
315
+ end
316
+
317
+ def setup(helpers)
318
+ helpers.each do |helper|
319
+ helper.is_a?(Module) ? class_eval { include helper } : class_eval(&helper)
301
320
  end
302
321
  end
303
322
  end
@@ -7,7 +7,6 @@ module Rack::ServerPages::SampleHelper
7
7
  body {background-color: #ffffff; color: #000000;}
8
8
  body, td, th, h1, h2 {font-family: sans-serif;}
9
9
  pre {margin: 0px; font-family: monospace;}
10
- a:link {color: #000099; text-decoration: none; background-color: #ffffff;}
11
10
  a:hover {text-decoration: underline;}
12
11
  table {border-collapse: collapse;}
13
12
  .center {text-align: center;}
@@ -72,13 +71,14 @@ module Rack::ServerPages::SampleHelper
72
71
  <% end %>
73
72
  <h2>Binding</h2>
74
73
  <table border="0" cellpadding="3" width="600">
74
+ <tr><td class="e">variables</td><td class="v"><%= (instance_variables).join(', ') %></td></tr>
75
75
  <tr><td class="e">methods</td><td class="v"><%= (methods - Object.methods).join(', ') %></td></tr>
76
76
  </table>
77
77
  <h2>License</h2>
78
78
  <table border="0" cellpadding="3" width="600">
79
79
  <tr class="v"><td>
80
80
  <p>
81
- MIT License
81
+ <a href="http://github.com/migrs/rack-server-pages">rack-server-pages</a> is Copyright (c) 2012 <a href="http://github.com/migrs">Masato Igarashi</a>(@<a href="http://twitter.com/migrs">migrs</a>) and distributed under the <a href="http://www.opensource.org/licenses/mit-license">MIT license</a>.
82
82
  </p>
83
83
  </td></tr>
84
84
  </table><br />
@@ -0,0 +1,3 @@
1
+ <% Rack::ServerPages::Template.tilt? ? layout('public/_layout.html') : headers['Content-Type'] = 'text/plain' %>
2
+ <% @title = 'CHANGES.md' %>
3
+ <%= partial 'CHANGES.md' %>
data/public/index.html CHANGED
@@ -10,6 +10,7 @@
10
10
  <li><a href="./sample">sample.erb</a></li>
11
11
  <li><a href="./info">info.php</a></li>
12
12
  <li><a href="./README">README</a></li>
13
+ <li><a href="./CHANGES">CHANGES</a></li>
13
14
  </ul>
14
15
  <a href="http://github.com/migrs/rack-server-pages">github</a>
15
16
  </body>
@@ -41,7 +41,7 @@ describe 'Rack::ServerPages' do
41
41
 
42
42
  describe 'Rack::ServerPages private methods' do
43
43
  describe '#evalute_path_info' do
44
- subject { app.new.__send__(:evalute_path_info, path_info) }
44
+ subject { m = app.new.instance_variable_get(:@path_regex).match(path_info); m[1,3] if m }
45
45
 
46
46
  context '/aaa/bbb.erb' do
47
47
  let(:path_info) { '/aaa/bbb.erb' }
@@ -77,6 +77,19 @@ describe 'Rack::ServerPages' do
77
77
  let(:path_info) { '/' }
78
78
  it { should eq [nil, nil, nil] }
79
79
  end
80
+
81
+ context path = '/aaa/bbb/AB-c.182-d.min.js' do
82
+ let(:path_info) { path }
83
+ it { should eq ['aaa/bbb/', 'AB-c.182-d.min', '.js'] }
84
+ end
85
+ end
86
+ end
87
+
88
+ describe 'Configuration' do
89
+ it 'test' do
90
+ mock_app do
91
+ run Rack::ServerPages
92
+ end
80
93
  end
81
94
  end
82
95
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-server-pages
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-06 00:00:00.000000000Z
12
+ date: 2012-01-14 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
- requirement: &70252865364220 !ruby/object:Gem::Requirement
16
+ requirement: &70348646709060 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70252865364220
24
+ version_requirements: *70348646709060
25
25
  description: ! "Rack middleware and appilcation for serving dynamic pages in very
26
26
  simple way.\n There are no controllers and no models, just only
27
27
  views like a asp, jsp and php!"
@@ -33,6 +33,7 @@ extra_rdoc_files: []
33
33
  files:
34
34
  - .gitignore
35
35
  - .travis.yml
36
+ - CHANGES.md
36
37
  - Gemfile
37
38
  - Gemfile.lock
38
39
  - Guardfile
@@ -42,6 +43,7 @@ files:
42
43
  - lib/rack-server-pages.rb
43
44
  - lib/rack/server_pages.rb
44
45
  - lib/rack/server_pages/sample_helper.rb
46
+ - public/CHANGES.erb
45
47
  - public/README.erb
46
48
  - public/_layout.html.erb
47
49
  - public/index.html