Module: Sinatra::Cache::Helpers

Defined in:
lib/sinatra/cache/helpers.rb

Instance Method Summary collapse

Instance Method Details

#cache(content, opts = {}) ⇒ Object

NB!! Deprecated method.

Just returns the content after throwing out a warning.



436
437
438
439
# File 'lib/sinatra/cache/helpers.rb', line 436

def cache(content, opts={}) 
  warn("Deprecated method, caching is now happening by default if the :cache_enabled option is true")
  content
end

#cache_expire(path, options = {}) ⇒ Object

Expires the cached file (page) or fragment.

Examples

cache_expire('/contact')  =>  expires ../contact.html

cache_expire('/feed.rss')  =>  expires ../feed.rss

To expire a cached fragment:

cache_expire('/some/path', :fragment => :name_of_fragment )  
  =>  expires ../some/path/:name_of_fragment.html


458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
# File 'lib/sinatra/cache/helpers.rb', line 458

def cache_expire(path, options={}) 
  # 1. bail quickly if we don't have caching enabled
  return unless settings.cache_enabled
  options = { :fragment => false }.merge(options)
  
  if options[:fragment] # dealing with a fragment 
    dir_structure = path.gsub(/^\//,'').gsub(/\/$/,'')
    file_path = "#{settings.cache_fragments_output_dir}/#{dir_structure}/#{options[:fragment]}.html"
  else
    file_path = cache_file_path(path)
  end
  
  if test(?f, file_path)
    File.delete(file_path)
    log(:info,"Expired [#{file_path.sub(settings.root,'')}] successfully")
  else
    log(:warn,"The cached file [#{file_path}] could NOT be expired as it was NOT found")
  end
end

#cache_fragment(fragment_name, shared = nil, &block) ⇒ Object

This method either caches the code fragment and then renders it, or locates the cached fragement and renders that.

By default the cached fragement is stored in the ../tmp/cache_fragments/ directory at the root of your app.

Each fragment is stored in the same directory structure as your request so, if you have a request like this:

get '/articles/2010/02' ...

…the cached fragment will be stored as:

../tmp/cache_fragments/articles/2010/02/< name_of_fragment >.html

This enables you to use similar names for your fragments or have multiple URLs use the same view / layout.

Examples

<% cache_fragment(:name_of_fragment) do %>
  # do something worth caching
<% end %>

GOTCHA

The fragment caching is dependent upon the final URL, so in the case of a blog, where each article uses the same view, but through different URLs, each of the articles would cache it’s own fragment.

To sort-of deal with this limitation I have added a very hackish ‘fix’ through adding a 2nd parameter (see example below), which will remove the last part of the URL and use the rest of the URL as the stored fragment path.

Example

Given the URL:

get '/articles/2010/02/fragment-caching-with-sinatra-cache' ...

and the following #cache_fragment declaration in your view

<% cache_fragment(:name_of_fragment, :shared) do %>
  # do something worth caching
<% end %>

…the cached fragment would be stored as:

../tmp/cache_fragments/articles/2010/02/< name_of_fragment >.html

Any other URLs with the same URL root, like…

get '/articles/2010/02/writing-sinatra-extensions' ...

… would use the same cached fragment.

Raises:

  • (ArgumentError)


390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/sinatra/cache/helpers.rb', line 390

def cache_fragment(fragment_name, shared = nil, &block) 
  # 1. check for a block, there must always be a block
  raise ArgumentError, "Missing block" unless block_given?
  
  # 2. get the fragment path, by combining the PATH_INFO of the request, and the fragment_name
  dir_structure = request.path_info.empty? ? '' : request.path_info.gsub(/^\//,'').gsub(/\/$/,'')
  # if we are sharing this fragment with other URLs (as in the all the articles in a category of a blog) 
  # then lob off the last part of the URL
  unless shared.nil?
    dirs = dir_structure.split('/')
    dir_structure = dirs.first(dirs.length-1).join('/')
  end
  cf = "#{settings.cache_fragments_output_dir}/#{dir_structure}/#{fragment_name}.html"
  # 3. ensure the fragment cache directory exists for this fragment
  FileUtils.mkdir_p(File.dirname(cf)) rescue "ERROR: could NOT create the cache directory: [ #{File.dirname(cf)} ]"
  
  # 3. check if the fragment is already cached ?
  if test(?f, cf)
    # 4. yes. cached, so load it up into the ERB buffer .  Sorry, don't know how to do this for Haml or any others.
    block_content = IO.read(cf)
  else
    # 4. not cached, so process the block and then cache it
    block_content = capture_html(&block) if block_given?
    # 5. add some timestamp comments around the fragment, if the end user wants it
    if settings.cache_fragments_wrap_with_html_comments
      content_2_cache = "<!-- cache fragment: #{dir_structure}/#{fragment_name} -->"
      content_2_cache << block_content
      content_2_cache << "<!-- /cache fragment: #{fragment_name} cached at [ #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}] -->\n"
    else
      content_2_cache = block_content
    end
    # 6. write it to cache
    cache_write_file(cf, content_2_cache)
  end
  # 5. 'return' the content by
  block_is_template?(block) ? concat_content(block_content) : block_content
end

#cache_timestampObject Also known as: cache_page_timestamp, page_cached_at

Prints a basic HTML comment with a timestamp in it, so that you can see when a file was cached last.

NB! IE6 does NOT like this to be the first line of a HTML document, so output inside the <head> tag. Many hours wasted on that lesson ;-)

Examples

<%= cache_timestamp %>  # => <!--  page cached: 2009-12-21 12:00:00 -->


490
491
492
493
494
# File 'lib/sinatra/cache/helpers.rb', line 490

def cache_timestamp 
  if settings.cache_enabled && settings.cache_environment == settings.environment
    "<!-- page cached: #{Time.now.strftime("%Y-%m-%d %H:%M:%S")} -->\n"
  end
end