rack-staticifier 0.1.6

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.
@@ -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