Skip to content
This repository has been archived by the owner on Nov 2, 2021. It is now read-only.

Commit

Permalink
Revert conditions. YAGNI.
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed Jun 20, 2009
1 parent bb7a372 commit 2d9f3e3
Show file tree
Hide file tree
Showing 7 changed files with 7 additions and 238 deletions.
2 changes: 1 addition & 1 deletion lib/thor.rb
Expand Up @@ -198,7 +198,7 @@ def valid_task?(meth) #:nodoc:
end end


def create_task(meth) #:nodoc: def create_task(meth) #:nodoc:
tasks[meth.to_s] = Thor::Task.new(meth, @desc, @usage, method_options, nil) tasks[meth.to_s] = Thor::Task.new(meth, @desc, @usage, method_options)
@usage, @desc, @method_options = nil @usage, @desc, @method_options = nil
end end


Expand Down
68 changes: 1 addition & 67 deletions lib/thor/group.rb
Expand Up @@ -22,71 +22,6 @@ def desc(description=nil)
end end
end end


# Sets the condition for some task to be executed in the class level. Why
# is this important? Setting the conditions in the class level allows to
# an inherited class change the conditions and customize the Thor::Group as
# it wishes.
#
# The conditions given are retrieved from the options hash. Let's suppose
# that a task is only executed if --test-framework is rspec. You could do
# this:
#
# class_option :test_framework, :type => :string
#
# conditions :test_framework => :rspec
# def create_rspec_files
# # magic
# end
#
# Later someone creates a framework on top of rspec and need rspec files to
# generated as well. He could then change the conditions:
#
# conditions :test_framework => [ :rspec, :remarkable ], :for => :create_rspec_files
#
# He could also use remove_conditions and remove previous set conditions:
#
# remove_conditions :test_framework, :for => :create_rspec_files
#
# Conditions only work with the class option to be comparead to is a boolean,
# string or numeric (no array or hash comparisions).
#
# ==== Parameters
# conditions<Hash>:: the conditions for the task. The key is the option name
# and the value is the condition to be checked. If the
# condition is an array, it checkes if the current value
# is included in the array. If a regexp, checks if the
# value matches, all other values are simply compared (==).
#
def conditions(conditions=nil)
subject = if conditions && conditions[:for]
find_and_refresh_task(conditions.delete(:for)).conditions
else
@conditions ||= {}
end

subject.merge!(conditions) if conditions
subject
end

# Remove a previous specified condition. Check <tt>conditions</tt> above for
# a complete example.
#
# ==== Parameters
# conditions<Array>:: An array of conditions to be removed.
# for<Hash>:: A hash with :for as key indicating the task to remove the conditions from.
#
# ==== Examples
#
# remove_conditions :test_framework, :orm, :for => :create_app_skeleton
#
def remove_conditions(*conditions)
subject = find_and_refresh_task(conditions.pop[:for]).conditions
conditions.each do |condition|
subject.delete(condition)
end
subject
end

# Start in Thor::Group works differently. It invokes all tasks inside the # Start in Thor::Group works differently. It invokes all tasks inside the
# class and does not have to parse task options. # class and does not have to parse task options.
# #
Expand Down Expand Up @@ -140,8 +75,7 @@ def valid_task?(meth) #:nodoc:
end end


def create_task(meth) #:nodoc: def create_task(meth) #:nodoc:
tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil, @conditions) tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil)
@conditions = nil
end end
end end


Expand Down
46 changes: 5 additions & 41 deletions lib/thor/task.rb
@@ -1,5 +1,5 @@
class Thor class Thor
class Task < Struct.new(:name, :description, :usage, :options, :conditions) class Task < Struct.new(:name, :description, :usage, :options)


# Creates a dynamic task. Dynamic tasks are created on demand to allow method # Creates a dynamic task. Dynamic tasks are created on demand to allow method
# missing calls (since a method missing does not have a task object for it). # missing calls (since a method missing does not have a task object for it).
Expand All @@ -8,24 +8,23 @@ def self.dynamic(name)
new(name, "A dynamically-generated task", name.to_s) new(name, "A dynamically-generated task", name.to_s)
end end


def initialize(name, description, usage, options=nil, conditions=nil) def initialize(name, description, usage, options=nil)
super(name.to_s, description, usage, options || {}, conditions || {}) super(name.to_s, description, usage, options || {})
end end


# Dup the options hash on clone. # Dup the options hash on clone.
# #
def initialize_copy(other) def initialize_copy(other)
super(other) super(other)
self.options = other.options.dup if other.options self.options = other.options.dup if other.options
self.conditions = other.conditions.dup if other.conditions
end end


# By default, a task invokes a method in the thor class. You can change this # By default, a task invokes a method in the thor class. You can change this
# implementation to create custom tasks. # implementation to create custom tasks.
# #
def run(instance, args=[]) def run(instance, args=[])
raise UndefinedTaskError, "the '#{name}' task of #{instance.class} is private" unless public_method?(instance) raise UndefinedTaskError, "the '#{name}' task of #{instance.class} is private" unless public_method?(instance)
instance.send(name, *args) if valid_conditions?(instance) instance.send(name, *args)
rescue ArgumentError => e rescue ArgumentError => e
backtrace = sans_backtrace(e.backtrace, caller) backtrace = sans_backtrace(e.backtrace, caller)


Expand Down Expand Up @@ -91,28 +90,6 @@ def public_method?(instance)
!(collection).include?(name.to_s) && !(collection).include?(name.to_sym) # For Ruby 1.9 !(collection).include?(name.to_s) && !(collection).include?(name.to_sym) # For Ruby 1.9
end end


