Skip to content

Commit

Permalink
Extended callbacks to allow a hook to be defined with a block, and th…
Browse files Browse the repository at this point in the history
…en content can be appended or prepended, or replace or remove the block entirely. Is fully backwards compatible with existing view hooks
  • Loading branch information
ndbroadbent committed Sep 24, 2010
1 parent a897de7 commit 63ac207
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 6 deletions.
61 changes: 55 additions & 6 deletions lib/fat_free_crm/callback.rb
Expand Up @@ -38,19 +38,44 @@ def self.responder(method)
# - array with multiple items returned by the hook chain.
#--------------------------------------------------------------------------
def self.hook(method, caller, context = {})
responder(method).inject([]) do |response, m|
response << m.send(method, caller, context)
responder(method).inject(Hash.new([])) do |response, m|
response[m.class.positions[method]] += [m.send(method, caller, context)]
response
end
end

#--------------------------------------------------------------------------
class Base
include Singleton

def self.inherited(child)
FatFreeCRM::Callback.add(child)
# Positioning hash to determine where content is placed.
child.class_eval do
@positions = Hash.new(:after)
end
super
end

class << self
attr_accessor :positions

def insert_before(hook, &block)
define_method hook, &block
@positions[hook] = :before
end
def insert_after(hook, &block)
define_method hook, &block
@positions[hook] = :after
end
def replace(hook, &block)
define_method hook, &block
@positions[hook] = :replace
end
def remove(hook)
define_method hook, Proc.new{""}
@positions[hook] = :replace
end
end

end # class Base

Expand All @@ -59,9 +84,33 @@ def self.inherited(child)
# data otherwise.
#--------------------------------------------------------------------------
module Helper
def hook(method, caller, context = {})
data = FatFreeCRM::Callback.hook(method, caller, context)
caller.class.to_s.start_with?("ActionView") ? data.join : data
def hook(method, caller, context = {}, &block)
is_view_hook = caller.class.to_s.start_with?("ActionView")

# If a block was given, hooks can choose to replace, append or prepend view content.
if block and is_view_hook
hook_hash = FatFreeCRM::Callback.hook(method, caller, context)
# Add content to the view with the following logic:
# -- before
# -- replace || original block
# -- after
view_data = ""
hook_hash[:before].each{|data| view_data << data }
# Only render the original view block if there are no :replace operations
if hook_hash[:replace].empty?
view_data << capture(&block)
else
hook_hash[:replace].each{|data| view_data << data }
end
hook_hash[:after].each{|data| view_data << data }
view_data

# Else, if no was block given.. (for backwards compatibility with existing hooks)
else
# All legacy hooks will have data stored in the :after key.
data = FatFreeCRM::Callback.hook(method, caller, context)[:after]
is_view_hook ? data.join : data
end
end
end # module Helper

Expand Down
51 changes: 51 additions & 0 deletions spec/lib/fat_free_crm/callback_spec.rb
@@ -0,0 +1,51 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')

class TestCallback < FatFreeCRM::Callback::Base
insert_before :test_before do |view, context|
"BEFORE-"
end
insert_after :test_after do |view, context|
"-AFTER"
end
replace :test_replace do |view, context|
"REPLACE"
end
remove :test_remove

def test_legacy(view, context={})
"LEGACY"
end
end

include FatFreeCRM::Callback::Helper
include ActionView::Helpers::CaptureHelper

def test_hook(position)
Haml::Engine.new(%Q^
= hook("test_#{position}".to_sym, ActionView::Base.new) do
BLOCK^).render.gsub("\n",'')
end

describe FatFreeCRM::Callback do
it "should insert content before the block" do
test_hook(:before).should == "BEFORE-BLOCK"
end

it "should insert content after the block" do
test_hook(:after).should == "BLOCK-AFTER"
end

it "should replace the content of the block" do
test_hook(:replace).should == "REPLACE"
end

it "should remove the block" do
test_hook(:remove).should == ""
end

it "should still work for legacy hooks" do
Haml::Engine.new(%Q^
= hook(:test_legacy, ActionView::Base.new)
^).render.gsub("\n",'').should == "LEGACY"
end
end

0 comments on commit 63ac207

Please sign in to comment.