Skip to content

Commit

Permalink
Provide support for class methods. Reintroduce the decorates class me…
Browse files Browse the repository at this point in the history
…thod, which may be used to hint at which class to delegate class methods to.
  • Loading branch information
cheald authored and haines committed Dec 2, 2012
1 parent 41ca1a3 commit 731995a
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 22 deletions.
28 changes: 27 additions & 1 deletion lib/draper/decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,33 @@ class << self
# @option options [Class, Symbol] :for The model class to find
def self.has_finders(options = {})
extend Draper::Finders
self.finder_class = options[:for] || name.chomp("Decorator")
if klass = options.delete(:for)
decorates klass
end
end

class << self
# Specify the class that this class decorates.
#
# @param [String, Symbol, Class] Class or name of class to decorate.
def decorates(klass)
@source_class = klass.kind_of?(Class) ? klass : klass.to_s.classify.constantize
end

# Provides access to the class that this decorator decorates
#
# @return [Class]: The class wrapped by the decorator
def source_class
@source_class ||= name.chomp("Decorator").constantize
end

def method_missing(method, *args, &block)
source_class.send(method, *args, &block)
end

def respond_to?(method, include_private = false)
super || source_class.respond_to?(method)
end
end

# Typically called within a decorator definition, this method causes
Expand Down
20 changes: 5 additions & 15 deletions lib/draper/finders.rb
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
module Draper
module Finders

attr_reader :finder_class
def finder_class=(klass)
@finder_class = klass.to_s.camelize.constantize
end

def find(id, options = {})
decorate(finder_class.find(id), options)
decorate(source_class.find(id), options)
end

def all(options = {})
decorate_collection(finder_class.all, options)
decorate_collection(source_class.all, options)
end

def first(options = {})
decorate(finder_class.first, options)
decorate(source_class.first, options)
end

def last(options = {})
decorate(finder_class.last, options)
decorate(source_class.last, options)
end

def method_missing(method, *args, &block)
result = finder_class.send(method, *args, &block)
result = source_class.send(method, *args, &block)
options = args.extract_options!

case method.to_s
Expand All @@ -35,10 +30,5 @@ def method_missing(method, *args, &block)
result
end
end

def respond_to?(method, include_private = false)
super || finder_class.respond_to?(method)
end

end
end
26 changes: 20 additions & 6 deletions spec/draper/decorator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -450,12 +450,12 @@

context "with no options" do
it "infers the finder class" do
ProductDecorator.finder_class.should be Product
ProductDecorator.source_class.should be Product
end

context "for a namespaced model" do
it "infers the finder class" do
Namespace::ProductDecorator.finder_class.should be Namespace::Product
Namespace::ProductDecorator.source_class.should be Namespace::Product
end
end
end
Expand All @@ -466,21 +466,21 @@
context "with a symbol" do
it "sets the finder class" do
subject.has_finders for: :product
subject.finder_class.should be Product
subject.source_class.should be Product
end
end

context "with a string" do
it "sets the finder class" do
subject.has_finders for: "some_thing"
subject.finder_class.should be SomeThing
subject.source_class.should be SomeThing
end
end

context "with a class" do
it "sets the finder_class" do
it "sets the source_class" do
subject.has_finders for: Namespace::Product
subject.finder_class.should be Namespace::Product
subject.source_class.should be Namespace::Product
end
end
end
Expand All @@ -494,4 +494,18 @@
end
end

context "class methods" do
it "passes through to the underlying wrapped class" do
ProductDecorator.sample_class_method.should == Product.sample_class_method
end

context "when told to decorate a different class " do
subject { decorator_class }
before { decorator_class.decorates :product }

it "should manually set the class to pass methods to" do
subject.sample_class_method.should == Product.sample_class_method
end
end
end
end
4 changes: 4 additions & 0 deletions spec/dummy/app/decorators/post_decorator.rb
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ def url_with_model
def url_with_id
h.post_url(id: id)
end

def link
h.link_to id.to_s, self
end
end
3 changes: 3 additions & 0 deletions spec/dummy/spec/decorators/post_decorator_spec.rb
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@
subject.url_with_id.should == "http://www.example.com/en/posts/#{source.id}"
end

it "can be passed implicitly to url_for" do
subject.link.should == "<a href=\"/en/posts/#{source.id}\">#{source.id}</a>"
end
end

0 comments on commit 731995a

Please sign in to comment.