benjaminjackson-sinatra-cache 0.3.8

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,64 @@
1
+
2
+ module Sinatra
3
+
4
+ ##
5
+ # Sinatra::Templates
6
+ #
7
+ # Monkey-patches the private <tt>#render</tt> method,
8
+ # in order to support 'auto-magic' cache functionality.
9
+ #
10
+ #
11
+ module Templates
12
+
13
+ private
14
+
15
+ def render(engine, data, options={}, locals={}, &block)
16
+ # merge app-level options
17
+ options = settings.send(engine).merge(options) if settings.respond_to?(engine)
18
+ options[:outvar] ||= '@_out_buf'
19
+
20
+ # extract generic options
21
+ locals = options.delete(:locals) || locals || {}
22
+ views = options.delete(:views) || settings.views || "./views"
23
+ @default_layout = :layout if @default_layout.nil?
24
+ layout = options.delete(:layout)
25
+ layout = @default_layout if layout.nil? or layout == true
26
+ content_type = options.delete(:content_type) || options.delete(:default_content_type)
27
+
28
+ # set the cache related options
29
+ cache_enabled = settings.respond_to?(:cache_enabled) ? settings.send(:cache_enabled) : false
30
+ cache_output_dir = settings.send(:cache_output_dir) if settings.respond_to?(:cache_output_dir)
31
+ # raise Exception, "The Sinatra::Cache cache_output_dir variable is pointing to a non-existant directory cache_output_dir=[#{cache_output_dir}]" unless test(?d, cache_output_dir)
32
+ cache_option = options[:cache]
33
+ cache_option = true if cache_option.nil?
34
+
35
+ # compile and render template
36
+ layout_was = @default_layout
37
+ @default_layout = false
38
+ template = compile_template(engine, data, options, views)
39
+ output = template.render(self, locals, &block)
40
+ @default_layout = layout_was
41
+
42
+ # render layout
43
+ if layout
44
+ begin
45
+ options = options.merge(:views => views, :layout => false)
46
+ output = render(engine, layout, options, locals) { output }
47
+ # Cache the content or just return it
48
+ (cache_enabled && cache_option && settings.send(:environment) == settings.cache_environment) ?
49
+ cache_write_file(cache_file_path, output.gsub(/\n\r?$/,"")) : output
50
+ rescue Errno::ENOENT
51
+ end
52
+ end
53
+
54
+ # rendering without a layout
55
+ (cache_enabled && cache_option && settings.send(:environment) == settings.cache_environment) ?
56
+ cache_write_file(cache_file_path, output.gsub(/\n\r?$/,"") ) : output
57
+
58
+ output.extend(ContentTyped).content_type = content_type if content_type
59
+ output
60
+ end
61
+
62
+ end #/module Templates
63
+
64
+ end #/module Sinatra
@@ -0,0 +1,73 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{benjaminjackson-sinatra-cache}
8
+ s.version = "0.3.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["kematzy", "benjaminjackson"]
12
+ s.date = %q{2012-02-13}
13
+ s.description = %q{A Sinatra Extension that makes Page and Fragment Caching easy.}
14
+ s.email = %q{kematzy@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "lib/sinatra/cache.rb",
26
+ "lib/sinatra/cache/helpers.rb",
27
+ "lib/sinatra/templates.rb",
28
+ "sinatra-cache.gemspec",
29
+ "spec/fixtures/apps/base/views/css.sass",
30
+ "spec/fixtures/apps/base/views/fragments.erb",
31
+ "spec/fixtures/apps/base/views/fragments_shared.erb",
32
+ "spec/fixtures/apps/base/views/index.erb",
33
+ "spec/fixtures/apps/base/views/layout.erb",
34
+ "spec/fixtures/apps/base/views/params.erb",
35
+ "spec/fixtures/apps/partials/views/home/index.erb",
36
+ "spec/fixtures/apps/partials/views/layout.erb",
37
+ "spec/fixtures/apps/partials/views/shared/_header.erb",
38
+ "spec/sinatra/cache_spec.rb",
39
+ "spec/spec_helper.rb"
40
+ ]
41
+ s.homepage = %q{http://github.com/benjaminjackson/sinatra-cache}
42
+ s.rdoc_options = ["--charset=UTF-8"]
43
+ s.require_paths = ["lib"]
44
+ s.rubygems_version = %q{1.3.8}
45
+ s.summary = %q{A Sinatra Extension that makes Page and Fragment Caching easy.}
46
+ s.test_files = [
47
+ "spec/sinatra/cache_spec.rb",
48
+ "spec/spec_helper.rb"
49
+ ]
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<sinatra>, [">= 1.1.0"])
57
+ s.add_runtime_dependency(%q<sinatra-outputbuffer>, [">= 0.1.0"])
58
+ s.add_development_dependency(%q<sinatra-tests>, [">= 0.1.6"])
59
+ s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
60
+ else
61
+ s.add_dependency(%q<sinatra>, [">= 1.1.0"])
62
+ s.add_dependency(%q<sinatra-outputbuffer>, [">= 0.1.0"])
63
+ s.add_dependency(%q<sinatra-tests>, [">= 0.1.6"])
64
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<sinatra>, [">= 1.1.0"])
68
+ s.add_dependency(%q<sinatra-outputbuffer>, [">= 0.1.0"])
69
+ s.add_dependency(%q<sinatra-tests>, [">= 0.1.6"])
70
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
71
+ end
72
+ end
73
+
@@ -0,0 +1,2 @@
1
+ body
2
+ :color red
@@ -0,0 +1,11 @@
1
+ <h1>FRAGMENTS</h1>
2
+
3
+ <% cache_fragment(:test_fragment) do %>
4
+ <div id="cache-fragment">
5
+ <p><%= "Fragment created: #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}" %></p>
6
+ </div>
7
+ <% sleep 1 %>
8
+ <% end %>
9
+
10
+ <h2>Content After Sleep</h2>
11
+ <p><%= "Time is now: #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}" %></p>
@@ -0,0 +1,11 @@
1
+ <h1>FRAGMENTS - SHARED</h1>
2
+
3
+ <% cache_fragment(:test_fragment, :shared) do %>
4
+ <div id="cache-fragment">
5
+ <p><%= "Shared Fragment created: #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}" %></p>
6
+ </div>
7
+ <% sleep 1 %>
8
+ <% end %>
9
+
10
+ <h2>Content After Sleep</h2>
11
+ <p><%= "Time is now: #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}" %></p>
@@ -0,0 +1 @@
1
+ <h1>HOME</h1>
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head>
3
+ <title>Sinatra::Cache</title>
4
+ <%= cache_timestamp %>
5
+ </head>
6
+ <body>
7
+ <%= yield %>
8
+ </body>
9
+ </html>
@@ -0,0 +1,3 @@
1
+ <h1>PARAMS</h1>
2
+ <p><%= @captures.join(" | ") %></p>
3
+ <pre><%= params.inspect %></pre>
@@ -0,0 +1,4 @@
1
+ <% content_for :section_header do %>
2
+ <h1>HELLO from [content_for(:section_header)]</h1>
3
+ <% end %>
4
+ <h2>HELLO FROM [FILE <%= __FILE__ %>]</h2>
@@ -0,0 +1,11 @@
1
+ <html>
2
+ <head>
3
+ <title>Sinatra::Cache</title>
4
+ <%= cache_timestamp %>
5
+ </head>
6
+ <body>
7
+ <%= partial("shared/header") %>
8
+
9
+ <%= yield %>
10
+ </body>
11
+ </html>
@@ -0,0 +1,3 @@
1
+ <div id="header">
2
+ <%= yield_content :section_header %>
3
+ </div>
@@ -0,0 +1,967 @@
1
+
2
+ require "#{File.dirname(File.dirname(File.expand_path(__FILE__)))}/spec_helper"
3
+
4
+ describe "Sinatra" do
5
+
6
+ before(:each) do
7
+ @delete_cached_test_files = true #convenience toggle
8
+ end
9
+ describe "Cache" do
10
+
11
+ class MyDefaultsTestApp < MyTestApp
12
+ register(Sinatra::Cache)
13
+ end
14
+
15
+
16
+ class MyTestApp
17
+ register(Sinatra::Cache)
18
+
19
+ # need to set the root of the app for the default :cache_fragments_output_dir to work
20
+ set :root, ::APP_ROOT
21
+
22
+ set :cache_enabled, true
23
+ set :cache_environment, :test
24
+ set :cache_output_dir, "#{test_cache_path('system/cache')}"
25
+ set :cache_fragments_output_dir, "#{test_cache_path('system/cache')}_fragments"
26
+ set :cache_fragments_wrap_with_html_comments, false
27
+
28
+ # NB! Although without tests, the positioning of the custom method in relation to other
29
+ # Cache related declaration has no effect.
30
+ helpers do
31
+ def uncached_erb(template, options={})
32
+ erb(template, options.merge(:cache => false ))
33
+ end
34
+ end
35
+
36
+ get('/') { erb(:index) }
37
+ get('/erb/?') { erb(:index, :layout => false) }
38
+
39
+ # complex regex URL, matches
40
+ get %r{^/params/?([\s\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?} do
41
+ @captures = params[:captures].nil? ? [] : params[:captures].compact
42
+ erb(:params)
43
+ end
44
+ get('/file-extensions.*') do
45
+ @vars = { :framework => "Sinatra", :url => "www.sinatrarb.com" }
46
+ case params[:splat].first.to_sym
47
+ when :json
48
+ erb(@vars.to_json, :layout => false )
49
+ when :yaml
50
+ erb(@vars.to_yaml,:layout => false)
51
+ else
52
+ # direct output, should NOT be Cached
53
+ @vars.inspect
54
+ # @vars.inspect
55
+ end
56
+ end
57
+
58
+ ## NO CACHING
59
+ get('/uncached/erb'){ erb(:index, :cache => false) }
60
+ get('/uncached/erb/no/layout'){ erb(:index, :cache => false, :layout => false ) }
61
+ get('/uncached/uncached_erb'){ uncached_erb(:index) }
62
+
63
+ get '/css/screen.css' do
64
+ content_type 'text/css'
65
+ sass(:css, :style => :compact)
66
+ end
67
+ get '/css/no/cache.css' do
68
+ content_type 'text/css'
69
+ sass(:css, :style => :compact, :cache => false)
70
+ end
71
+
72
+ # enable :method_override
73
+ post('/post/?') { erb("POST", :layout => false) }
74
+ put('/put/?') { erb('PUT', :layout => false) }
75
+ delete('/delete/?') { erb('DELETE', :layout => false) }
76
+
77
+ get %r{^/fragments/?([\s\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?} do
78
+ erb(:fragments, :layout => false, :cache => false)
79
+ end
80
+ get %r{^/sharedfragments/?([\s\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?} do
81
+ erb(:fragments_shared, :layout => false, :cache => false)
82
+ end
83
+
84
+
85
+ end
86
+
87
+ # convenience shared spec that sets up MyTestApp and tests it's OK,
88
+ # without it you will get "stack level too deep" errors
89
+ it_should_behave_like "MyTestApp"
90
+
91
+ # it_should_behave_like "debug => app.methods"
92
+
93
+ describe "VERSION" do
94
+
95
+ it "should return the VERSION string" do
96
+ Sinatra::Cache::VERSION.should be_a_kind_of(String)
97
+ Sinatra::Cache::VERSION.should match(/\d\.\d+\.\d+(\.\d)?/)
98
+ end
99
+
100
+ end #/ VERSION
101
+
102
+ describe "#self.version" do
103
+
104
+ it "should return a version of the Sinatra::Cache VERSION string" do
105
+ Sinatra::Cache.version.should be_a_kind_of(String)
106
+ Sinatra::Cache.version.should match(/Sinatra::Cache v\d\.\d+\.\d+(\.\d)?/)
107
+ end
108
+
109
+ end #/ #self.version
110
+
111
+
112
+ describe "Configuration" do
113
+
114
+ describe "with Default Settings" do
115
+
116
+ it "should set :cache_enabled to false" do
117
+ MyDefaultsTestApp.cache_enabled.should == false
118
+ end
119
+
120
+ it "should set :cache_environment to :production" do
121
+ MyDefaultsTestApp.cache_environment.should == :production
122
+ end
123
+
124
+ it "should set :cache_page_extension to '.html'" do
125
+ MyDefaultsTestApp.cache_page_extension.should == '.html'
126
+ end
127
+
128
+ it "should set :cache_output_dir to '../public'" do
129
+ MyDefaultsTestApp.cache_output_dir.should == "#{public_fixtures_path}"
130
+ end
131
+
132
+ it "should set :cache_fragments_output_dir to '../tmp/cache_fragments'" do
133
+ MyDefaultsTestApp.cache_fragments_output_dir.should == "#{fixtures_path}/tmp/cache_fragments"
134
+ end
135
+
136
+ it "should set :cache_logging to true" do
137
+ MyDefaultsTestApp.cache_logging.should == true
138
+ end
139
+
140
+ it "should set :cache_logging_level to :info" do
141
+ MyDefaultsTestApp.cache_logging_level.should == :info
142
+ end
143
+
144
+ it "should set :cache_fragments_wrap_with_html_comments to true" do
145
+ MyDefaultsTestApp.cache_fragments_wrap_with_html_comments.should == true
146
+ end
147
+
148
+ end #/ with Default Settings
149
+
150
+ describe "with Custom Settings" do
151
+
152
+ it "should set :cache_enabled to true" do
153
+ MyTestApp.cache_enabled.should == true
154
+ end
155
+
156
+ it "should set :cache_environment to :test" do
157
+ MyTestApp.cache_environment.should == :test
158
+ end
159
+
160
+ it "should set :cache_page_extension to '.html'" do
161
+ MyTestApp.cache_page_extension.should == '.html'
162
+ end
163
+
164
+ it "should set :cache_output_dir to '../public/system/cache'" do
165
+ MyTestApp.cache_output_dir.should == "#{test_cache_path('system/cache')}"
166
+ end
167
+
168
+ it "should set :cache_fragments_output_dir to '../public/system/cache_fragments'" do
169
+ MyTestApp.cache_fragments_output_dir.should == "#{test_cache_path('system/cache')}_fragments"
170
+ end
171
+
172
+ it "should set :cache_logging to true" do
173
+ MyTestApp.cache_logging.should == true
174
+ end
175
+
176
+ it "should set :cache_logging_level to :info" do
177
+ MyTestApp.cache_logging_level.should == :info
178
+ end
179
+
180
+ it "should set :cache_fragments_wrap_with_html_comments to false" do
181
+ MyTestApp.cache_fragments_wrap_with_html_comments.should == false
182
+ end
183
+
184
+ end #/ Custom
185
+
186
+ end #/ Configuration
187
+
188
+
189
+ describe "Helpers" do
190
+
191
+ describe "#cache_timestamp" do
192
+
193
+ it "should return an HTML comment with the current timestamp" do
194
+ erb_app "<%= cache_timestamp %>"
195
+ body.should match(/\<\!-- page cached\: #{Regexp.escape(Time.now.strftime("%Y-%m-%d %H:%M:%S"))} -->/)
196
+ end
197
+
198
+ end #/ #cache_timestamp
199
+
200
+ module Sinatra::Cache::Helpers
201
+ public :cache_file_path, :cache_write_file, :cache_file_name, :cache_page_path
202
+ end
203
+
204
+ describe "#cache_file_path" do
205
+
206
+ it "should have some tests"
207
+
208
+ end #/ #cache_file_path
209
+
210
+ describe "#cache_write_file" do
211
+
212
+ it "should have some tests"
213
+
214
+ end #/ #cache_write_file
215
+
216
+ describe "#cache_file_name" do
217
+
218
+ it "should have some tests"
219
+
220
+ end #/ #cache_file_name
221
+
222
+ describe "#cache_page_path" do
223
+
224
+ it "should have some tests"
225
+
226
+ end #/ #cache_page_path
227
+
228
+ end #/ Helpers
229
+
230
+
231
+ describe "with caching enabled" do
232
+
233
+ describe "basic Page caching" do
234
+
235
+ describe "GET requests for" do
236
+
237
+ describe "the Home page - ['/' => /index.html] (with layout)" do
238
+
239
+ before(:each) do
240
+ @cache_file = "#{test_cache_path('system/cache')}/index.html"
241
+ get('/')
242
+ end
243
+
244
+ after(:each) do
245
+ FileUtils.rm(@cache_file) if @delete_cached_test_files
246
+ end
247
+
248
+ it "should render the expected output" do
249
+ body.should have_tag('html > head > title', 'Sinatra::Cache')
250
+ body.should match(/<!-- page cached: #{Regexp.escape(Time.now.strftime("%Y-%m-%d %H:%M:%S"))} -->/)
251
+ body.should have_tag('html > body > h1', 'HOME')
252
+ end
253
+
254
+ it "should create a cached file in the cache output directory" do
255
+ test(?f, @cache_file).should == true
256
+ end
257
+
258
+ end #/ GET ['/' => /index.html]
259
+
260
+ describe "a basic URL without a trailing slash - ['/erb' => /erb.html] (ERB without layout)" do
261
+
262
+ before(:each) do
263
+ @cache_file = "#{test_cache_path('system/cache')}/erb.html"
264
+ get('/erb')
265
+ end
266
+
267
+ after(:each) do
268
+ FileUtils.rm(@cache_file) if @delete_cached_test_files
269
+ end
270
+
271
+ it "should render the expected output" do
272
+ body.should == "<h1>HOME</h1>"
273
+ end
274
+
275
+ it "should create a cached file in the cache output directory" do
276
+ test(?f, @cache_file).should == true
277
+ end
278
+
279
+ end #/ GET ['/erb' => /erb.html]
280
+
281
+ describe "a basic URL with a trailing slash - ['/erb/' => /erb/index.html]" do
282
+
283
+ before(:each) do
284
+ @cache_file = "#{test_cache_path('system/cache')}/erb/index.html"
285
+ get('/erb/')
286
+ end
287
+
288
+ after(:each) do
289
+ FileUtils.rm(@cache_file) if @delete_cached_test_files
290
+ end
291
+
292
+ it "should render the expected output" do
293
+ body.should == "<h1>HOME</h1>"
294
+ end
295
+
296
+ it "should create a cached file at ../cache/< URL >/index.html" do
297
+ test(?f, @cache_file).should == true
298
+ end
299
+
300
+ end #/ GET ['/erb/' => /erb/index.html]
301
+
302
+ describe "a URL with file extension - ['/file-extensions.EXT' => /file-extensions.EXT]" do
303
+
304
+ before(:each) do
305
+ ext = '.yaml'
306
+ @cache_file = "#{test_cache_path('system/cache')}/file-extensions#{ext}"
307
+ get("/file-extensions#{ext}")
308
+ end
309
+
310
+ after(:each) do
311
+ FileUtils.rm(@cache_file) if @delete_cached_test_files
312
+ end
313
+
314
+ it "should render the expected output" do
315
+ body.should_not == ""
316
+ end
317
+
318
+ it "should create the cached file with the extension" do
319
+ test(?f, @cache_file).should == true
320
+ end
321
+
322
+ end #/ GET ['/file-extensions.EXT' => /file-extensions.EXT]
323
+
324
+ describe "URLs with multiple levels and/or with ?params attached" do
325
+
326
+ %w(
327
+ /params/? /params/1.xml?p=2 /params/page/?page=2 /params/page/?page=99
328
+ /params/a/ /params/a/b /params/a/b/c /params/a/b/c/d
329
+ ).each do |url|
330
+
331
+ # does the URL contain a ? or not
332
+ params_free_url = url =~ /\?/ ? url.split('?').first.chomp('?') : url
333
+ file_url = (params_free_url[-1,1] =~ /\//) ? "#{params_free_url}index" : params_free_url
334
+
335
+ # create the string for the test output below
336
+ file_url_str = File.extname(file_url) == '' ? file_url << '.html' : file_url
337
+
338
+ describe "the URL ['#{url}' => #{file_url_str}]" do
339
+
340
+ before(:each) do
341
+ @file_url = file_url
342
+ @cache_file = "#{test_cache_path('system/cache')}#{file_url}"
343
+ @cache_file << ".html" if File.extname(@file_url) == ''
344
+ # puts "when the URL=[#{url}] the @cache_file=[#{@cache_file}] [#{__FILE__}:#{__LINE__}]"
345
+ get(url)
346
+ end
347
+
348
+ after(:each) do
349
+ FileUtils.remove_dir("#{test_cache_path('system/cache')}/params") if @delete_cached_test_files
350
+ end
351
+
352
+ it "should render the expected output" do
353
+ body.should have_tag('html > head > title', 'Sinatra::Cache')
354
+ body.should have_tag('html > body > h1', 'PARAMS')
355
+ body.should have_tag('html > body > p' )
356
+ end
357
+
358
+ it "should create a cached file at [../public/system/cache#{file_url_str}]" do
359
+ test(?f, @cache_file).should == true
360
+ end
361
+
362
+ end #/ GET 'url' -
363
+
364
+ end #/ end loop
365
+
366
+ end #/ URLs with multiple levels and/or with ?params attached
367
+
368
+ describe "with :cache => false, :layout => false " do
369
+
370
+ before(:each) do
371
+ @cache_file = "#{test_cache_path('system/cache')}/uncached/erb/no/layout.html"
372
+ get('/uncached/erb/no/layout')
373
+ end
374
+
375
+ it "should output the correct HTML as expected" do
376
+ body.should have_tag('h1', 'HOME')
377
+ end
378
+
379
+ it "should NOT cache the output" do
380
+ test(?d, File.dirname(@cache_file) ).should == false # testing for directory
381
+ test(?f, @cache_file).should == false
382
+ end
383
+
384
+ end #/ with :cache => false, :layout => false
385
+
386
+ describe "with :cache => false" do
387
+
388
+ before(:each) do
389
+ @cache_file = "#{test_cache_path('system/cache')}/uncached/erb.html"
390
+ get('/uncached/erb')
391
+ end
392
+
393
+ it "should output the correct HTML as expected" do
394
+ body.should have_tag('h1', 'HOME')
395
+ end
396
+
397
+ it "should NOT cache the output" do
398
+ test(?d, File.dirname(@cache_file) ).should == false # testing for directory
399
+ test(?f, @cache_file).should == false
400
+ end
401
+
402
+ end #/ with :cache => false
403
+
404
+ describe "URLs with custom erb helpers, like :admin_erb().." do
405
+
406
+ before(:each) do
407
+ @cache_file = "#{test_cache_path('system/cache')}/uncached/uncached_erb.html"
408
+ get('/uncached/uncached_erb')
409
+ end
410
+
411
+ it "should output the correct HTML as expected" do
412
+ body.should have_tag('html > body > h1', 'HOME')
413
+ end
414
+
415
+ it "should NOT cache the output" do
416
+ test(?d, File.dirname(@cache_file) ).should == false # testing for directory
417
+ test(?f, @cache_file).should == false
418
+ end
419
+
420
+ end #/ URLs with custom erb helpers, like :admin_erb()..
421
+
422
+ describe "CSS URLs with dynamic .sass files" do
423
+
424
+ describe "the URL ['/css/screen.css' => /css/screen.css]" do
425
+
426
+ before(:each) do
427
+ @cache_file = "#{test_cache_path('system/cache')}/css/screen.css"
428
+ FileUtils.remove_dir(File.dirname(@cache_file), :force => true )
429
+ get('/css/screen.css')
430
+ end
431
+
432
+ after(:each) do
433
+ FileUtils.rm(@cache_file) if @delete_cached_test_files
434
+ FileUtils.remove_dir(File.dirname(@cache_file), :force => true ) if @delete_cached_test_files
435
+ end
436
+
437
+ it "should output the correct CSS as expected" do
438
+ body.should == "body { color: red; }\n"
439
+ end
440
+
441
+ it "should automatically create the cache /css output directory" do
442
+ test(?d, File.dirname(@cache_file) ).should == true
443
+ end
444
+
445
+ it "should create a cached file at [../public/system/cache/css/screen.css]" do
446
+ test(?f, @cache_file).should == true
447
+ end
448
+
449
+ end #/ GET ['/css/screen.css' => /css/screen.css]
450
+
451
+ describe "URLs with ':cache => false' - ['/css/no/cache.css' => /css/no/cache.css]" do
452
+
453
+ before(:each) do
454
+ @cache_file = "#{test_cache_path('system/cache')}/css/no/cache.css"
455
+ get('/css/no/cache.css')
456
+ end
457
+
458
+ it "should output the correct CSS as expected" do
459
+ body.should == "body { color: red; }\n"
460
+ end
461
+
462
+ it "should NOT cache the output" do
463
+ test(?d, File.dirname(@cache_file) ).should == false # testing for directory
464
+ test(?f, @cache_file).should == false
465
+ end
466
+
467
+ end #/ GET ['/css/no/cache.css' => /css/no/cache.css]
468
+
469
+ end #/ CSS URLs with dynamic .sass files
470
+
471
+ end #/ GET requests
472
+
473
+ describe "POST, PUT, DELETE requests" do
474
+
475
+ describe "POST '/post'" do
476
+
477
+ before(:each) do
478
+ @cache_file = "#{test_cache_path('system/cache')}/post.html"
479
+ post('/post', :test => {:name => "test-#{Time.now.strftime("%Y-%d-%m %H:%M:%S")}", :content => "with content" })
480
+ end
481
+
482
+ it "should render any output as normal" do
483
+ body.should == 'POST'
484
+ end
485
+
486
+ it "should NOT cache the output" do
487
+ test(?f, @cache_file).should == false
488
+ end
489
+
490
+ end #/ POST '/post'
491
+
492
+ describe "PUT '/put'" do
493
+
494
+ before(:each) do
495
+ @cache_file = "#{test_cache_path('system/cache')}/put.html"
496
+ put('/put', { :test => { :name => "test" }, :_method => "put" })
497
+ end
498
+
499
+ it "should render any output as normal" do
500
+ body.should == 'PUT'
501
+ end
502
+
503
+ it "should NOT cache the output" do
504
+ test(?f, @cache_file).should == false
505
+ end
506
+
507
+ end #/ PUT '/put'
508
+
509
+ describe "DELETE '/delete'" do
510
+
511
+ before(:each) do
512
+ @cache_file = "#{test_cache_path('system/cache')}/delete.html"
513
+ delete('/delete') #, { :test => { :name => "test" }, :_method => "put" })
514
+ end
515
+
516
+ it "should render any output as normal" do
517
+ body.should == 'DELETE'
518
+ end
519
+
520
+ it "should NOT cache the output" do
521
+ test(?f, @cache_file).should == false
522
+ end
523
+
524
+ end #/ DELETE '/delete'
525
+
526
+ end #/ POST, PUT, DELETE requests
527
+
528
+ end #/ basic Page caching
529
+
530
+ describe "and Fragment caching" do
531
+
532
+ describe "with default settings" do
533
+
534
+ def app; ::MyTestApp.new ; end
535
+
536
+ describe "using NOT shared fragments" do
537
+
538
+ after(:all) do
539
+ FileUtils.rm_r("#{test_cache_path('system/cache')}_fragments/fragments") if @delete_cached_test_files
540
+ end
541
+
542
+ %w(
543
+ /fragments /fragments/a/b/ /fragments/with/param/?page=1
544
+ /fragments/dasherised-urls/works-as-well
545
+ ).each do |url|
546
+
547
+ params_free_url = url =~ /\?/ ? url.split('?').first.chomp('?') : url
548
+ dir_structure = params_free_url.gsub(/^\//,'').gsub(/\/$/,'')
549
+
550
+ it "should cache the fragments from the URL [#{url}] as [#{dir_structure}/test_fragment.html]" do
551
+ get(url)
552
+ # body.should have_tag(:debug)
553
+ body.should have_tag('h1','FRAGMENTS', :count => 1)
554
+ body.should_not match(/<!-- cache fragment:(.+)test_fragment -->/)
555
+ body.should_not match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
556
+
557
+ # render the page a 2nd time from cache
558
+ get(url)
559
+ body.should have_tag('h1','FRAGMENTS', :count => 1)
560
+ body.should_not match(/<!-- cache fragment:(.+)test_fragment -->/)
561
+ body.should_not match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
562
+
563
+ # the cached fragment has already been found if we get this far,
564
+ # but just for good measure do we check for the existence of the fragment file.
565
+ test(?f, "#{test_cache_path('system/cache')}_fragments/#{dir_structure}/test_fragment.html").should == true
566
+ end
567
+ end
568
+
569
+ end #/ using NOT shared fragments
570
+
571
+ describe "using shared fragments" do
572
+
573
+ after(:all) do
574
+ FileUtils.rm_r("#{test_cache_path('system/cache')}_fragments/sharedfragments") if @delete_cached_test_files
575
+ end
576
+
577
+ describe "when requesting the first URL" do
578
+
579
+ # FIXME:: work out some clever way to split all of these tests into single items instead of in one big blob
580
+
581
+ it "should cache the fragment based on the URL and use it on subsequent requests by URLs sharing the same root URL" do
582
+ url = '/sharedfragments/2010/02/some-article-01'
583
+ params_free_url = url =~ /\?/ ? url.split('?').first.chomp('?') : url
584
+ dir_structure = params_free_url.gsub(/^\//,'').gsub(/\/$/,'')
585
+ dirs = dir_structure.split('/')
586
+ dir_structure = dirs.first(dirs.length-1).join('/')
587
+
588
+ get(url)
589
+ # body.should have_tag(:debug)
590
+ body.should have_tag('h1','FRAGMENTS - SHARED', :count => 1)
591
+ body.should_not match(/<!-- cache fragment:(.+)test_fragment -->/)
592
+ body.should_not match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
593
+
594
+ get(url)
595
+ body.should have_tag('h1','FRAGMENTS - SHARED', :count => 1)
596
+ body.should_not match(/<!-- cache fragment:(.+)test_fragment -->/)
597
+ body.should_not match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
598
+
599
+ # the cached fragment has already been found if we get this far,
600
+ # but just for good measure do we check for the existence of the fragment file.
601
+ test(?f, "#{test_cache_path('system/cache')}_fragments/#{dir_structure}/test_fragment.html").should == true
602
+
603
+ # should use the cached fragment rather than cache a new fragment
604
+ url = '/sharedfragments/2010/02/another-article-02'
605
+ get(url)
606
+ body.should have_tag('h1','FRAGMENTS - SHARED', :count => 1)
607
+ body.should_not match(/<!-- cache fragment:(.+)test_fragment -->/)
608
+ body.should_not match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
609
+ end
610
+
611
+ end #/ when requesting the first URL
612
+
613
+ end #/ using shared fragments
614
+
615
+ end #/ with default settings
616
+
617
+ describe "with :cache_fragments_wrap_with_html_comments enabled" do
618
+
619
+ class MyWrapTestApp < Sinatra::Base
620
+
621
+ set :app_dir, "#{APP_ROOT}/apps/base"
622
+ set :public, "#{fixtures_path}/public"
623
+ set :views, "#{app_dir}/views"
624
+
625
+ register(Sinatra::Tests)
626
+
627
+ enable :raise_errors
628
+
629
+ register(Sinatra::Cache)
630
+
631
+ # need to set the root of the app for the default :cache_fragments_output_dir to work
632
+ set :root, ::APP_ROOT
633
+
634
+ set :cache_enabled, true
635
+ set :cache_environment, :test
636
+ set :cache_output_dir, "#{test_cache_path('system/cache')}"
637
+ set :cache_fragments_output_dir, "#{test_cache_path('system/cache')}_wrap_fragments"
638
+ set :cache_fragments_wrap_with_html_comments, true
639
+
640
+ get('/') { erb(:index) }
641
+
642
+ get %r{^/fragments/?([\s\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?} do
643
+ erb(:fragments, :layout => false, :cache => false)
644
+ end
645
+ get %r{^/sharedfragments/?([\s\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?} do
646
+ erb(:fragments_shared, :layout => false, :cache => false)
647
+ end
648
+
649
+ end
650
+
651
+ def app; ::MyWrapTestApp.new ; end
652
+
653
+ describe "using NOT shared fragments" do
654
+
655
+ after(:all) do
656
+ FileUtils.rm_r("#{test_cache_path('system/cache')}_wrap_fragments/fragments") if @delete_cached_test_files
657
+ end
658
+
659
+ %w(
660
+ /fragments /fragments/a/b/ /fragments/with/param/?page=1
661
+ /fragments/dasherised-urls/works-as-well
662
+ ).each do |url|
663
+
664
+ params_free_url = url =~ /\?/ ? url.split('?').first.chomp('?') : url
665
+ dir_structure = params_free_url.gsub(/^\//,'').gsub(/\/$/,'')
666
+
667
+ it "should cache the fragments from the URL [#{url}] as [#{dir_structure}/test_fragment.html]" do
668
+ get(url)
669
+ # body.should have_tag(:debug)
670
+ body.should have_tag('h1','FRAGMENTS', :count => 1)
671
+ body.should_not match(/<!-- cache fragment:(.+)test_fragment -->/)
672
+ body.should_not match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
673
+
674
+ # render the page a 2nd time from cache
675
+ get(url)
676
+ body.should have_tag('h1','FRAGMENTS', :count => 1)
677
+ body.should match(/<!-- cache fragment:(.+)test_fragment -->/)
678
+ body.should match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
679
+
680
+ # the cached fragment has already been found if we get this far,
681
+ # but just for good measure do we check for the existence of the fragment file.
682
+ test(?f, "#{test_cache_path('system/cache')}_wrap_fragments/#{dir_structure}/test_fragment.html").should == true
683
+ end
684
+ end
685
+
686
+ end #/ using NOT shared fragments
687
+
688
+ describe "using shared fragments" do
689
+
690
+ after(:all) do
691
+ FileUtils.rm_r("#{test_cache_path('system/cache')}_wrap_fragments/sharedfragments") if @delete_cached_test_files
692
+ end
693
+
694
+ describe "when requesting the first URL" do
695
+
696
+ # FIXME:: work out some clever way to split all of these tests into single items instead of in one big blob
697
+
698
+ it "should cache the fragment based on the URL and use it on subsequent requests by URLs sharing the same root URL" do
699
+ url = '/sharedfragments/2010/02/some-article-01'
700
+ params_free_url = url =~ /\?/ ? url.split('?').first.chomp('?') : url
701
+ dir_structure = params_free_url.gsub(/^\//,'').gsub(/\/$/,'')
702
+ dirs = dir_structure.split('/')
703
+ dir_structure = dirs.first(dirs.length-1).join('/')
704
+
705
+ get(url)
706
+ # body.should have_tag(:debug)
707
+ body.should have_tag('h1','FRAGMENTS - SHARED', :count => 1)
708
+ body.should_not match(/<!-- cache fragment:(.+)test_fragment -->/)
709
+ body.should_not match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
710
+
711
+ get(url)
712
+ body.should have_tag('h1','FRAGMENTS - SHARED', :count => 1)
713
+ body.should match(/<!-- cache fragment:(.+)test_fragment -->/)
714
+ body.should match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
715
+
716
+ # the cached fragment has already been found if we get this far,
717
+ # but just for good measure do we check for the existence of the fragment file.
718
+ test(?f, "#{test_cache_path('system/cache')}_wrap_fragments/#{dir_structure}/test_fragment.html").should == true
719
+
720
+ # should use the cached fragment rather than cache a new fragment
721
+ url = '/sharedfragments/2010/02/another-article-02'
722
+ get(url)
723
+ body.should have_tag('h1','FRAGMENTS - SHARED', :count => 1)
724
+ body.should match(/<!-- cache fragment:(.+)test_fragment -->/)
725
+ body.should match(/<!-- \/cache fragment: test_fragment cached at \[ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\] -->/)
726
+ end
727
+
728
+ end #/ when requesting the first URL
729
+
730
+ end #/ using shared fragments
731
+
732
+ end #/ with customs settings
733
+
734
+
735
+ end #/ and Fragment caching
736
+
737
+ describe "basic Cache Expiring" do
738
+
739
+ describe "Pages" do
740
+
741
+ it "should expire the page ['/params/cache/expire/' => ../cache/params/cache/expire/index.html]" do
742
+ get('/params/cache/expire/')
743
+ test(?f,"#{test_cache_path('system/cache')}/params/cache/expire/index.html" ).should == true
744
+ lambda {
745
+ erb_app "<% cache_expire('/params/cache/expire/') %>"
746
+ }.should_not raise_error(Exception)
747
+
748
+ test(?f,"#{test_cache_path('system/cache')}/params/cache/expire/index.html" ).should == false
749
+
750
+ end
751
+
752
+ it "should expire the page ['/params/cache/expired' => ../cache/params/cache/expired.html]" do
753
+ get('/params/cache/expired')
754
+ test(?f,"#{test_cache_path('system/cache')}/params/cache/expired.html" ).should == true
755
+ lambda {
756
+ erb_app "<% cache_expire('/params/cache/expired') %>"
757
+ }.should_not raise_error(Exception)
758
+
759
+ test(?f,"#{test_cache_path('system/cache')}/params/cache/expired.html" ).should == false
760
+
761
+ end
762
+
763
+ end #/ Pages
764
+
765
+ describe "Fragments" do
766
+
767
+ it "should expire the fragment ['/fragments/cache/expire/' => ../cache_fragments/fragments/cache/expire/test_fragment.html]" do
768
+ get('/fragments/cache/expire/')
769
+ test(?f,"#{test_cache_path('system/cache')}_fragments/fragments/cache/expire/test_fragment.html" ).should == true
770
+ lambda {
771
+ erb_app "<% cache_expire('/fragments/cache/expire/',:fragment => :test_fragment) %>"
772
+ }.should_not raise_error(Exception)
773
+ test(?f,"#{test_cache_path('system/cache')}/params/cache_fragments/expire/test_fragment.html" ).should == false
774
+ end
775
+
776
+ it "should expire the fragment ['/fragments/cache/expired' => ../cache_fragments/fragments/cache/expired/test_fragment.html]" do
777
+ get('/fragments/cache/expired')
778
+ test(?f,"#{test_cache_path('system/cache')}_fragments/fragments/cache/expired/test_fragment.html" ).should == true
779
+ lambda {
780
+ erb_app "<% cache_expire('/fragments/cache/expired',:fragment => :test_fragment) %>"
781
+ }.should_not raise_error(Exception)
782
+ test(?f,"#{test_cache_path('system/cache')}/params/cache_fragments/expired/test_fragment.html" ).should == false
783
+ end
784
+
785
+ end #/ Pages
786
+
787
+ end #/ basic Cache Expiring
788
+
789
+
790
+ end #/ with caching enabled
791
+
792
+ describe "EDGE cases" do
793
+
794
+ describe "Using nested buffers" do
795
+
796
+ require 'sinatra/outputbuffer'
797
+
798
+ class MyPartialsTestApp < Sinatra::Base
799
+ register(Sinatra::Tests)
800
+
801
+ enable :raise_errors
802
+
803
+ register(Sinatra::OutputBuffer)
804
+ register(Sinatra::Cache)
805
+
806
+ # need to set the root of the app for the default :cache_fragments_output_dir to work
807
+ set :root, ::APP_ROOT
808
+ set :app_dir, "#{APP_ROOT}/apps/partials"
809
+ set :public, "#{fixtures_path}/public"
810
+ set :views, "#{APP_ROOT}/apps/partials/views"
811
+
812
+ set :cache_enabled, true
813
+ set :cache_environment, :test
814
+ set :cache_output_dir, "#{test_cache_path('system/cache')}"
815
+ set :cache_fragments_output_dir, "#{test_cache_path('system/cache')}_fragments"
816
+
817
+ # NB! Although without tests, the positioning of the custom method in relation to other
818
+ # Cache related declaration has no effect.
819
+ helpers do
820
+ def uncached_erb(template, options={})
821
+ erb(template, options.merge(:cache => false ))
822
+ end
823
+
824
+ ##
825
+ # Renders ERB partials
826
+ #
827
+ # ==== Examples
828
+ #
829
+ # <%= partial('shared/header') %> => renders app/views/shared/_header.erb
830
+ #
831
+ # <%= partial('snippets/snippet') %> => renders app/views/snippets/_snippet.erb
832
+ #
833
+ #
834
+ # @api public
835
+ def partial(template, *args)
836
+ template_array = template.to_s.split('/')
837
+ template = template_array[0..-2].join('/') + "/_#{template_array[-1]}"
838
+ options = args.last.is_a?(Hash) ? args.pop : {}
839
+ options.merge!(:layout => false, :cache => false) # add support for Sinatra::Cache
840
+ # options[:outvar] = '@_out_buf'
841
+ if collection = options.delete(:collection) then
842
+ collection.inject([]) do |buffer, member|
843
+ buffer << erb(:"#{template}", options.merge(:layout => false, :locals => { template_array[-1].to_sym => member } ) )
844
+ end.join("\n")
845
+ else
846
+ erb(:"#{template}", options)
847
+ end
848
+ rescue Errno::ENOENT => e
849
+ out = "ERROR: The partial [views/#{template.to_s}] is missing."
850
+ out << " Please create it to remove this error. [ Exception: #{h e.inspect}]" if self.class.development? || self.class.test?
851
+ out
852
+ rescue Exception => e
853
+ if self.class.production?
854
+ # TODO:: must store the error in the log somehow.
855
+ "<!-- ERROR: rendering the partial [#{template.to_s}] -->"
856
+ else
857
+ throw e
858
+ end
859
+ end
860
+
861
+ end
862
+
863
+ get('/') { erb(:"home/index") }
864
+ # get('/erb/?') { erb(:index, :layout => false) }
865
+
866
+ # complex regex URL, matches
867
+ get %r{^/params/?([\s\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?} do
868
+ @captures = params[:captures].nil? ? [] : params[:captures].compact
869
+ erb(:params)
870
+ end
871
+ get('/file-extensions.*') do
872
+ @vars = { :framework => "Sinatra", :url => "www.sinatrarb.com" }
873
+ case params[:splat].first.to_sym
874
+ when :json
875
+ erb(@vars.to_json, :layout => false )
876
+ when :yaml
877
+ erb(@vars.to_yaml,:layout => false)
878
+ else
879
+ # direct output, should NOT be Cached
880
+ @vars.inspect
881
+ # @vars.inspect
882
+ end
883
+ end
884
+
885
+ ## NO CACHING
886
+ get('/uncached/erb'){ erb(:index, :cache => false) }
887
+ get('/uncached/erb/no/layout'){ erb(:index, :cache => false, :layout => false ) }
888
+ get('/uncached/uncached_erb'){ uncached_erb(:index) }
889
+
890
+ get '/css/screen.css' do
891
+ content_type 'text/css'
892
+ sass(:css, :style => :compact)
893
+ end
894
+ get '/css/no/cache.css' do
895
+ content_type 'text/css'
896
+ sass(:css, :style => :compact, :cache => false)
897
+ end
898
+
899
+ # enable :method_override
900
+ post('/post/?') { erb("POST", :layout => false) }
901
+ put('/put/?') { erb('PUT', :layout => false) }
902
+ delete('/delete/?') { erb('DELETE', :layout => false) }
903
+
904
+ get %r{^/fragments/?([\s\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?} do
905
+ erb(:fragments, :layout => false, :cache => false)
906
+ end
907
+ get %r{^/sharedfragments/?([\s\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?} do
908
+ erb(:fragments_shared, :layout => false, :cache => false)
909
+ end
910
+
911
+ end
912
+
913
+ def app; ::MyPartialsTestApp.new ; end
914
+
915
+ describe "basic Page caching" do
916
+
917
+ describe "GET requests for" do
918
+
919
+ describe "the Home page - ['/' => /index.html] (with layout)" do
920
+
921
+ before(:each) do
922
+ @cache_file = "#{test_cache_path('system/cache')}/index.html"
923
+ get('/')
924
+ end
925
+
926
+ after(:each) do
927
+ FileUtils.rm(@cache_file) if @delete_cached_test_files
928
+ end
929
+
930
+ it "should render the expected output" do
931
+ # <html>
932
+ # <head>
933
+ # <title>Sinatra::Cache</title>
934
+ # <!-- page cached: 2010-11-15 18:21:06 -->
935
+ # </head>
936
+ # <body>
937
+ # <div id="header">
938
+ # <h1>HELLO from [content_for(:section_header)]</h1>
939
+ # </div>
940
+ # <h2>HELLO FROM [FILE ../sinatra-cache/spec/fixtures/apps/partials/views/home/index.erb]</h2>
941
+ # </body>
942
+ # </html>
943
+ body.should have_tag('html > head > title', 'Sinatra::Cache')
944
+ body.should match(/<!-- page cached: \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d -->/)
945
+ body.should have_tag('html > body > div#header > h1', /HELLO from \[content_for\(:section_header\)\]/)
946
+ body.should have_tag('html > body > h2', /HELLO FROM \[/)
947
+ end
948
+
949
+ it "should create a cached file in the cache output directory" do
950
+ test(?f, @cache_file).should == true
951
+ end
952
+
953
+ end #/ GET ['/' => /index.html]
954
+
955
+ end #/ GET requests
956
+
957
+ end #/ basic Page caching
958
+
959
+
960
+ end #/ Using nested buffers
961
+
962
+ end #/ EDGE cases
963
+
964
+
965
+ end #/ Cache
966
+
967
+ end #/ Sinatra