mirror of
https://github.com/drapergem/draper
synced 2023-03-27 23:21:17 -04:00
Refactoring #method_missing to define a previously missing method in the Decorator when calling it for the first time.
This commit is contained in:
parent
78b200a84f
commit
ebe30511b7
6 changed files with 147 additions and 1 deletions
|
@ -157,7 +157,10 @@ module Draper
|
|||
def method_missing(method, *args, &block)
|
||||
if allow?(method)
|
||||
begin
|
||||
model.send(method, *args, &block)
|
||||
self.class.send :define_method, method do |*args, &block|
|
||||
model.send(method, *args, &block)
|
||||
end
|
||||
self.send(method, *args, &block)
|
||||
rescue NoMethodError
|
||||
super
|
||||
end
|
||||
|
|
4
performance/active_record.rb
Normal file
4
performance/active_record.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
module ActiveRecord
|
||||
class Base
|
||||
end
|
||||
end
|
55
performance/bechmark.rb
Normal file
55
performance/bechmark.rb
Normal file
|
@ -0,0 +1,55 @@
|
|||
require 'rubygems'
|
||||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
||||
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
||||
Bundler.require(:default) if defined?(Bundler)
|
||||
|
||||
require "benchmark"
|
||||
require "draper"
|
||||
require "./performance/models"
|
||||
require "./performance/decorators"
|
||||
|
||||
Benchmark.bm do |bm|
|
||||
puts "\n[ Exclusivelly using #method_missing for model delegation ]"
|
||||
[ 1_000, 10_000, 100_000 ].each do |i|
|
||||
puts "\n[ #{i} ]"
|
||||
bm.report("#new ") do
|
||||
i.times do |n|
|
||||
ProductDecorator.decorate(Product.new)
|
||||
end
|
||||
end
|
||||
|
||||
bm.report("#hello_world ") do
|
||||
i.times do |n|
|
||||
ProductDecorator.decorate(Product.new).hello_world
|
||||
end
|
||||
end
|
||||
|
||||
bm.report("#sample_class_method ") do
|
||||
i.times do |n|
|
||||
ProductDecorator.decorate(Product.new).class.sample_class_method
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
puts "\n[ Defining methods on method_missing first hit ]"
|
||||
[ 1_000, 10_000, 100_000 ].each do |i|
|
||||
puts "\n[ #{i} ]"
|
||||
bm.report("#new ") do
|
||||
i.times do |n|
|
||||
FastProductDecorator.decorate(FastProduct.new)
|
||||
end
|
||||
end
|
||||
|
||||
bm.report("#hello_world ") do
|
||||
i.times do |n|
|
||||
FastProductDecorator.decorate(FastProduct.new).hello_world
|
||||
end
|
||||
end
|
||||
|
||||
bm.report("#sample_class_method ") do
|
||||
i.times do |n|
|
||||
FastProductDecorator.decorate(FastProduct.new).class.sample_class_method
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
47
performance/decorators.rb
Normal file
47
performance/decorators.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
require "./performance/models"
|
||||
class ProductDecorator < Draper::Base
|
||||
decorates :product
|
||||
|
||||
def awesome_title
|
||||
"Awesome Title"
|
||||
end
|
||||
|
||||
# Original #method_missing
|
||||
def method_missing(method, *args, &block)
|
||||
if allow?(method)
|
||||
begin
|
||||
model.send(method, *args, &block)
|
||||
rescue NoMethodError
|
||||
super
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class FastProductDecorator < Draper::Base
|
||||
decorates :product
|
||||
|
||||
def awesome_title
|
||||
"Awesome Title"
|
||||
end
|
||||
|
||||
# Modified #method_missing
|
||||
def method_missing(method, *args, &block)
|
||||
if allow?(method)
|
||||
begin
|
||||
self.class.send :define_method, method do |*args, &block|
|
||||
model.send(method, *args, &block)
|
||||
end
|
||||
self.send(method, *args, &block)
|
||||
rescue NoMethodError
|
||||
super
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
20
performance/models.rb
Normal file
20
performance/models.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
require "./performance/active_record"
|
||||
class Product < ActiveRecord::Base
|
||||
def self.sample_class_method
|
||||
"sample class method"
|
||||
end
|
||||
|
||||
def hello_world
|
||||
"Hello, World"
|
||||
end
|
||||
end
|
||||
|
||||
class FastProduct < ActiveRecord::Base
|
||||
def self.sample_class_method
|
||||
"sample class method"
|
||||
end
|
||||
|
||||
def hello_world
|
||||
"Hello, World"
|
||||
end
|
||||
end
|
|
@ -382,4 +382,21 @@ describe Draper::Base do
|
|||
subject.kind_of?(source.class).should == true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#method_missing" do
|
||||
context "when #hello_world is called for the first time" do
|
||||
it "hits method missing" do
|
||||
subject.should_receive(:method_missing)
|
||||
subject.hello_world
|
||||
end
|
||||
end
|
||||
|
||||
context "when #hello_world is called again" do
|
||||
before { subject.hello_world }
|
||||
it "proxies method directly after first hit" do
|
||||
subject.should_not_receive(:method_missing)
|
||||
subject.hello_world
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue