Rename `source_class` to `object_class`

This commit is contained in:
Andrew Haines 2013-04-30 19:37:05 +01:00
parent d67a53a39f
commit ae13cb58d5
4 changed files with 67 additions and 52 deletions

View File

@ -26,7 +26,7 @@ module Draper
def method_missing(method, *args, &block)
return super unless delegatable?(method)
source_class.send(method, *args, &block)
object_class.send(method, *args, &block)
end
# Checks if the decorator responds to a class method, or is able to proxy
@ -37,7 +37,7 @@ module Draper
# @private
def delegatable?(method)
source_class? && source_class.respond_to?(method)
object_class? && object_class.respond_to?(method)
end
# @private

View File

@ -39,7 +39,7 @@ module Draper
end
# Automatically delegates instance methods to the source object. Class
# methods will be delegated to the {source_class}, if it is set.
# methods will be delegated to the {object_class}, if it is set.
#
# @return [void]
def self.delegate_all
@ -52,11 +52,11 @@ module Draper
# source (including when using {decorates_finders}), and the source class
# cannot be inferred from the decorator class (e.g. `ProductDecorator`
# maps to `Product`).
# @param [String, Symbol, Class] source_class
# @param [String, Symbol, Class] object_class
# source class (or class name) that corresponds to this decorator.
# @return [void]
def self.decorates(source_class)
@source_class = source_class.to_s.camelize.constantize
def self.decorates(object_class)
@object_class = object_class.to_s.camelize.constantize
end
# Returns the source class corresponding to the decorator class, as set by
@ -64,22 +64,27 @@ module Draper
# `ProductDecorator` maps to `Product`).
#
# @return [Class] the source class that corresponds to this decorator.
def self.source_class
@source_class ||= inferred_source_class
def self.object_class
@object_class ||= inferred_object_class
end
# Checks whether this decorator class has a corresponding {source_class}.
def self.source_class?
source_class
# Checks whether this decorator class has a corresponding {object_class}.
def self.object_class?
object_class
rescue Draper::UninferrableSourceError
false
end
class << self # TODO deprecate this
alias_method :source_class, :object_class
alias_method :source_class?, :object_class?
end
# Automatically decorates ActiveRecord finder methods, so that you can use
# `ProductDecorator.find(id)` instead of
# `ProductDecorator.decorate(Product.find(id))`.
#
# Finder methods are applied to the {source_class}.
# Finder methods are applied to the {object_class}.
#
# @return [void]
def self.decorates_finders
@ -201,7 +206,7 @@ module Draper
delegate :to_param, :to_partial_path
# ActiveModel compatibility
singleton_class.delegate :model_name, to: :source_class
singleton_class.delegate :model_name, to: :object_class
# @return [Class] the class created by {decorate_collection}.
def self.collection_decorator_class
@ -214,13 +219,13 @@ module Draper
private
def self.source_name
def self.object_class_name
raise NameError if name.nil? || name.demodulize !~ /.+Decorator$/
name.chomp("Decorator")
end
def self.inferred_source_class
name = source_name
def self.inferred_object_class
name = object_class_name
name.constantize
rescue NameError => error
raise if name && !error.missing_name?(name)
@ -228,8 +233,8 @@ module Draper
end
def self.collection_decorator_name
plural = source_name.pluralize
raise NameError if plural == source_name
plural = object_class_name.pluralize
raise NameError if plural == object_class_name
"#{plural}Decorator"
end

View File

@ -5,26 +5,26 @@ module Draper
module Finders
def find(id, options = {})
decorate(source_class.find(id), options)
decorate(object_class.find(id), options)
end
def all(options = {})
decorate_collection(source_class.all, options)
decorate_collection(object_class.all, options)
end
def first(options = {})
decorate(source_class.first, options)
decorate(object_class.first, options)
end
def last(options = {})
decorate(source_class.last, options)
decorate(object_class.last, options)
end
# Decorates dynamic finder methods (`find_all_by_` and friends).
def method_missing(method, *args, &block)
return super unless method =~ /^find_(all_|last_|or_(initialize_|create_))?by_/
result = source_class.send(method, *args, &block)
result = object_class.send(method, *args, &block)
options = args.extract_options!
if method =~ /^find_all/

View File

