Skip to content

Commit

Permalink
Adds some of the functionality for controller methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Neighman committed Jun 22, 2008
1 parent 5c997f8 commit 036e206
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 30 deletions.
86 changes: 82 additions & 4 deletions docs/merb cache spec thoughts.txt
Expand Up @@ -34,15 +34,93 @@

## API
# Similar to existing API:
# Actions should only cache on get requests

# CLASS
cache_action :action, ttl, :key_params => [:id, :username]

cache_action :action, ttl
cache_actions [:action, [:action, ttl]]
cache_actions [[:action, ttl], [:action, ttl]]
cache_actions :exclude => [:index, :show]


################ EXAMPLE CLASS LEVEL CALLS
cache_page :index

cache_actions :expire_in => <seconds>

cache_action(:show, :store => :my_memcached_store) do |controller|
expire_in <seconds>
keys = [:year, :month, :day, :name]

if controller.current_user.is_admin?
base_key "path/to/admin_area"
keys.unshift(controller.current_user.id) # Need another array for the SHA
key_params keys
else
key_params keys
end
end

cache_actions :create, :update do |controller|
force_action_cache(controller, :show, :year => 2007, :month => 3, :day => 5)
force_action_cache(controller, :index)
force_fragment_cache(:some => "key")
do_not_cache_this_action!
# Need a way to tell force_action_cache that the action was successful
end

cache_action :edit, :expire_in => <seconds>

################## END EXAMPLE

Use a Merb::Cache::Proxy object to calculate the base key, params_key, and id_key or get the default
Stick it into run method where we setup a

expire_action :action
expire_actions [:action, :action]

cached_action? :action
setup before :run_cache with whatever options are required
opts
p = Proc.new{ _run_cache(opts) }
before :only => [:show, :index] &p

def _run_cache(opts)
CacheProxy.new(opts).run!(&(self.class._cache_store[action_name]))
end

Where run! yields to the given block

CacheProxy should be able to read a cache param to force the cache.


cache_actions :exclude => [:create, :delete, :update] do

end

# INSTANCE METHODS
expire_action :action
expire_actions [:action, :action]
cached? :action
cached? "key"
expire! "key"


# Should only be get requests that are cached. So URL should identify the params

# Default Keys

# Page Cache
page cache key = Match the URL path with <action>.<format> !!!ALWAYS!!!

# Action Cache
cache_action :action do
action_cache_key(:some => "additional", :param => "keys")
end
fragment_key_base + params_key( which is URL path) + id_keys as hash .format

