Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
avit committed Jun 15, 2012
0 parents commit fb6a4ba
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.gem
.bundle
Gemfile.lock
pkg/*
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source "http://rubygems.org"

# Specify your gem's dependencies in rspec_caching_test.gemspec
gemspec
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require "bundler/gem_tasks"
52 changes: 52 additions & 0 deletions lib/rspec-rails-caching.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require 'rspec-rails-caching/version'
require 'rspec-rails-caching/matchers'
require 'rspec-rails-caching/test_store'
require 'rspec-rails-caching/extensions/action_controller'

module RSpecRailsCaching
RSpec::Rails::ControllerExampleGroup.class_eval do
include Matchers
end

RSpec.configure do |config|
config.alias_it_should_behave_like_to :with_configuration, "with"
config.before(:all, :type => :controller, :caching => true) do |example|
silence_warnings do
@_orig_cache_store = RAILS_CACHE
Object.const_set "RAILS_CACHE", TestStore.new
end

ActionController::Base.cache_store = RAILS_CACHE
ActionController::Base.perform_caching = true

# The controller needs to be reloaded to metaprogram the caches_page
# callback with the perform_caching option turned on. There is no
# reloading if the example controller isn't in the load paths, likely
# because it was defined inline in the spec.
if ctrl_class_file =
ActiveSupport::Dependencies.search_for_file(example.class.controller_class.to_s.underscore)
then
ActiveSupport::Dependencies.load(ctrl_class_file)
end

example.class.controller_class.class_eval do
self.perform_caching = true
extend Extensions::ActionController::ClassMethods
end
end

config.after(:all) do |example|
silence_warnings do
Object.const_set "RAILS_CACHE", @_orig_cache_store
end
ActionController::Base.cache_store = RAILS_CACHE
ActionController::Base.perform_caching = false
end

config.around(:each, :type => :controller, :caching => true) do |example|
# This block does some voodoo to ensure the controller class gets
# reloaded in the right context. I don't understand why it's necessary.
end
end

end
1 change: 1 addition & 0 deletions lib/rspec-rails-caching/extensions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require 'rspec-rails-caching/extensions/action_controller/base'
20 changes: 20 additions & 0 deletions lib/rspec-rails-caching/extensions/action_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module RSpecRailsCaching::Extensions
module ActionController

module ClassMethods
def cache_page(content, path, extension = nil, *)
instrument_page_cache :write_page, path do
cache_store.cached_pages << path
end
end

def expire_page(path)
instrument_page_cache :expire_page, path do
cache_store.cached_pages.delete path
cache_store.expired_pages << path
end
end
end

end
end
9 changes: 9 additions & 0 deletions lib/rspec-rails-caching/matchers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module RSpecRailsCaching
module Matchers
end
end

require 'rspec-rails-caching/matchers/cache_page'
require 'rspec-rails-caching/matchers/expire_page'
require 'rspec-rails-caching/matchers/test_cache_caches'
require 'rspec-rails-caching/matchers/test_cache_expires'
38 changes: 38 additions & 0 deletions lib/rspec-rails-caching/matchers/cache_page.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module RSpecRailsCaching::Matchers
extend RSpec::Matchers::DSL

matcher :cache_page do |*expected|
match do |actual|
actual = actual.call if actual.respond_to?(:call)
unless actual.is_a? ActionController::TestResponse
raise ArgumentError("cache_page matcher expects a callable Proc or a TestResponse")
end

Array(expected).all? { |e| cache_store.page_cached?(e) }
end

failure_message_for_should do |actual|
"expected #{controller.class} to cache: #{expected.inspect} but got #{cache_results.inspect}"
end

failure_message_for_should_not do |actual|
"expected #{controller.class} not to cache: #{expected.inspect} but got #{cache_results.inspect}"
end

description do
"cache page #{expected.inspect}"
end

def controller
matcher_execution_context.controller
end

def cache_store
controller.cache_store
end

def cache_results
cache_store.cached_pages
end
end
end
38 changes: 38 additions & 0 deletions lib/rspec-rails-caching/matchers/expire_page.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module RSpecRailsCaching::Matchers
extend RSpec::Matchers::DSL

matcher :expire_page do |*expected|
match do |actual|
actual = actual.call if actual.respond_to?(:call)
unless actual.is_a? ActionController::TestResponse
raise ArgumentError("cache_page matcher expects a callable Proc or a TestResponse")
end

Array(expected).all? { |e| cache_store.page_expired?(e) }
end

failure_message_for_should do |actual|
"expected #{controller.class} to expire: #{expected.inspect} but got #{cache_results.inspect}"
end

failure_message_for_should_not do |actual|
"expected #{controller.class} not to expire: #{expected.inspect} but got #{cache_results.inspect}"
end

description do
"expire page #{expected.inspect}"
end

def controller
matcher_execution_context.controller
end

def cache_store
controller.cache_store
end

def cache_results
cache_store.expired_pages
end
end
end
70 changes: 70 additions & 0 deletions lib/rspec-rails-caching/test_store.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
module RSpecRailsCaching
class TestStore < ActiveSupport::Cache::Store

attr_reader :cached
attr_reader :expired
attr_reader :expiration_patterns
attr_reader :data
attr_accessor :read_cache
attr_reader :cached_pages
attr_reader :expired_pages

attr_accessor :context

def initialize(do_read_cache = false)
@data = {}
@cached = []
@expired = []
@expiration_patterns = []
@read_cache = do_read_cache
@cached_pages = []
@expired_pages = []
end

def reset
@data.clear
@cached.clear
@expired.clear
@expiration_patterns.clear
end

def read_entry(name, options = nil)
read_cache ? @data[name] : nil
end

def write_entry(name, value, options = nil)
@data[name] = value if read_cache
@cached << name
end

def delete_entry(name, options = nil)
@expired << name
end

def delete_matched(matcher, options = nil)
@expiration_patterns << matcher
end

def cached?(name)
@cached.include?(name)
end

def expired?(name)
@expired.include?(name) || @expiration_patterns.detect { |matcher| name =~ matcher }
end

def page_cached?(options = {})
@cached_pages.include?(test_cache_url(options))
end

def page_expired?(options = {})
@expired_pages.include?(test_cache_url(options))
end

private
def test_cache_url(options)
return options if options.is_a?(String)
url_for(options.merge({ :only_path => true, :skip_relative_url_root => true }))
end
end
end
3 changes: 3 additions & 0 deletions lib/rspec-rails-caching/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module RSpecRailsCaching
VERSION = "0.1.0"
end
22 changes: 22 additions & 0 deletions rspec-caching.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "rspec-rails-caching/version"

Gem::Specification.new do |s|
s.name = "rspec-rails-caching"
s.version = RSpecRailsCaching::VERSION
s.authors = ["Andrew Vit"]
s.email = ["[email protected]"]
s.homepage = "https://github.com/avit/rspec-rails-caching"
s.summary = %q{RSpec Rails Caching}
s.description = %q{RSpec helper for testing page and action caching in Rails}

s.rubyforge_project = "rspec-rails-caching"
s.add_dependency "rails", ">=3.0.0"
s.add_dependency "rspec", ">=2.8.0"

s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
end

0 comments on commit fb6a4ba

Please sign in to comment.