commit 018b25811118c3bb95162324b3feae3a1e2b9923 Author: Yehuda Katz Date: Sat Jul 2 20:51:23 2011 -0700 Get method_missing working again. I'm not sure how it was working before, but the tests didn't pass. # Altered a bit to work with this version. diff --git a/lib/thor/task.rb b/lib/thor/task.rb index 8dcff53..f94d5b6 100644 --- a/lib/thor/task.rb +++ b/lib/thor/task.rb @@ -18,8 +18,15 @@ class Thor # By default, a task invokes a method in the thor class. You can change this # implementation to create custom tasks. def run(instance, args=[]) - public_method?(instance) ? - instance.send(name, *args) : instance.class.handle_no_task_error(name) + if private_method?(instance) + instance.class.handle_no_task_error(name) + elsif public_method?(instance) + instance.send(name, *args) + elsif local_method?(instance, :method_missing) + instance.send(:method_missing, name.to_sym, *args) + else + instance.class.handle_no_task_error(name) + end rescue ArgumentError => e handle_argument_error?(instance, e, caller) ? instance.class.handle_argument_error(self, e) : (raise e) @@ -71,6 +78,15 @@ class Thor (collection & [name.to_s, name.to_sym]).empty? end + def private_method?(instance) + !(instance.private_methods & [name.to_s, name.to_sym]).empty? + end + + def local_method?(instance, name) + methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false) + !(methods & [name.to_s, name.to_sym]).empty? + end + def sans_backtrace(backtrace, caller) #:nodoc: saned = backtrace.reject { |frame| frame =~ FILE_REGEXP } saned -= caller @@ -105,11 +121,7 @@ class Thor def run(instance, args=[]) if (instance.methods & [name.to_s, name.to_sym]).empty? - if ((instance.protected_methods + instance.public_methods) & ([:method_missing, "method_missing"])).empty? - super - else - instance.send(:method_missing, name.to_sym, *args) - end + super else instance.class.handle_no_task_error(name) end diff --git a/spec/task_spec.rb b/spec/task_spec.rb index 1c7ea7c..3372de1 100644 --- a/spec/task_spec.rb +++ b/spec/task_spec.rb @@ -11,21 +11,18 @@ describe Thor::Task do describe "#formatted_usage" do it "includes namespace within usage" do - Object.stub!(:namespace).and_return("foo") - Object.stub!(:arguments).and_return([]) - task(:bar => :required).formatted_usage(Object).should == "foo:can_has --bar=BAR" + object = Struct.new(:namespace, :arguments).new("foo", []) + task(:bar => :required).formatted_usage(object).should == "foo:can_has --bar=BAR" end it "removes default from namespace" do - Object.stub!(:namespace).and_return("default:foo") - Object.stub!(:arguments).and_return([]) - task(:bar => :required).formatted_usage(Object).should == ":foo:can_has --bar=BAR" + object = Struct.new(:namespace, :arguments).new("default:foo", []) + task(:bar => :required).formatted_usage(object).should == ":foo:can_has --bar=BAR" end it "injects arguments into usage" do - Object.stub!(:namespace).and_return("foo") - Object.stub!(:arguments).and_return([ Thor::Argument.new(:bar, nil, true, :string) ]) - task(:foo => :required).formatted_usage(Object).should == "foo:can_has BAR --foo=FOO" + object = Struct.new(:namespace, :arguments).new("foo", [Thor::Argument.new(:bar, nil, true, :string)]) + task(:foo => :required).formatted_usage(object).should == "foo:can_has BAR --foo=FOO" end end @@ -55,15 +52,23 @@ describe Thor::Task do describe "#run" do it "runs a task by calling a method in the given instance" do mock = mock() - mock.should_receive(:send).with("can_has", 1, 2, 3) - task.run(mock, [1, 2, 3]) + mock.should_receive(:can_has).and_return {|*args| args } + task.run(mock, [1, 2, 3]).should == [1, 2, 3] end it "raises an error if the method to be invoked is private" do - mock = mock() - mock.should_receive(:private_methods).and_return(['can_has']) - mock.class.should_receive(:handle_no_task_error).with("can_has") - task.run(mock) + klass = Class.new do + def self.handle_no_task_error(name) + name + end + + private + def can_has + "fail" + end + end + + task.run(klass.new).should == "can_has" end end end