# Check if the task conditions are met before invoking.
#
def valid_conditions?(instance)
return true if conditions.empty?

conditions.each do |key, expected|
actual = stringify!(instance.options[key])
expected = stringify!(expected)

return false if case expected
when Regexp
actual !~ expected
when Array
!expected.include?(actual)
else
actual != expected
end
end

true
end

# Clean everything that comes from the Thor gempath and remove the caller. # Clean everything that comes from the Thor gempath and remove the caller.
# #
def sans_backtrace(backtrace, caller) def sans_backtrace(backtrace, caller)
Expand All @@ -121,18 +98,5 @@ def sans_backtrace(backtrace, caller)
saned -= caller saned -= caller
end end


# Receives an object and convert any symbol to string.
#
def stringify!(duck)
case duck
when Array
duck.map!{ |i| i.is_a?(Symbol) ? i.to_s : i }
when Symbol
duck.to_s
else
duck
end
end

end end
end end
29 changes: 0 additions & 29 deletions spec/fixtures/conditions.thor

This file was deleted.

19 changes: 0 additions & 19 deletions spec/group_spec.rb
Expand Up @@ -77,23 +77,4 @@
content.must_not =~ /Options/ content.must_not =~ /Options/
end end
end end

describe "#conditions" do
it "invoke only tasks where conditions met" do
Conditional.start([]).must == [nil, nil, nil, nil]
Conditional.start(["--test-framework", "rspec"]).must == [1, 2, nil, nil]
Conditional.start(["--test-framework", "remarkable"]).must == [nil, 2, 3, nil]
Conditional.start(["--with-dispatchers"]).must == [nil, nil, nil, 4]
end

it "when supplied with :for changes the conditions for a previous task" do
Simplified.start(["--test-framework", "remarkable"]).must == [1, 2, 3, 4]
end
end

describe "#remove_conditions" do
it "removes conditions from a previous specified task" do
Simplified.start([]).must == [nil, nil, nil, 4]
end
end
end end
1 change: 0 additions & 1 deletion spec/spec_helper.rb
Expand Up @@ -12,7 +12,6 @@
load File.join(File.dirname(__FILE__), "fixtures", "group.thor") load File.join(File.dirname(__FILE__), "fixtures", "group.thor")
load File.join(File.dirname(__FILE__), "fixtures", "script.thor") load File.join(File.dirname(__FILE__), "fixtures", "script.thor")
load File.join(File.dirname(__FILE__), "fixtures", "invoke.thor") load File.join(File.dirname(__FILE__), "fixtures", "invoke.thor")
load File.join(File.dirname(__FILE__), "fixtures", "conditions.thor")


Kernel.module_eval do Kernel.module_eval do
alias_method :must, :should alias_method :must, :should
Expand Down
80 changes: 0 additions & 80 deletions spec/task_spec.rb
Expand Up @@ -48,12 +48,6 @@ def task(options={})
task.dup.options.delete(:foo) task.dup.options.delete(:foo)
task.options[:foo].must_not be_nil task.options[:foo].must_not be_nil
end end

it "dup conditions hash" do
task = Thor::Task.new("can_has", nil, nil, {}, :foo => true, :bar => :required)
task.dup.conditions.delete(:foo)
task.conditions[:foo].must_not be_nil
end
end end


describe "#run" do describe "#run" do
Expand All @@ -79,78 +73,4 @@ def task(options={})
Thor::Task.new(:task, "I can has cheezburger", "can_has").short_description == "I can has cheezburger" Thor::Task.new(:task, "I can has cheezburger", "can_has").short_description == "I can has cheezburger"
end end
end end

describe "#valid_conditions?" do
def run(instance, conditions={})
Thor::Task.new(:can_has, "I can has cheezburger", "can_has", nil, conditions).run(instance)
end

def stub!(options={})
instance = Object.new
stub(instance).options{ options }
instance
end

it "runs the task if no conditions are given" do
instance = stub!
mock(instance).can_has
run(instance)
end

it "runs the task if conditions are met" do
instance = stub!(:with_conditions => true)
mock(instance).can_has
run(instance, :with_conditions => true)
end

it "does not run the task if conditions are not met" do
instance = stub!(:with_conditions => true)
dont_allow(instance).can_has
run(instance, :with_conditions => false)
end

it "runs the task if symbol is equivalent to the given string" do
instance = stub!(:framework => :rails)
mock(instance).can_has
run(instance, :framework => "rails")

instance = stub!(:framework => "rails")
mock(instance).can_has
run(instance, :framework => :rails)

instance = stub!(:framework => :rails)
mock(instance).can_has
run(instance, :framework => :rails)
end

it "does not run the task if strings does not match" do
instance = stub!(:framework => "merb")
dont_allow(instance).can_has
run(instance, :framework => "rails")
end

it "runs the task if regexp matches" do
instance = stub!(:framework => "rails")
mock(instance).can_has
run(instance, :framework => /rails/)
end

it "does not run the task if regexp matches" do
instance = stub!(:framework => "merb")
dont_allow(instance).can_has
run(instance, :framework => /rails/)
end

it "runs the task if value is included in array" do
instance = stub!(:framework => "rails")
mock(instance).can_has
run(instance, :framework => [:rails, :merb])
end

it "does not run the task if value is not included in array" do
instance = stub!(:framework => "sinatra")
dont_allow(instance).can_has
run(instance, :framework => [:rails, :merb])
end
end
end end

0 comments on commit 2d9f3e3

Please sign in to comment.