# Fragment Cache
cache_fragment(
fragment_cache_key = fragment_key_base + params_key + id_key


# New thoughts

Expand Down
1 change: 0 additions & 1 deletion lib/merb-cache.rb
Expand Up @@ -9,7 +9,6 @@
require 'merb-cache/cache_store'

path = File.expand_path(File.join(File.dirname(__FILE__))) / "merb-cache" / "cache_stores"
puts "Path is #{path}"
Merb::Cache.register(:memcached, :path => (path / "memcached_store"), :class_name => "MemcachedStore")
Merb::Cache.register(:mintcache, :path => (path / "mintcache_store"), :class_name => "MintcachedStore")

Expand Down
84 changes: 74 additions & 10 deletions lib/merb-cache/controller.rb
Expand Up @@ -2,17 +2,51 @@ module Merb
module Cache
module ControllerClassMethods

def cache_action(action)
raise NotImplmented
# Merb::Cache::Store.put(Merb::Cache.key_for(action)) unless cached_action?(action)
def cache_action(action, options = {}, &block)
# Get the filter options
opts = {}
[:exclude, :only, :with].each{ |k| r = options.delete(k); opts.merge!(r) if r}

# setup the options for the before_filter
opts.delete(:exclude)
opts[:only] = action

_add_action_cache(action, options, &block)

# Setup a before filter
b = Proc.new do
_fetch_action_cache(options)
end
a = Proc.new do
_set_action_cache(options)
end
before nil, opts, &b
after nil, opts, &a
end

# Pure convenience
def cache_actions(actions)
raise NotImplmented
# actions.each do |action|
# action.expire_action(action)
# end
def cache_actions(*args, &block)
options = args.pop if Hash === args.last
options ||= {}
opts = {}
[:exclude, :only, :with].each{ |k| r = options.delete(k); opts.merge!(r) if r}

if args.empty?
unless opts[:exclude]
args = self.callable_actions
opts[:only] = args.flatten
end
end

# Setup a before filter and after filter
b = Proc.new do
_fetch_action_cache(options)
end
a = Proc.new do
_set_action_cache(options)
end
before nil, opts, &b
after nil, opts, &a
end

def cached_action?(action)
Expand All @@ -32,7 +66,16 @@ def expire_actions(actions)
# end
end

# The default path for the controller
# A place to store the cached actions
def _action_caches
@_action_caches ||= Hash.new{|h,k| h[k] = {}}
end

private
def _add_action_cache(action, options, &proc)
self._action_caches[action][:options] = options
self._action_caches[action][:proc] = proc
end
end

module ControllerInstanceMethods
Expand Down Expand Up @@ -60,7 +103,28 @@ def cached?(key, store = :default)
def expire!(key, store = :default)
Merb::Cache[store].expire!(key)
end


def expire_action
raise NotImplmented
end

def expire_actions
raise NotImplmented
end

def cached_action?
raise NotImplmented
end

private
def _fetch_action_cache(opts = {})

end

def _set_action_cache(opts = {})

end

end
end
end
Expand Down
116 changes: 101 additions & 15 deletions spec/controller_spec.rb
Expand Up @@ -2,14 +2,110 @@

describe Merb::Cache do
describe CacheSpecController, "controller class methods" do
it "should respond to cache_action"
it "should respond to cache_actions"

before(:each) do
Object.class_eval{ remove_const("CacheSpecControllerActionsController") if defined?(CacheSpecControllerActionsController)}
Object.class_eval("class CacheSpecControllerActionsController < Merb::Controller; def show; 'In Show'; end; end")
@klass = CacheSpecControllerActionsController
@controller = @klass.new({})
end

it{ @klass.should respond_to(:cache_action) }

it "should setup a cacheing options in the classes cache store" do
@klass.class_eval <<-Ruby
cache_action :show
Ruby
action_caches = @klass.send(:_action_caches)
action_caches.should be_a_kind_of(Hash)
action_caches[:show].should_not be_nil
action_caches[:show][:proc].should be_nil
action_caches[:show][:options].should be_empty
end

it "should add the proc to the action cache store" do
@klass.class_eval <<-Ruby
cache_action :show do
"Stuff"
end
Ruby
ac = @klass.send(:_action_caches)
ac.should be_a_kind_of(Hash)
ac[:show][:proc].call.should =="Stuff"
end

it "should add a before filter for the given action" do
@klass._before_filters.should be_empty
@klass.class_eval <<-Ruby
cache_action :show
Ruby
@klass._before_filters.any?{|filter, opts| opts == {:only => ["show"]} }.should be_true
end

it "should call _fetch_action_cache in the before_filter" do
@klass.send(:cache_action, :show)
@controller = @klass.new({})
@controller.should_receive(:_fetch_action_cache)
@controller.should_receive(:_set_action_cache)
@controller._dispatch("show")
@controller.body.should == "In Show"
end

it{ @klass.should respond_to(:cache_actions)}

it "should add all the actions to via cache_action with the options" do
pending
@klass.should_receive(:cache_setup).twice
@klass.class_eval <<-Ruby
cache_actions :show, :index, :expire_in => 100 do
"Stuff"
end
Ruby
ac = @klass.send(:_action_caches)
ac.should be_a_kind_of(Hash)
ac[:show][:options].should == {:expire_in => 100}
ac[:index][:options].should == {:expire_in => 100}
ac[:show][:proc].call.should == "Stuff"
end

describe "_fetch_action_cache" do
it "should implement a _fetch_action_cache private method" do
@klass.private_instance_methods.should include("_fetch_action_cache")
end
end

describe "_set_action_cache" do
it "should implement a _set_action_cache private method" do
@klass.private_instance_methods.should include("_set_action_cache")
end
end

end

describe CacheSpecController, "controller instance methods" do
it "should respond to expire_action"
it "should respond to expire_actions"
it "should respond to cached_action?"

before(:all) do
Merb::Cache.setup_default
@controller = CacheSpecController.new({})

@route_params = {:controller => "My::Controller", :action => "show", :id => 4}
@get_params = {:search => "some search params"}
@controller.stub!(:params).and_return(@route_params.merge(@get_params))
end

it{ @controller.should respond_to(:expire_action)}

it{ @controller.should respond_to(:expire_actions)}

it{ @controller.should respond_to(:cached_action?)}

it "should call the call the base key path on the controller class" do
pending
@controller.class.should
@controller.cache_key.should_not be_nil
@controller.cache_key
end

it "should be cached"
it "should not be cached"
end
Expand Down Expand Up @@ -96,14 +192,4 @@

end

describe Merb::Cache::ControllerClassMethods do

before(:all) do
Merb::Cache.setup_default
@controller = CacheSpecController.new({})
end



end
end

0 comments on commit 036e206

Please sign in to comment.