@ -157,74 +157,84 @@ module Draper
describe ".decorates" do
protect_class Decorator
it "sets .source_class with a symbol" do
it "sets .object_class with a symbol" do
Decorator.decorates :product
expect(Decorator.source_class).to be Product
expect(Decorator.object_class).to be Product
end
it "sets .source_class with a string" do
it "sets .object_class with a string" do
Decorator.decorates "product"
expect(Decorator.source_class).to be Product
expect(Decorator.object_class).to be Product
end
it "sets .source_class with a class" do
it "sets .object_class with a class" do
Decorator.decorates Product
expect(Decorator.source_class).to be Product
expect(Decorator.object_class).to be Product
end
end
describe ".source_class" do
describe ".object_class" do
protect_class ProductDecorator
protect_class Namespaced::ProductDecorator
context "when not set by .decorates" do
it "raises an UninferrableSourceError for a so-named 'Decorator'" do
expect{Decorator.source_class}.to raise_error UninferrableSourceError
expect{Decorator.object_class}.to raise_error UninferrableSourceError
end
it "raises an UninferrableSourceError for anonymous decorators" do
expect{Class.new(Decorator).source_class}.to raise_error UninferrableSourceError
expect{Class.new(Decorator).object_class}.to raise_error UninferrableSourceError
end
it "raises an UninferrableSourceError for a decorator without a model" do
expect{OtherDecorator.source_class}.to raise_error UninferrableSourceError
expect{OtherDecorator.object_class}.to raise_error UninferrableSourceError
end
it "raises an UninferrableSourceError for other naming conventions" do
expect{ProductPresenter.source_class}.to raise_error UninferrableSourceError
expect{ProductPresenter.object_class}.to raise_error UninferrableSourceError
end
it "infers the source for '<Model>Decorator'" do
expect(ProductDecorator.source_class).to be Product
expect(ProductDecorator.object_class).to be Product
end
it "infers namespaced sources" do
expect(Namespaced::ProductDecorator.source_class).to be Namespaced::Product
expect(Namespaced::ProductDecorator.object_class).to be Namespaced::Product
end
context "when an unrelated NameError is thrown" do
it "re-raises that error" do
String.any_instance.stub(:constantize).and_return{SomethingThatDoesntExist}
expect{ProductDecorator.source_class}.to raise_error NameError, /SomethingThatDoesntExist/
expect{ProductDecorator.object_class}.to raise_error NameError, /SomethingThatDoesntExist/
end
end
end
it "is aliased to .source_class" do
expect(ProductDecorator.source_class).to be Product
end
end
describe ".source_class?" do
it "returns truthy when .source_class is set" do
Decorator.stub(:source_class).and_return(Model)
describe ".object_class?" do
it "returns truthy when .object_class is set" do
Decorator.stub(:object_class).and_return(Model)
expect(Decorator.source_class?).to be_true
expect(Decorator.object_class?).to be_true
end
it "returns false when .source_class is not inferrable" do
Decorator.stub(:source_class).and_raise(UninferrableSourceError.new(Decorator))
it "returns false when .object_class is not inferrable" do
Decorator.stub(:object_class).and_raise(UninferrableSourceError.new(Decorator))
expect(Decorator.source_class?).to be_false
expect(Decorator.object_class?).to be_false
end
it "is aliased to .source_class?" do
Decorator.stub(:object_class).and_return(Model)
expect(Decorator.source_class?).to be_true
end
end
@ -402,7 +412,7 @@ module Draper
describe ".model_name" do
it "delegates to the source class" do
Decorator.stub source_class: double(model_name: :delegated)
Decorator.stub object_class: double(model_name: :delegated)
expect(Decorator.model_name).to be :delegated
end
@ -540,15 +550,15 @@ module Draper
context "with a source class" do
it "delegates methods that exist on the source class" do
source_class = Class.new
source_class.stub hello_world: :delegated
Decorator.stub source_class: source_class
object_class = Class.new
object_class.stub hello_world: :delegated
Decorator.stub object_class: object_class
expect(Decorator.hello_world).to be :delegated
end
it "does not delegate methods that do not exist on the source class" do
Decorator.stub source_class: Class.new
Decorator.stub object_class: Class.new
expect{Decorator.hello_world}.to raise_error NoMethodError
end
@ -602,13 +612,13 @@ module Draper
context "with a source class" do
it "returns true for its own class methods" do
Decorator.class_eval{def self.hello_world; end}
Decorator.stub source_class: Class.new
Decorator.stub object_class: Class.new
expect(Decorator).to respond_to :hello_world
end
it "returns true for the source's class methods" do
Decorator.stub source_class: double(hello_world: :delegated)
Decorator.stub object_class: double(hello_world: :delegated)
expect(Decorator).to respond_to :hello_world
end
@ -627,7 +637,7 @@ module Draper
describe ".respond_to_missing?" do
it "allows .method to be called on delegated class methods" do
Decorator.stub source_class: double(hello_world: :delegated)
Decorator.stub object_class: double(hello_world: :delegated)
expect { Decorator.method(:hello_world) }.not_to raise_error NameError
expect(Decorator.method(:hello_world)).not_to be_nil