rack-staticifier 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ = Rack::Staticifier
2
+
3
+ Rack::Staticifier is Rack middleware for staticly caching responses.
4
+
5
+ == Install
6
+
7
+ $ gem sources -a http://gems.github.com
8
+ $ sudo gem install remi-rack-staticifier
9
+
10
+ == Usage
11
+
12
+ require 'rack/staticifier'
13
+
14
+ # this will cache ALL responses in a 'cache' directory
15
+ use Rack::Staticifier
16
+
17
+ # this will cache ALL responses in a 'public/my/cached/stuff' directory
18
+ use Rack::Staticifier, :root => 'public/my/cached/stuff'
19
+
20
+ # this will only cache requests with 'foo' in the URL
21
+ use Rack::Staticifier do |env, response|
22
+ env['PATH_INFO'].include?('foo')
23
+ end
24
+
25
+ # this will only cache requests with 'hi' in the response body
26
+ use Rack::Staticifier do |env, response|
27
+ # response is a regular Rack response, eg. [200, {}, ['hi there']]
28
+ body = ''
29
+ response.last.each {|string| body << string }
30
+ body.include?('hi')
31
+ end
32
+
33
+ # this will only cache requests with 'foo' in the URL (incase you don't want to pass a block)
34
+ use Rack::Staticifier, :cache_if => lambda { |env, response| env['PATH_INFO'].include?('foo') }
35
+
36
+ == TODO
37
+
38
+ * compare to Rack::ResponseCache (in rack-contrib) ... maybe that can replace this, or vice-versa?
@@ -0,0 +1,66 @@
1
+ require 'rake'
2
+ require 'rubygems'
3
+ require 'rake/rdoctask'
4
+ require 'spec/rake/spectask'
5
+
6
+ puts "\nGem: rack-staticifier\n\n"
7
+
8
+ begin
9
+ require 'jeweler'
10
+ Jeweler::Tasks.new do |s|
11
+ s.name = 'rack-staticifier'
12
+ s.summary = 'Staticly cache requests to any Rack application'
13
+ s.email = 'remi@remitaylor.com'
14
+ s.homepage = 'http://github.com/remi/rack-staticifier'
15
+ s.description = 'Staticly cache requests to any Rack application - perfect for creating static sites/blogs/etc!'
16
+ s.authors = %w( remi )
17
+ s.files = FileList['[A-Z]*', '{lib,spec,bin,examples}/**/*']
18
+ # s.rubyforge_project = 'gemname'
19
+ # s.extra_rdoc_files = %w( README.rdoc )
20
+ end
21
+ rescue LoadError
22
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
23
+ end
24
+
25
+ Spec::Rake::SpecTask.new do |t|
26
+ t.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ desc "Run all examples with RCov"
30
+ Spec::Rake::SpecTask.new('rcov') do |t|
31
+ t.spec_files = FileList['spec/**/*_spec.rb']
32
+ t.rcov = true
33
+ end
34
+
35
+ # require 'hanna'
36
+ # require 'darkfish-rdoc'
37
+
38
+ Rake::RDocTask.new do |rdoc|
39
+ rdoc.rdoc_dir = 'rdoc'
40
+ rdoc.title = 'rack-staticifier'
41
+ rdoc.options << '--line-numbers' << '--inline-source'
42
+ # rdoc.options += ["--template=#{`allison --path`}"] # sudo gem install allison
43
+ # rdoc.options += %w( -f darkfish ) # sudo gem install darkfish-rdoc
44
+ # rdoc.options += %w( -T hanna ) # sudo gem install mislav-hanna
45
+ rdoc.options += %w( -m README.rdoc ) # the initial page displayed
46
+ rdoc.rdoc_files.include('README.rdoc')
47
+ rdoc.rdoc_files.include('lib/**/*.rb')
48
+ end
49
+
50
+ desc 'Confirm that gemspec is $SAFE'
51
+ task :safe do
52
+ require 'yaml'
53
+ require 'rubygems/specification'
54
+ data = File.read('rack-staticifier.gemspec')
55
+ spec = nil
56
+ if data !~ %r{!ruby/object:Gem::Specification}
57
+ Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
58
+ else
59
+ spec = YAML.load(data)
60
+ end
61
+ spec.validate
62
+ puts spec
63
+ puts "OK"
64
+ end
65
+
66
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 6
3
+ :major: 0
4
+ :minor: 1
@@ -0,0 +1,3 @@
1
+ require 'my-blog'
2
+
3
+ run Sinatra::Application
@@ -0,0 +1,17 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ %w( rubygems sinatra maruku ).each {|lib| require lib }
4
+
5
+ get '/' do
6
+ "welcome to my blog!"
7
+ end
8
+
9
+ get '/:name.html' do
10
+ file = File.join File.dirname(__FILE__), 'posts', "#{ params['name'] }.mkd"
11
+ if File.file? file
12
+ Maruku.new(File.read(file)).to_html
13
+ else
14
+ status 404
15
+ "Not Found! #{ params['name'] }"
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ #! /bin/bash
2
+ echo '/'
3
+ ls posts/* | xargs -L 1 basename | sed 's|\(.*\)\.mkd|\/\1.html|g'
@@ -0,0 +1,3 @@
1
+ # First Post!
2
+
3
+ hi!
@@ -0,0 +1,5 @@
1
+ # Totally
2
+
3
+ ## Awesome
4
+
5
+ post about nothing
@@ -0,0 +1,29 @@
1
+ #! /usr/bin/env ruby
2
+ # %w( rubygems sinatra rack/staticifier ).each {|lib| require lib }
3
+ %w( rubygems sinatra ).each {|lib| require lib }
4
+ require File.dirname(__FILE__) + '/../lib/rack-staticifier'
5
+
6
+ use Rack::Staticifier
7
+
8
+ set :public, 'cache'
9
+
10
+ $posts = {
11
+ 'hello-world' => '<html><body>Hello World!</body></html>',
12
+ 'hi-there' => 'Hi from my blog post text'
13
+ }
14
+
15
+ get '/' do
16
+ "Home Page rendered at #{ Time.now }"
17
+ end
18
+
19
+ get '/:post.html' do
20
+ name = params['post']
21
+
22
+ if $posts.keys.include?(name)
23
+ $posts[name]
24
+
25
+ else
26
+ status 404
27
+ "Cannot find page: #{ name }"
28
+ end
29
+ end
@@ -0,0 +1,88 @@
1
+ module Rack #:nodoc:
2
+
3
+ # Rack::Staticifier is Rack middleware for staticly caching responses.
4
+ #
5
+ # ==== Usage
6
+ #
7
+ # # this will cache ALL responses in a 'cache' directory
8
+ # use Rack::Staticifier
9
+ #
10
+ # # this will cache ALL responses in a 'public/my/cached/stuff' directory
11
+ # use Rack::Staticifier, :root => 'public/my/cached/stuff'
12
+ #
13
+ # # this will only cache requests with 'foo' in the URL
14
+ # use Rack::Staticifier do |env, response|
15
+ # env['PATH_INFO'].include?('foo')
16
+ # end
17
+ #
18
+ # # this will only cache requests with 'hi' in the response body
19
+ # use Rack::Staticifier do |env, response|
20
+ # # response is a regular Rack response, eg. [200, {}, ['hi there']]
21
+ # body = ''
22
+ # response.last.each {|string| body << string }
23
+ # body.include?('hi')
24
+ # end
25
+ #
26
+ # # this will only cache requests with 'foo' in the URL (incase you don't want to pass a block)
27
+ # use Rack::Staticifier, :cache_if => lambda { |env, response| env['PATH_INFO'].include?('foo') }
28
+ #
29
+ class Staticifier
30
+
31
+ STATUS_CODES_NOT_TO_CACHE = [ 304 ]
32
+
33
+ # the Rack application
34
+ attr_reader :app
35
+
36
+ # configuration options
37
+ attr_reader :config
38
+
39
+ def initialize app, config_options = nil, &block
40
+ @app = app
41
+ @config = default_config_options
42
+
43
+ config.merge!(config_options) if config_options
44
+ config[:cache_if] = block if block
45
+ end
46
+
47
+ def call env
48
+ response = @app.call env
49
+ cache_response(env, response) if should_cache_response?(env, response)
50
+ response
51
+ end
52
+
53
+ private
54
+
55
+ def default_config_options
56
+ { :root => 'cache' }
57
+ end
58
+
59
+ def should_cache_response? env, response
60
+ return false if STATUS_CODES_NOT_TO_CACHE.include?(response.first) # there are certain HTTP Status Codes we should never cache
61
+ return false if response.last.respond_to?(:to_path) # we don't cache Rack::File's
62
+ return true unless config.keys.include?(:cache_if) and config[:cache_if].respond_to?(:call) # true if no cache_if / block
63
+
64
+ should_cache = config[:cache_if].call(env, response)
65
+ should_cache
66
+ end
67
+
68
+ def cache_response env, response
69
+ request_path = env['PATH_INFO']
70
+ request_path << 'index.html' if request_path.end_with?('/')
71
+
72
+ basename = ::File.basename request_path
73
+ dirname = ::File.join config[:root], ::File.dirname(request_path)
74
+ fullpath = ::File.join dirname, basename
75
+
76
+ FileUtils.mkdir_p(dirname)
77
+ ::File.open(fullpath, 'w'){|f| f << response_body(response) }
78
+ end
79
+
80
+ def response_body response
81
+ body = ''
82
+ response.last.each {|string| body << string } # per the Rack spec, the last object should respond to #each
83
+ body
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,2 @@
1
+ # require 'rack/staticifier'
2
+ require 'rack-staticifier'
@@ -0,0 +1,198 @@
1
+ require 'rubygems'
2
+ require 'rackbox'
3
+ require 'fileutils'
4
+
5
+ require File.dirname(__FILE__) + '/../lib/rack-staticifier'
6
+
7
+ describe Rack::Staticifier do
8
+
9
+ before do
10
+ %w( public cache foo ).each {|dir| FileUtils.rm_rf dir }
11
+ @app = lambda {|env| [200, {}, ["hello from #{env['PATH_INFO']}"]] }
12
+ end
13
+
14
+ after :all do
15
+ %w( public cache foo ).each {|dir| FileUtils.rm_rf dir } # clean up!
16
+ end
17
+
18
+ it 'should render index.html for any requests ending in a slash' do
19
+ app = Rack::Staticifier.new @app
20
+
21
+ # for the '/' route
22
+ File.file?("cache/index.html").should be_false
23
+ RackBox.request app, "/"
24
+ File.file?("cache/index.html").should be_true
25
+ File.read("cache/index.html").should == "hello from /"
26
+
27
+ %w( foo/ bar/ ).each do |uri|
28
+ File.file?("cache/#{uri}index.html").should be_false
29
+ RackBox.request app, "/#{uri}"
30
+ File.file?("cache/#{uri}index.html").should be_true
31
+ File.read("cache/#{uri}index.html").should == "hello from /#{uri}"
32
+ end
33
+ end
34
+
35
+ it 'should cache all requests by default (in cache directory)' do
36
+ app = Rack::Staticifier.new @app
37
+
38
+ %w( foo bar ).each do |uri|
39
+ File.file?("cache/#{uri}.html").should be_false
40
+ RackBox.request app, "/#{uri}.html"
41
+ File.file?("cache/#{uri}.html").should be_true
42
+ File.read("cache/#{uri}.html").should == "hello from /#{uri}.html"
43
+ end
44
+ end
45
+
46
+ it 'should cache all requests in a custom directory' do
47
+ app = Rack::Staticifier.new @app, :root => 'foo'
48
+
49
+ %w( foo bar ).each do |uri|
50
+ File.file?("foo/#{uri}.html").should be_false
51
+ RackBox.request app, "/#{uri}.html"
52
+ File.file?("foo/#{uri}.html").should be_true
53
+ File.read("foo/#{uri}.html").should == "hello from /#{uri}.html"
54
+ end
55
+ end
56
+
57
+ it 'should cache all requests in a custom subdirectory' do
58
+ app = Rack::Staticifier.new @app, :root => 'foo/bar'
59
+
60
+ %w( foo bar ).each do |uri|
61
+ File.file?("foo/bar/#{uri}.html").should be_false
62
+ RackBox.request app, "/#{uri}.html"
63
+ File.file?("foo/bar/#{uri}.html").should be_true
64
+ File.read("foo/bar/#{uri}.html").should == "hello from /#{uri}.html"
65
+ end
66
+ end
67
+
68
+ it 'should cache requests with slashes in them (create subdirectories)' do
69
+ app = Rack::Staticifier.new @app, :root => 'foo'
70
+
71
+ %w( hi/there a/b/c/1/2/3 totally/neato ).each do |uri|
72
+ File.file?("foo/#{uri}.html").should be_false
73
+ RackBox.request app, "/#{uri}.html"
74
+ File.file?("foo/#{uri}.html").should be_true
75
+ File.read("foo/#{uri}.html").should == "hello from /#{uri}.html"
76
+ end
77
+ end
78
+
79
+ it 'should be able to only cache requests based on request environment' do
80
+ app = Rack::Staticifier.new @app, :cache_if => lambda {|env,resp| env['PATH_INFO'].include?('cache') }
81
+
82
+ %w( hi there crazy/person ).each do |uri|
83
+ File.file?("cache/#{uri}.html").should be_false
84
+ RackBox.request app, "/#{uri}.html"
85
+ File.file?("cache/#{uri}.html").should be_false
86
+ end
87
+
88
+ %w( cache cache-me please/cache/me ).each do |uri|
89
+ File.file?("cache/#{uri}.html").should be_false
90
+ RackBox.request app, "/#{uri}.html"
91
+ File.file?("cache/#{uri}.html").should be_true
92
+ File.read("cache/#{uri}.html").should == "hello from /#{uri}.html"
93
+ end
94
+ end
95
+
96
+ it 'should be able to only cache requests based on request environment (by passing a block)' do
97
+ app = Rack::Staticifier.new(@app){ |env,resp| env['PATH_INFO'].include?('cache') }
98
+
99
+ %w( hi there crazy/person ).each do |uri|
100
+ File.file?("cache/#{uri}.html").should be_false
101
+ RackBox.request app, "/#{uri}.html"
102
+ File.file?("cache/#{uri}.html").should be_false
103
+ end
104
+
105
+ %w( cache cache-me please/cache/me ).each do |uri|
106
+ File.file?("cache/#{uri}.html").should be_false
107
+ RackBox.request app, "/#{uri}.html"
108
+ File.file?("cache/#{uri}.html").should be_true
109
+ File.read("cache/#{uri}.html").should == "hello from /#{uri}.html"
110
+ end
111
+ end
112
+
113
+ it 'should be able to only cache requests based on generated response' do
114
+ app = Rack::Staticifier.new @app, :cache_if => lambda {|env,resp|
115
+ body = ''
116
+ resp[2].each {|s| body << s }
117
+ body.include?("hello from /foo")
118
+ }
119
+
120
+ %w( nope hi not/start/with/foo/x nor-me-foo ).each do |uri|
121
+ File.file?("cache/#{uri}.html").should be_false
122
+ RackBox.request app, "/#{uri}.html"
123
+ File.file?("cache/#{uri}.html").should be_false
124
+ end
125
+
126
+ %w( foo fooooo foo/bar ).each do |uri|
127
+ File.file?("cache/#{uri}.html").should be_false
128
+ RackBox.request app, "/#{uri}.html"
129
+ File.file?("cache/#{uri}.html").should be_true
130
+ File.read("cache/#{uri}.html").should == "hello from /#{uri}.html"
131
+ end
132
+ end
133
+
134
+ it 'should not be cache a Rack::File (#to_path)' do
135
+ pending "either RackBox or Rack::MockRequest isn't happy about running this"
136
+
137
+ =begin
138
+ 1)
139
+ TypeError in 'Rack::Staticifier should not be cache a Rack::File (#to_path)'
140
+ can't convert nil into String
141
+ /usr/lib/ruby/gems/1.8/gems/rack-1.0.0/lib/rack/file.rb:81:in `initialize'
142
+ /usr/lib/ruby/gems/1.8/gems/rack-1.0.0/lib/rack/file.rb:81:in `open'
143
+ /usr/lib/ruby/gems/1.8/gems/rack-1.0.0/lib/rack/file.rb:81:in `each'
144
+ /usr/lib/ruby/gems/1.8/gems/rack-1.0.0/lib/rack/mock.rb:126:in `initialize'
145
+ /usr/lib/ruby/gems/1.8/gems/remi-rackbox-1.1.5/lib/rackbox/rack/sticky_sessions.rb:40:in `new'
146
+ /usr/lib/ruby/gems/1.8/gems/remi-rackbox-1.1.5/lib/rackbox/rack/sticky_sessions.rb:40:in `request'
147
+ /usr/lib/ruby/gems/1.8/gems/rack-1.0.0/lib/rack/mock.rb:55:in `get'
148
+ /usr/lib/ruby/gems/1.8/gems/remi-rackbox-1.1.5/lib/rackbox/rackbox.rb:84:in `send'
149
+ /usr/lib/ruby/gems/1.8/gems/remi-rackbox-1.1.5/lib/rackbox/rackbox.rb:84:in `request'
150
+ ./spec/rack-staticifier_spec.rb:137:
151
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/example/example_methods.rb:37:in `instance_eval'
152
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/example/example_methods.rb:37:in `execute'
153
+ /usr/lib/ruby/1.8/timeout.rb:53:in `timeout'
154
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/example/example_methods.rb:34:in `execute'
155
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/example/example_group_methods.rb:208:in `execute_examples'
156
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/example/example_group_methods.rb:206:in `each'
157
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/example/example_group_methods.rb:206:in `execute_examples'
158
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/example/example_group_methods.rb:104:in `run'
159
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/runner/example_group_runner.rb:23:in `run'
160
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/runner/example_group_runner.rb:22:in `each'
161
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/runner/example_group_runner.rb:22:in `run'
162
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/runner/options.rb:117:in `run_examples'
163
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/lib/spec/runner/command_line.rb:9:in `run'
164
+ /usr/lib/ruby/gems/1.8/gems/rspec-1.2.2/bin/spec:4:
165
+ /usr/bin/spec:19:in `load'
166
+ /usr/bin/spec:19:
167
+ =end
168
+
169
+ app = lambda {|env| [200, {}, Rack::File.new(__FILE__)] }
170
+ File.file?("cache/foo.html").should be_false
171
+ RackBox.request app, "/foo.html"
172
+ File.file?("cache/foo.html").should be_false # shouldn't be cached!
173
+
174
+ # just double check ...
175
+ app = lambda {|env| [200, {}, ["cache me!"]] }
176
+ File.file?("cache/foo.html").should be_false
177
+ RackBox.request app, "/foo.html"
178
+ File.file?("cache/foo.html").should be_true # normal #each should be cached
179
+ end
180
+
181
+ it 'should not cache responses with certain HTTP Status Codes' do
182
+ Rack::Staticifier::STATUS_CODES_NOT_TO_CACHE.each do |code|
183
+ app = lambda {|env| [code, {}, ["not cached"]] }
184
+ File.file?("foo.html").should be_false
185
+ RackBox.request app, "/foo.html"
186
+ File.file?("foo.html").should be_false # shouldn't be cached!
187
+ end
188
+
189
+ # this assumes that 304 will always be in STATUS_CODES_NOT_TO_CACHE ... want to double check!
190
+ app = lambda {|env| [304, {}, ["not cached"]] }
191
+ File.file?("foo.html").should be_false
192
+ RackBox.request app, "/foo.html"
193
+ File.file?("foo.html").should be_false # shouldn't be cached!
194
+ end
195
+
196
+ it 'should be able to customize the name of the cached file (?)'
197
+
198
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-staticifier
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 6
10
+ version: 0.1.6
11
+ platform: ruby
12
+ authors:
13
+ - remi
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2009-06-15 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Staticly cache requests to any Rack application - perfect for creating static sites/blogs/etc!
23
+ email: remi@remitaylor.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.rdoc
30
+ files:
31
+ - README.rdoc
32
+ - Rakefile
33
+ - VERSION.yml
34
+ - examples/blog-to-staticify/config.ru
35
+ - examples/blog-to-staticify/my-blog.rb
36
+ - examples/blog-to-staticify/paths-to-cache
37
+ - examples/blog-to-staticify/posts/first.mkd
38
+ - examples/blog-to-staticify/posts/second.mkd
39
+ - examples/sinatra-blog-with-built-in-caching/my-sinatra-blog.rb
40
+ - lib/rack-staticifier.rb
41
+ - lib/rack/staticifier.rb
42
+ - spec/rack-staticifier_spec.rb
43
+ has_rdoc: true
44
+ homepage: http://github.com/remi/rack-staticifier
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.7
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Staticly cache requests to any Rack application
77
+ test_files:
78
+ - spec/rack-staticifier_spec.rb
79
+ - examples/blog-to-staticify/my-blog.rb
80
+ - examples/sinatra-blog-with-built-in-caching/my-sinatra-blog.rb