rack-server-pages 0.0.3 → 0.0.4

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/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