Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Rename task -> command

Add aliases to old names for backward compatibility.
  • Loading branch information...
commit 25c49f98cc8468588f5d0af7c272e3db550c147f 1 parent 1fc5902
@sferik sferik authored
View
368 lib/thor.rb
@@ -3,21 +3,22 @@
class Thor
class << self
- # Sets the default task when thor is executed without an explicit task to be called.
+ # Sets the default command when thor is executed without an explicit command to be called.
#
# ==== Parameters
- # meth<Symbol>:: name of the default task
+ # meth<Symbol>:: name of the default command
#
- def default_task(meth=nil)
- @default_task = case meth
+ def default_command(meth=nil)
+ @default_command = case meth
when :none
'help'
when nil
- @default_task || from_superclass(:default_task, 'help')
+ @default_command || from_superclass(:default_command, 'help')
else
meth.to_s
end
end
+ alias default_task default_command
# Registers another Thor subclass as a command.
#
@@ -36,7 +37,7 @@ def register(klass, subcommand_name, usage, description, options={})
end
end
- # Defines the usage and the description of the next task.
+ # Defines the usage and the description of the next command.
#
# ==== Parameters
# usage<String>
@@ -45,29 +46,29 @@ def register(klass, subcommand_name, usage, description, options={})
#
def desc(usage, description, options={})
if options[:for]
- task = find_and_refresh_task(options[:for])
- task.usage = usage if usage
- task.description = description if description
+ command = find_and_refresh_command(options[:for])
+ command.usage = usage if usage
+ command.description = description if description
else
@usage, @desc, @hide = usage, description, options[:hide] || false
end
end
- # Defines the long description of the next task.
+ # Defines the long description of the next command.
#
# ==== Parameters
# long description<String>
#
def long_desc(long_description, options={})
if options[:for]
- task = find_and_refresh_task(options[:for])
- task.long_description = long_description if long_description
+ command = find_and_refresh_command(options[:for])
+ command.long_description = long_description if long_description
else
@long_desc = long_description
end
end
- # Maps an input to a task. If you define:
+ # Maps an input to a command. If you define:
#
# map "-T" => "list"
#
@@ -75,10 +76,10 @@ def long_desc(long_description, options={})
#
# thor -T
#
- # Will invoke the list task.
+ # Will invoke the list command.
#
# ==== Parameters
- # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given task.
+ # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
#
def map(mappings=nil)
@map ||= from_superclass(:map, {})
@@ -96,7 +97,7 @@ def map(mappings=nil)
@map
end
- # Declares the options for the next task to be declared.
+ # Declares the options for the next command to be declared.
#
# ==== Parameters
# Hash[Symbol => Object]:: The hash key is the name of the option and the value
@@ -112,15 +113,15 @@ def method_options(options=nil)
alias options method_options
# Adds an option to the set of method options. If :for is given as option,
- # it allows you to change the options from a previous defined task.
+ # it allows you to change the options from a previous defined command.
#
- # def previous_task
+ # def previous_command
# # magic
# end
#
- # method_option :foo => :bar, :for => :previous_task
+ # method_option :foo => :bar, :for => :previous_command
#
- # def next_task
+ # def next_command
# # magic
# end
#
@@ -139,38 +140,38 @@ def method_options(options=nil)
#
def method_option(name, options={})
scope = if options[:for]
- find_and_refresh_task(options[:for]).options
+ find_and_refresh_command(options[:for]).options
else
method_options
end
build_option(name, options, scope)
end
-
alias option method_option
- # Prints help information for the given task.
+ # Prints help information for the given command.
#
# ==== Parameters
# shell<Thor::Shell>
- # task_name<String>
+ # command_name<String>
#
- def task_help(shell, task_name)
- meth = normalize_task_name(task_name)
- task = all_tasks[meth]
- handle_no_task_error(meth) unless task
+ def command_help(shell, command_name)
+ meth = normalize_command_name(command_name)
+ command = all_commands[meth]
+ handle_no_command_error(meth) unless command
shell.say "Usage:"
- shell.say " #{banner(task)}"
+ shell.say " #{banner(command)}"
shell.say
- class_options_help(shell, nil => task.options.map { |_, o| o })
- if task.long_description
+ class_options_help(shell, nil => command.options.map { |_, o| o })
+ if command.long_description
shell.say "Description:"
- shell.print_wrapped(task.long_description, :indent => 2)
+ shell.print_wrapped(command.long_description, :indent => 2)
else
- shell.say task.description
+ shell.say command.description
end
end
+ alias task_help command_help
# Prints help information for this class.
#
@@ -178,32 +179,34 @@ def task_help(shell, task_name)
# shell<Thor::Shell>
#
def help(shell, subcommand = false)
- list = printable_tasks(true, subcommand)
+ list = printable_commands(true, subcommand)
Thor::Util.thor_classes_in(self).each do |klass|
- list += klass.printable_tasks(false)
+ list += klass.printable_commands(false)
end
list.sort!{ |a,b| a[0] <=> b[0] }
- shell.say "Tasks:"
+ shell.say "Commands:"
shell.print_table(list, :indent => 2, :truncate => true)
shell.say
class_options_help(shell)
end
- # Returns tasks ready to be printed.
- def printable_tasks(all = true, subcommand = false)
- (all ? all_tasks : tasks).map do |_, task|
- next if task.hidden?
+ # Returns commands ready to be printed.
+ def printable_commands(all = true, subcommand = false)
+ (all ? all_commands : commands).map do |_, command|
+ next if command.hidden?
item = []
- item << banner(task, false, subcommand)
- item << (task.description ? "# #{task.description.gsub(/\s+/m,' ')}" : "")
+ item << banner(command, false, subcommand)
+ item << (command.description ? "# #{command.description.gsub(/\s+/m,' ')}" : "")
item
end.compact
end
+ alias printable_tasks printable_commands
def subcommands
@subcommands ||= from_superclass(:subcommands, [])
end
+ alias subtasks subcommands
def subcommand(subcommand, subcommand_class)
self.subcommands << subcommand.to_s
@@ -214,6 +217,7 @@ def subcommand(subcommand, subcommand_class)
invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
end
end
+ alias subtask subcommand
# Extend check unknown options to accept a hash of conditions.
#
@@ -236,10 +240,10 @@ def check_unknown_options?(config) #:nodoc:
options = check_unknown_options
return false unless options
- task = config[:current_task]
- return true unless task
+ command = config[:current_command]
+ return true unless command
- name = task.name
+ name = command.name
if subcommands.include?(name)
false
@@ -253,16 +257,16 @@ def check_unknown_options?(config) #:nodoc:
end
# Stop parsing of options as soon as an unknown option or a regular
- # argument is encountered. All remaining arguments are passed to the task.
- # This is useful if you have a task that can receive arbitrary additional
+ # argument is encountered. All remaining arguments are passed to the command.
+ # This is useful if you have a command that can receive arbitrary additional
# options, and where those additional options should not be handled by
# Thor.
#
# ==== Example
#
- # To better understand how this is useful, let's consider a task that calls
+ # To better understand how this is useful, let's consider a command that calls
# an external command. A user may want to pass arbitrary options and
- # arguments to that command. The task itself also accepts some options,
+ # arguments to that command. The command itself also accepts some options,
# which should be handled by Thor.
#
# class_option "verbose", :type => :boolean
@@ -288,161 +292,167 @@ def check_unknown_options?(config) #:nodoc:
# --verbose foo
#
# ==== Parameters
- # Symbol ...:: A list of tasks that should be affected.
- def stop_on_unknown_option!(*task_names)
+ # Symbol ...:: A list of commands that should be affected.
+ def stop_on_unknown_option!(*command_names)
@stop_on_unknown_option ||= Set.new
- @stop_on_unknown_option.merge(task_names)
+ @stop_on_unknown_option.merge(command_names)
end
- def stop_on_unknown_option?(task) #:nodoc:
- !!@stop_on_unknown_option && @stop_on_unknown_option.include?(task.name.to_sym)
+ def stop_on_unknown_option?(command) #:nodoc:
+ !!@stop_on_unknown_option && @stop_on_unknown_option.include?(command.name.to_sym)
end
- protected
-
- # The method responsible for dispatching given the args.
- def dispatch(meth, given_args, given_opts, config) #:nodoc:
- # There is an edge case when dispatching from a subcommand.
- # A problem occurs invoking the default task. This case occurs
- # when arguments are passed and a default task is defined, and
- # the first given_args does not match the default task.
- # Thor use "help" by default so we skip that case.
- # Note the call to retrieve_task_name. It's called with
- # given_args.dup since that method calls args.shift. Then lookup
- # the task normally. If the first item in given_args is not
- # a task then use the default task. The given_args will be
- # intact later since dup was used.
- if config[:invoked_via_subcommand] && given_args.size >= 1 && default_task != "help" && given_args.first != default_task
- meth ||= retrieve_task_name(given_args.dup)
- task = all_tasks[normalize_task_name(meth)]
- task ||= all_tasks[normalize_task_name(default_task)]
- else
- meth ||= retrieve_task_name(given_args)
- task = all_tasks[normalize_task_name(meth)]
- end
+ protected
+
+ # The method responsible for dispatching given the args.
+ def dispatch(meth, given_args, given_opts, config) #:nodoc:
+ # There is an edge case when dispatching from a subcommand.
+ # A problem occurs invoking the default command. This case occurs
+ # when arguments are passed and a default command is defined, and
+ # the first given_args does not match the default command.
+ # Thor use "help" by default so we skip that case.
+ # Note the call to retrieve_command_name. It's called with
+ # given_args.dup since that method calls args.shift. Then lookup
+ # the command normally. If the first item in given_args is not
+ # a command then use the default command. The given_args will be
+ # intact later since dup was used.
+ if config[:invoked_via_subcommand] && given_args.size >= 1 && default_command != "help" && given_args.first != default_command
+ meth ||= retrieve_command_name(given_args.dup)
+ command = all_commands[normalize_command_name(meth)]
+ command ||= all_commands[normalize_command_name(default_command)]
+ else
+ meth ||= retrieve_command_name(given_args)
+ command = all_commands[normalize_command_name(meth)]
+ end
- if task
- args, opts = Thor::Options.split(given_args)
- if stop_on_unknown_option?(task) && !args.empty?
- # given_args starts with a non-option, so we treat everything as
- # ordinary arguments
- args.concat opts
- opts.clear
- end
- else
- args, opts = given_args, nil
- task = Thor::DynamicTask.new(meth)
+ if command
+ args, opts = Thor::Options.split(given_args)
+ if stop_on_unknown_option?(command) && !args.empty?
+ # given_args starts with a non-option, so we treat everything as
+ # ordinary arguments
+ args.concat opts
+ opts.clear
end
-
- opts = given_opts || opts || []
- config.merge!(:current_task => task, :task_options => task.options)
-
- instance = new(args, opts, config)
- yield instance if block_given?
- args = instance.args
- trailing = args[Range.new(arguments.size, -1)]
- instance.invoke_task(task, trailing || [])
+ else
+ args, opts = given_args, nil
+ command = Thor::DynamicCommand.new(meth)
end
- # The banner for this class. You can customize it if you are invoking the
- # thor class by another ways which is not the Thor::Runner. It receives
- # the task that is going to be invoked and a boolean which indicates if
- # the namespace should be displayed as arguments.
- #
- def banner(task, namespace = nil, subcommand = false)
- "#{basename} #{task.formatted_usage(self, $thor_runner, subcommand)}"
- end
+ opts = given_opts || opts || []
+ config.merge!(:current_command => command, :command_options => command.options)
- def baseclass #:nodoc:
- Thor
- end
+ instance = new(args, opts, config)
+ yield instance if block_given?
+ args = instance.args
+ trailing = args[Range.new(arguments.size, -1)]
+ instance.invoke_command(command, trailing || [])
+ end
- def create_task(meth) #:nodoc:
- if @usage && @desc
- base_class = @hide ? Thor::HiddenTask : Thor::Task
- tasks[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
- @usage, @desc, @long_desc, @method_options, @hide = nil
- true
- elsif self.all_tasks[meth] || meth == "method_missing"
- true
- else
- puts "[WARNING] Attempted to create task #{meth.inspect} without usage or description. " <<
- "Call desc if you want this method to be available as task or declare it inside a " <<
- "no_tasks{} block. Invoked from #{caller[1].inspect}."
- false
- end
- end
+ # The banner for this class. You can customize it if you are invoking the
+ # thor class by another ways which is not the Thor::Runner. It receives
+ # the command that is going to be invoked and a boolean which indicates if
+ # the namespace should be displayed as arguments.
+ #
+ def banner(command, namespace = nil, subcommand = false)
+ "#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}"
+ end
- def initialize_added #:nodoc:
- class_options.merge!(method_options)
- @method_options = nil
- end
+ def baseclass #:nodoc:
+ Thor
+ end
- # Retrieve the task name from given args.
- def retrieve_task_name(args) #:nodoc:
- meth = args.first.to_s unless args.empty?
- if meth && (map[meth] || meth !~ /^\-/)
- args.shift
- else
- nil
- end
+ def create_command(meth) #:nodoc:
+ if @usage && @desc
+ base_class = @hide ? Thor::HiddenCommand : Thor::Command
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
+ @usage, @desc, @long_desc, @method_options, @hide = nil
+ true
+ elsif self.all_commands[meth] || meth == "method_missing"
+ true
+ else
+ puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " <<
+ "Call desc if you want this method to be available as command or declare it inside a " <<
+ "no_commands{} block. Invoked from #{caller[1].inspect}."
+ false
end
+ end
+ alias create_task create_command
- # receives a (possibly nil) task name and returns a name that is in
- # the tasks hash. In addition to normalizing aliases, this logic
- # will determine if a shortened command is an unambiguous substring of
- # a task or alias.
- #
- # +normalize_task_name+ also converts names like +animal-prison+
- # into +animal_prison+.
- def normalize_task_name(meth) #:nodoc:
- return default_task.to_s.gsub('-', '_') unless meth
-
- possibilities = find_task_possibilities(meth)
- if possibilities.size > 1
- raise ArgumentError, "Ambiguous task #{meth} matches [#{possibilities.join(', ')}]"
- elsif possibilities.size < 1
- meth = meth || default_task
- elsif map[meth]
- meth = map[meth]
- else
- meth = possibilities.first
- end
+ def initialize_added #:nodoc:
+ class_options.merge!(method_options)
+ @method_options = nil
+ end
- meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
+ # Retrieve the command name from given args.
+ def retrieve_command_name(args) #:nodoc:
+ meth = args.first.to_s unless args.empty?
+ if meth && (map[meth] || meth !~ /^\-/)
+ args.shift
+ else
+ nil
end
-
- # this is the logic that takes the task name passed in by the user
- # and determines whether it is an unambiguous substrings of a task or
- # alias name.
- def find_task_possibilities(meth)
- len = meth.to_s.length
- possibilities = all_tasks.merge(map).keys.select { |n| meth == n[0, len] }.sort
- unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
-
- if possibilities.include?(meth)
- [meth]
- elsif unique_possibilities.size == 1
- unique_possibilities
- else
- possibilities
- end
+ end
+ alias retrieve_task_name retrieve_command_name
+
+ # receives a (possibly nil) command name and returns a name that is in
+ # the commands hash. In addition to normalizing aliases, this logic
+ # will determine if a shortened command is an unambiguous substring of
+ # a command or alias.
+ #
+ # +normalize_command_name+ also converts names like +animal-prison+
+ # into +animal_prison+.
+ def normalize_command_name(meth) #:nodoc:
+ return default_command.to_s.gsub('-', '_') unless meth
+
+ possibilities = find_command_possibilities(meth)
+ if possibilities.size > 1
+ raise ArgumentError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
+ elsif possibilities.size < 1
+ meth = meth || default_command
+ elsif map[meth]
+ meth = map[meth]
+ else
+ meth = possibilities.first
end
- def subcommand_help(cmd)
- desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
- class_eval <<-RUBY
- def help(task = nil, subcommand = true); super; end
- RUBY
+ meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
+ end
+ alias normalize_task_name normalize_command_name
+
+ # this is the logic that takes the command name passed in by the user
+ # and determines whether it is an unambiguous substrings of a command or
+ # alias name.
+ def find_command_possibilities(meth)
+ len = meth.to_s.length
+ possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
+ unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
+
+ if possibilities.include?(meth)
+ [meth]
+ elsif unique_possibilities.size == 1
+ unique_possibilities
+ else
+ possibilities
end
+ end
+ alias find_task_possibilities find_command_possibilities
+
+ def subcommand_help(cmd)
+ desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
+ class_eval <<-RUBY
+ def help(command = nil, subcommand = true); super; end
+ RUBY
+ end
+ alias subtask_help subcommand_help
+
end
include Thor::Base
map HELP_MAPPINGS => :help
- desc "help [TASK]", "Describe available tasks or one specific task"
- def help(task = nil, subcommand = false)
- task ? self.class.task_help(shell, task) : self.class.help(shell, subcommand)
+ desc "help [COMMAND]", "Describe available commands or one specific command"
+ def help(command = nil, subcommand = false)
+ command ? self.class.command_help(shell, command) : self.class.help(shell, subcommand)
end
end
View
8 lib/thor/actions.rb
@@ -268,8 +268,8 @@ def run_ruby_script(command, config={})
# switches.
#
# ==== Parameters
- # task<String>:: the task to be invoked
- # args<Array>:: arguments to the task
+ # command<String>:: the command to be invoked
+ # args<Array>:: arguments to the command
# config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output.
# Other options are given as parameter to Thor.
#
@@ -282,13 +282,13 @@ def run_ruby_script(command, config={})
# thor :list, :all => true, :substring => 'rails'
# #=> thor list --all --substring=rails
#
- def thor(task, *args)
+ def thor(command, *args)
config = args.last.is_a?(Hash) ? args.pop : {}
verbose = config.key?(:verbose) ? config.delete(:verbose) : true
pretend = config.key?(:pretend) ? config.delete(:pretend) : false
capture = config.key?(:capture) ? config.delete(:capture) : false
- args.unshift task
+ args.unshift(command)
args.push Thor::Options.to_switches(config)
command = args.join(' ').strip
View
152 lib/thor/base.rb
@@ -1,10 +1,10 @@
+require 'thor/command'
require 'thor/core_ext/hash_with_indifferent_access'
require 'thor/core_ext/ordered_hash'
require 'thor/error'
-require 'thor/shell'
require 'thor/invocation'
require 'thor/parser'
-require 'thor/task'
+require 'thor/shell'
require 'thor/util'
class Thor
@@ -47,8 +47,8 @@ def initialize(args=[], options={}, config={})
# first two parameters.
if options.is_a?(Array)
- task_options = config.delete(:task_options) # hook for start
- parse_options = parse_options.merge(task_options) if task_options
+ command_options = config.delete(:command_options) # hook for start
+ parse_options = parse_options.merge(command_options) if command_options
array_options, hash_options = options, {}
else
# Handle the case where the class was explicitly instantiated
@@ -59,7 +59,7 @@ def initialize(args=[], options={}, config={})
# Let Thor::Options parse the options first, so it can remove
# declared options from the array. This will leave us with
# a list of arguments that weren't declared.
- stop_on_unknown = self.class.stop_on_unknown_option? config[:current_task]
+ stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command]
opts = Thor::Options.new(parse_options, hash_options, stop_on_unknown)
self.options = opts.parse(array_options)
self.options = config[:class_options].merge(self.options) if config[:class_options]
@@ -120,15 +120,15 @@ def register_klass_file(klass) #:nodoc:
module ClassMethods
def attr_reader(*) #:nodoc:
- no_tasks { super }
+ no_commands { super }
end
def attr_writer(*) #:nodoc:
- no_tasks { super }
+ no_commands { super }
end
def attr_accessor(*) #:nodoc:
- no_tasks { super }
+ no_commands { super }
end
# If you want to raise an error for unknown options, call check_unknown_options!
@@ -147,8 +147,8 @@ def check_unknown_options?(config) #:nodoc:
# If true, option parsing is suspended as soon as an unknown option or a
# regular argument is encountered. All remaining arguments are passed to
- # the task as regular arguments.
- def stop_on_unknown_option?(task_name) #:nodoc:
+ # the command as regular arguments.
+ def stop_on_unknown_option?(command_name) #:nodoc:
false
end
@@ -173,11 +173,11 @@ def strict_args_position?(config) #:nodoc:
# is how they are parsed from the command line, arguments are retrieved
# from position:
#
- # thor task NAME
+ # thor command NAME
#
# Instead of:
#
- # thor task --name=NAME
+ # thor command --name=NAME
#
# Besides, arguments are used inside your code as an accessor (self.argument),
# while options are all kept in a hash (self.options).
@@ -204,7 +204,7 @@ def strict_args_position?(config) #:nodoc:
#
def argument(name, options={})
is_thor_reserved_word?(name, :argument)
- no_tasks { attr_accessor name }
+ no_commands { attr_accessor name }
required = if options.key?(:optional)
!options[:optional]
@@ -308,7 +308,7 @@ def remove_class_option(*names)
end
# Defines the group. This is used when thor list is invoked so you can specify
- # that only tasks from a pre-defined group will be shown. Defaults to standard.
+ # that only commands from a pre-defined group will be shown. Defaults to standard.
#
# ==== Parameters
# name<String|Symbol>
@@ -322,74 +322,78 @@ def group(name=nil)
end
end
- # Returns the tasks for this Thor class.
+ # Returns the commands for this Thor class.
#
# ==== Returns
- # OrderedHash:: An ordered hash with tasks names as keys and Thor::Task
+ # OrderedHash:: An ordered hash with commands names as keys and Thor::Command
# objects as values.
#
- def tasks
- @tasks ||= Thor::CoreExt::OrderedHash.new
+ def commands
+ @commands ||= Thor::CoreExt::OrderedHash.new
end
+ alias tasks commands
- # Returns the tasks for this Thor class and all subclasses.
+ # Returns the commands for this Thor class and all subclasses.
#
# ==== Returns
- # OrderedHash:: An ordered hash with tasks names as keys and Thor::Task
+ # OrderedHash:: An ordered hash with commands names as keys and Thor::Command
# objects as values.
#
- def all_tasks
- @all_tasks ||= from_superclass(:all_tasks, Thor::CoreExt::OrderedHash.new)
- @all_tasks.merge(tasks)
+ def all_commands
+ @all_commands ||= from_superclass(:all_commands, Thor::CoreExt::OrderedHash.new)
+ @all_commands.merge(commands)
end
+ alias all_tasks all_commands
- # Removes a given task from this Thor class. This is usually done if you
+ # Removes a given command from this Thor class. This is usually done if you
# are inheriting from another class and don't want it to be available
# anymore.
#
- # By default it only remove the mapping to the task. But you can supply
+ # By default it only remove the mapping to the command. But you can supply
# :undefine => true to undefine the method from the class as well.
#
# ==== Parameters
- # name<Symbol|String>:: The name of the task to be removed
- # options<Hash>:: You can give :undefine => true if you want tasks the method
+ # name<Symbol|String>:: The name of the command to be removed
+ # options<Hash>:: You can give :undefine => true if you want commands the method
# to be undefined from the class as well.
#
- def remove_task(*names)
+ def remove_command(*names)
options = names.last.is_a?(Hash) ? names.pop : {}
names.each do |name|
- tasks.delete(name.to_s)
- all_tasks.delete(name.to_s)
+ commands.delete(name.to_s)
+ all_commands.delete(name.to_s)
undef_method name if options[:undefine]
end
end
+ alias remove_task remove_command
- # All methods defined inside the given block are not added as tasks.
+ # All methods defined inside the given block are not added as commands.
#
# So you can do:
#
# class MyScript < Thor
- # no_tasks do
- # def this_is_not_a_task
+ # no_commands do
+ # def this_is_not_a_command
# end
# end
# end
#
- # You can also add the method and remove it from the task list:
+ # You can also add the method and remove it from the command list:
#
# class MyScript < Thor
- # def this_is_not_a_task
+ # def this_is_not_a_command
# end
- # remove_task :this_is_not_a_task
+ # remove_command :this_is_not_a_command
# end
#
- def no_tasks
- @no_tasks = true
+ def no_commands
+ @no_commands = true
yield
ensure
- @no_tasks = false
+ @no_commands = false
end
+ alias no_tasks no_commands
# Sets the namespace for the Thor or Thor::Group class. By default the
# namespace is retrieved from the class name. If your Thor class is named
@@ -401,7 +405,7 @@ def no_tasks
#
# namespace :my_scripts
#
- # You change how your tasks are invoked:
+ # You change how your commands are invoked:
#
# thor my_scripts -h
#
@@ -409,9 +413,9 @@ def no_tasks
#
# namespace :default
#
- # Your tasks can be invoked with a shortcut. Instead of:
+ # Your commands can be invoked with a shortcut. Instead of:
#
- # thor :my_task
+ # thor :my_command
#
def namespace(name=nil)
@namespace = case name
@@ -422,13 +426,13 @@ def namespace(name=nil)
end
end
- # Parses the task and options from the given args, instantiate the class
- # and invoke the task. This method is used when the arguments must be parsed
+ # Parses the command and options from the given args, instantiate the class
+ # and invoke the command. This method is used when the arguments must be parsed
# from an array. If you are inside Ruby and want to use a Thor class, you
# can simply initialize it:
#
# script = MyScript.new(args, options, config)
- # script.invoke(:task, first_arg, second_arg, third_arg)
+ # script.invoke(:command, first_arg, second_arg, third_arg)
#
def start(given_args=ARGV, config={})
config[:shell] ||= Thor::Base.shell.new
@@ -437,39 +441,41 @@ def start(given_args=ARGV, config={})
ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
exit(1) if exit_on_failure?
rescue Errno::EPIPE
- # This happens if a thor task is piped to something like `head`,
+ # This happens if a thor command is piped to something like `head`,
# which closes the pipe when it's done reading. This will also
# mean that if the pipe is closed, further unnecessary
# computation will not occur.
exit(0)
end
- # Allows to use private methods from parent in child classes as tasks.
+ # Allows to use private methods from parent in child classes as commands.
#
# ==== Parameters
- # names<Array>:: Method names to be used as tasks
+ # names<Array>:: Method names to be used as commands
#
# ==== Examples
#
- # public_task :foo
- # public_task :foo, :bar, :baz
+ # public_command :foo
+ # public_command :foo, :bar, :baz
#
- def public_task(*names)
+ def public_command(*names)
names.each do |name|
class_eval "def #{name}(*); super end"
end
end
+ alias public_task public_command
- def handle_no_task_error(task, has_namespace = $thor_runner) #:nodoc:
+ def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc:
if has_namespace
- raise UndefinedTaskError, "Could not find task #{task.inspect} in #{namespace.inspect} namespace."
+ raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace."
else
- raise UndefinedTaskError, "Could not find task #{task.inspect}."
+ raise UndefinedCommandError, "Could not find command #{command.inspect}."
end
end
+ alias handle_no_task_error handle_no_command_error
- def handle_argument_error(task, error, arity=nil) #:nodoc:
- msg = "#{basename} #{task.name}"
+ def handle_argument_error(command, error, arity=nil) #:nodoc:
+ msg = "#{basename} #{command.name}"
if arity && arity != 0
required = arity < 0 ? (-1 - arity) : arity
if required == 0
@@ -482,7 +488,7 @@ def handle_argument_error(task, error, arity=nil) #:nodoc:
msg = "call #{msg} as"
end
- msg << ": #{self.banner(task).inspect}."
+ msg << ": #{self.banner(command).inspect}."
raise InvocationError, msg
end
@@ -560,28 +566,29 @@ def build_options(options, scope) #:nodoc:
end
end
- # Finds a task with the given name. If the task belongs to the current
+ # Finds a command with the given name. If the command belongs to the current
# class, just return it, otherwise dup it and add the fresh copy to the
- # current task hash.
- def find_and_refresh_task(name) #:nodoc:
- task = if task = tasks[name.to_s]
- task
- elsif task = all_tasks[name.to_s]
- tasks[name.to_s] = task.clone
+ # current command hash.
+ def find_and_refresh_command(name) #:nodoc:
+ command = if command = commands[name.to_s]
+ command
+ elsif command = all_commands[name.to_s]
+ commands[name.to_s] = command.clone
else
- raise ArgumentError, "You supplied :for => #{name.inspect}, but the task #{name.inspect} could not be found."
+ raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found."
end
end
+ alias find_and_refresh_task find_and_refresh_command
# Everytime someone inherits from a Thor class, register the klass
# and file into baseclass.
def inherited(klass)
Thor::Base.register_klass_file(klass)
- klass.instance_variable_set(:@no_tasks, false)
+ klass.instance_variable_set(:@no_commands, false)
end
# Fire this callback whenever a method is added. Added methods are
- # tracked as tasks by invoking the create_task method.
+ # tracked as commands by invoking the create_command method.
def method_added(meth)
meth = meth.to_s
@@ -594,9 +601,9 @@ def method_added(meth)
return unless public_instance_methods.include?(meth) ||
public_instance_methods.include?(meth.to_sym)
- return if @no_tasks || !create_task(meth)
+ return if @no_commands || !create_command(meth)
- is_thor_reserved_word?(meth, :task)
+ is_thor_reserved_word?(meth, :command)
Thor::Base.register_klass_file(self)
end
@@ -635,10 +642,11 @@ def basename
def baseclass #:nodoc:
end
- # SIGNATURE: Creates a new task if valid_task? is true. This method is
+ # SIGNATURE: Creates a new command if valid_command? is true. This method is
# called when a new method is added to the class.
- def create_task(meth) #:nodoc:
+ def create_command(meth) #:nodoc:
end
+ alias create_task create_command
# SIGNATURE: Defines behavior when the initialize method is added to the
# class.
@@ -646,7 +654,7 @@ def initialize_added #:nodoc:
end
# SIGNATURE: The hook invoked by start.
- def dispatch(task, given_args, given_opts, config) #:nodoc:
+ def dispatch(command, given_args, given_opts, config) #:nodoc:
raise NotImplementedError
end
View
28 lib/thor/task.rb → lib/thor/command.rb
@@ -1,5 +1,5 @@
class Thor
- class Task < Struct.new(:name, :description, :long_description, :usage, :options)
+ class Command < Struct.new(:name, :description, :long_description, :usage, :options)
FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
def initialize(name, description, long_description, usage, options=nil)
@@ -15,27 +15,27 @@ def hidden?
false
end
- # By default, a task invokes a method in the thor class. You can change this
- # implementation to create custom tasks.
+ # By default, a command invokes a method in the thor class. You can change this
+ # implementation to create custom commands.
def run(instance, args=[])
arity = nil
if private_method?(instance)
- instance.class.handle_no_task_error(name)
+ instance.class.handle_no_command_error(name)
elsif public_method?(instance)
arity = instance.method(name).arity
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)
+ instance.class.handle_no_command_error(name)
end
rescue ArgumentError => e
handle_argument_error?(instance, e, caller) ?
instance.class.handle_argument_error(self, e, arity) : (raise e)
rescue NoMethodError => e
handle_no_method_error?(instance, e, caller) ?
- instance.class.handle_no_task_error(name) : (raise e)
+ instance.class.handle_no_command_error(name) : (raise e)
end
# Returns the formatted usage by injecting given required arguments
@@ -107,26 +107,30 @@ def handle_no_method_error?(instance, error, caller)
error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
end
end
+ Task = Command
- # A task that is hidden in help messages but still invocable.
- class HiddenTask < Task
+ # A command that is hidden in help messages but still invocable.
+ class HiddenCommand < Command
def hidden?
true
end
end
+ HiddenTask = HiddenCommand
- # A dynamic task that handles method missing scenarios.
- class DynamicTask < Task
+ # A dynamic command that handles method missing scenarios.
+ class DynamicCommand < Command
def initialize(name, options=nil)
- super(name.to_s, "A dynamically-generated task", name.to_s, name.to_s, options)
+ super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options)
end
def run(instance, args=[])
if (instance.methods & [name.to_s, name.to_sym]).empty?
super
else
- instance.class.handle_no_task_error(name)
+ instance.class.handle_no_command_error(name)
end
end
end
+ DynamicTask = DynamicCommand
+
end
View
11 lib/thor/error.rb
@@ -5,17 +5,15 @@ class Thor
# Errors that are caused by the developer, like declaring a method which
# overwrites a thor keyword, it SHOULD NOT raise a Thor::Error. This way, we
# ensure that developer errors are shown with full backtrace.
- #
class Error < StandardError
end
- # Raised when a task was not found.
- #
- class UndefinedTaskError < Error
+ # Raised when a command was not found.
+ class UndefinedCommandError < Error
end
+ UndefinedTaskError = UndefinedCommandError
- # Raised when a task was found, but not invoked properly.
- #
+ # Raised when a command was found, but not invoked properly.
class InvocationError < Error
end
@@ -29,7 +27,6 @@ class MalformattedArgumentError < InvocationError
end
# Raised when a user tries to call a private method encoded in templated filename.
- #
class PrivateMethodEncodedError < Error
end
end
View
55 lib/thor/group.rb
@@ -1,9 +1,9 @@
require 'thor/base'
# Thor has a special class called Thor::Group. The main difference to Thor class
-# is that it invokes all tasks at once. It also include some methods that allows
+# is that it invokes all commands at once. It also include some methods that allows
# invocations to be done at the class method, which are not available to Thor
-# tasks.
+# commands.
class Thor::Group
class << self
# The description for this Thor::Group. If none is provided, but a source root
@@ -48,7 +48,7 @@ def invocation_blocks #:nodoc:
end
# Invoke the given namespace or class given. It adds an instance
- # method that will invoke the klass and task. You can give a block to
+ # method that will invoke the klass and command. You can give a block to
# configure how it will be invoked.
#
# The namespace/class given will have its options showed on the help
@@ -64,12 +64,12 @@ def invoke(*names, &block)
class_eval <<-METHOD, __FILE__, __LINE__
def _invoke_#{name.to_s.gsub(/\W/, '_')}
- klass, task = self.class.prepare_for_invocation(nil, #{name.inspect})
+ klass, command = self.class.prepare_for_invocation(nil, #{name.inspect})
if klass
say_status :invoke, #{name.inspect}, #{verbose.inspect}
block = self.class.invocation_blocks[#{name.inspect}]
- _invoke_for_class_method klass, task, &block
+ _invoke_for_class_method klass, command, &block
else
say_status :error, %(#{name.inspect} [not found]), :red
end
@@ -100,7 +100,7 @@ def _invoke_#{name.to_s.gsub(/\W/, '_')}
# In some cases you want to customize how a specified hook is going to be
# invoked. You can do that by overwriting the class method
# prepare_for_invocation. The class method must necessarily return a klass
- # and an optional task.
+ # and an optional command.
#
# ==== Custom invocations
#
@@ -127,12 +127,12 @@ def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
value = options[#{name.inspect}]
value = #{name.inspect} if TrueClass === value
- klass, task = self.class.prepare_for_invocation(#{name.inspect}, value)
+ klass, command = self.class.prepare_for_invocation(#{name.inspect}, value)
if klass
say_status :invoke, value, #{verbose.inspect}
block = self.class.invocation_blocks[#{name.inspect}]
- _invoke_for_class_method klass, task, &block
+ _invoke_for_class_method klass, command, &block
else
say_status :error, %(\#{value} [not found]), :red
end
@@ -149,7 +149,7 @@ def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
#
def remove_invocation(*names)
names.each do |name|
- remove_task(name)
+ remove_command(name)
remove_class_option(name)
invocations.delete(name)
invocation_blocks.delete(name)
@@ -196,21 +196,22 @@ def get_options_from_invocations(group_options, base_options) #:nodoc:
end
end
- # Returns tasks ready to be printed.
- def printable_tasks(*)
+ # Returns commands ready to be printed.
+ def printable_commands(*)
item = []
item << banner
item << (desc ? "# #{desc.gsub(/\s+/m,' ')}" : "")
[item]
end
+ alias printable_tasks printable_commands
- def handle_argument_error(task, error, arity=nil) #:nodoc:
+ def handle_argument_error(command, error, arity=nil) #:nodoc:
if arity > 0
- msg = "#{basename} #{task.name} takes #{arity} argument"
+ msg = "#{basename} #{command.name} takes #{arity} argument"
msg << "s" if arity > 1
msg << ", but it should not."
else
- msg = "You should not pass arguments to #{basename} #{task.name}."
+ msg = "You should not pass arguments to #{basename} #{command.name}."
end
raise error, msg
@@ -219,7 +220,7 @@ def handle_argument_error(task, error, arity=nil) #:nodoc:
protected
# The method responsible for dispatching given the args.
- def dispatch(task, given_args, given_opts, config) #:nodoc:
+ def dispatch(command, given_args, given_opts, config) #:nodoc:
if Thor::HELP_MAPPINGS.include?(given_args.first)
help(config[:shell])
return
@@ -231,8 +232,8 @@ def dispatch(task, given_args, given_opts, config) #:nodoc:
instance = new(args, opts, config)
yield instance if block_given?
- if task
- instance.invoke_task(all_tasks[task])
+ if command
+ instance.invoke_command(all_commands[command])
else
instance.invoke_all
end
@@ -241,22 +242,24 @@ def dispatch(task, given_args, given_opts, config) #:nodoc:
# The banner for this class. You can customize it if you are invoking the
# thor class by another ways which is not the Thor::Runner.
def banner
- "#{basename} #{self_task.formatted_usage(self, false)}"
+ "#{basename} #{self_command.formatted_usage(self, false)}"
end
- # Represents the whole class as a task.
- def self_task #:nodoc:
- Thor::DynamicTask.new(self.namespace, class_options)
+ # Represents the whole class as a command.
+ def self_command #:nodoc:
+ Thor::DynamicCommand.new(self.namespace, class_options)
end
+ alias self_task self_command
def baseclass #:nodoc:
Thor::Group
end
- def create_task(meth) #:nodoc:
- tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil, nil)
+ def create_command(meth) #:nodoc:
+ commands[meth.to_s] = Thor::Command.new(meth, nil, nil, nil, nil)
true
end
+ alias create_task create_command
end
include Thor::Base
@@ -265,19 +268,19 @@ def create_task(meth) #:nodoc:
# Shortcut to invoke with padding and block handling. Use internally by
# invoke and invoke_from_option class methods.
- def _invoke_for_class_method(klass, task=nil, *args, &block) #:nodoc:
+ def _invoke_for_class_method(klass, command=nil, *args, &block) #:nodoc:
with_padding do
if block
case block.arity
when 3
- block.call(self, klass, task)
+ block.call(self, klass, command)
when 2
block.call(self, klass)
when 1
instance_exec(klass, &block)
end
else
- invoke klass, task, *args
+ invoke klass, command, *args
end
end
end
View
54 lib/thor/invocation.rb
@@ -6,12 +6,12 @@ def self.included(base) #:nodoc:
module ClassMethods
# This method is responsible for receiving a name and find the proper
- # class and task for it. The key is an optional parameter which is
+ # class and command for it. The key is an optional parameter which is
# available only in class methods invocations (i.e. in Thor::Group).
def prepare_for_invocation(key, name) #:nodoc:
case name
when Symbol, String
- Thor::Util.find_class_and_task_by_namespace(name.to_s, !key)
+ Thor::Util.find_class_and_command_by_namespace(name.to_s, !key)
else
name
end
@@ -25,15 +25,15 @@ def initialize(args=[], options={}, config={}, &block) #:nodoc:
super
end
- # Receives a name and invokes it. The name can be a string (either "task" or
- # "namespace:task"), a Thor::Task, a Class or a Thor instance. If the task
- # cannot be guessed by name, it can also be supplied as second argument.
+ # Receives a name and invokes it. The name can be a string (either "command" or
+ # "namespace:command"), a Thor::Command, a Class or a Thor instance. If the
+ # command cannot be guessed by name, it can also be supplied as second argument.
#
# You can also supply the arguments, options and configuration values for
- # the task to be invoked, if none is given, the same values used to
+ # the command to be invoked, if none is given, the same values used to
# initialize the invoker are used to initialize the invoked.
#
- # When no name is given, it will invoke the default task of the current class.
+ # When no name is given, it will invoke the default command of the current class.
#
# ==== Examples
#
@@ -54,16 +54,16 @@ def initialize(args=[], options={}, config={}, &block) #:nodoc:
# end
# end
#
- # You can notice that the method "foo" above invokes two tasks: "bar",
+ # You can notice that the method "foo" above invokes two commands: "bar",
# which belongs to the same class and "hello" which belongs to the class B.
#
- # By using an invocation system you ensure that a task is invoked only once.
+ # By using an invocation system you ensure that a command is invoked only once.
# In the example above, invoking "foo" will invoke "b:hello" just once, even
# if it's invoked later by "bar" method.
#
# When class A invokes class B, all arguments used on A initialization are
# supplied to B. This allows lazy parse of options. Let's suppose you have
- # some rspec tasks:
+ # some rspec commands:
#
# class Rspec < Thor::Group
# class_option :mock_framework, :type => :string, :default => :rr
@@ -100,30 +100,31 @@ def invoke(name=nil, *args)
end
args.unshift(nil) if Array === args.first || NilClass === args.first
- task, args, opts, config = args
+ command, args, opts, config = args
- klass, task = _retrieve_class_and_task(name, task)
+ klass, command = _retrieve_class_and_command(name, command)
raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
args, opts, config = _parse_initialization_options(args, opts, config)
- klass.send(:dispatch, task, args, opts, config) do |instance|
+ klass.send(:dispatch, command, args, opts, config) do |instance|
instance.parent_options = options
end
end
- # Invoke the given task if the given args.
- def invoke_task(task, *args) #:nodoc:
+ # Invoke the given command if the given args.
+ def invoke_command(command, *args) #:nodoc:
current = @_invocations[self.class]
- unless current.include?(task.name)
- current << task.name
- task.run(self, *args)
+ unless current.include?(command.name)
+ current << command.name
+ command.run(self, *args)
end
end
+ alias invoke_task invoke_command
- # Invoke all tasks for the current instance.
+ # Invoke all commands for the current instance.
def invoke_all #:nodoc:
- self.class.all_tasks.map { |_, task| invoke_task(task) }
+ self.class.all_commands.map { |_, command| invoke_command(command) }
end
# Invokes using shell padding.
@@ -138,21 +139,22 @@ def _shared_configuration #:nodoc:
{ :invocations => @_invocations }
end
- # This method simply retrieves the class and task to be invoked.
- # If the name is nil or the given name is a task in the current class,
+ # This method simply retrieves the class and command to be invoked.
+ # If the name is nil or the given name is a command in the current class,
# use the given name and return self as class. Otherwise, call
# prepare_for_invocation in the current class.
- def _retrieve_class_and_task(name, sent_task=nil) #:nodoc:
+ def _retrieve_class_and_command(name, sent_command=nil) #:nodoc:
case
when name.nil?
[self.class, nil]
- when self.class.all_tasks[name.to_s]
+ when self.class.all_commands[name.to_s]
[self.class, name.to_s]
else
- klass, task = self.class.prepare_for_invocation(nil, name)
- [klass, task || sent_task]
+ klass, command = self.class.prepare_for_invocation(nil, name)
+ [klass, command || sent_command]
end
end
+ alias _retrieve_class_and_task _retrieve_class_and_command
# Initialize klass using values stored in the @_initializer.
def _parse_initialization_options(args, opts, config) #:nodoc:
View
39 lib/thor/runner.rb
@@ -16,33 +16,33 @@ class Thor::Runner < Thor #:nodoc:
def help(meth = nil)
if meth && !self.respond_to?(meth)
initialize_thorfiles(meth)
- klass, task = Thor::Util.find_class_and_task_by_namespace(meth)
- self.class.handle_no_task_error(task, false) if klass.nil?
- klass.start(["-h", task].compact, :shell => self.shell)
+ klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
+ self.class.handle_no_command_error(command, false) if klass.nil?
+ klass.start(["-h", command].compact, :shell => self.shell)
else
super
end
end
- # If a task is not found on Thor::Runner, method missing is invoked and
- # Thor::Runner is then responsible for finding the task in all classes.
+ # If a command is not found on Thor::Runner, method missing is invoked and
+ # Thor::Runner is then responsible for finding the command in all classes.
#
def method_missing(meth, *args)
meth = meth.to_s
initialize_thorfiles(meth)
- klass, task = Thor::Util.find_class_and_task_by_namespace(meth)
- self.class.handle_no_task_error(task, false) if klass.nil?
- args.unshift(task) if task
+ klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
+ self.class.handle_no_command_error(command, false) if klass.nil?
+ args.unshift(command) if command
klass.start(args, :shell => self.shell)
end
- desc "install NAME", "Install an optionally named Thor file into your system tasks"
+ desc "install NAME", "Install an optionally named Thor file into your system commands"
method_options :as => :string, :relative => :boolean, :force => :boolean
def install(name)
initialize_thorfiles
# If a directory name is provided as the argument, look for a 'main.thor'
- # task in said directory.
+ # command in said directory.
begin
if File.directory?(File.expand_path(name))
base, package = File.join(name, "main.thor"), :directory
@@ -143,14 +143,14 @@ def update(name)
end
end
- desc "installed", "List the installed Thor modules and tasks"
+ desc "installed", "List the installed Thor modules and commands"
method_options :internal => :boolean
def installed
initialize_thorfiles(nil, true)
display_klasses(true, options["internal"])
end
- desc "list [SEARCH]", "List the available thor tasks (--substring means .*SEARCH)"
+ desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)"
method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
def list(search="")
initialize_thorfiles
@@ -168,8 +168,8 @@ def list(search="")
private
- def self.banner(task, all = false, subcommand = false)
- "thor " + task.formatted_usage(self, all, subcommand)
+ def self.banner(command, all = false, subcommand = false)
+ "thor " + command.formatted_usage(self, all, subcommand)
end
def thor_root
@@ -276,25 +276,25 @@ def thorfiles_relevant_to(meth)
def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
- raise Error, "No Thor tasks available" if klasses.empty?
+ raise Error, "No Thor commands available" if klasses.empty?
show_modules if with_modules && !thor_yaml.empty?
list = Hash.new { |h,k| h[k] = [] }
groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
# Get classes which inherit from Thor
- (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_tasks(false) }
+ (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) }
# Get classes which inherit from Thor::Base
- groups.map! { |k| k.printable_tasks(false).first }
+ groups.map! { |k| k.printable_commands(false).first }
list["root"] = groups
# Order namespaces with default coming first
list = list.sort{ |a,b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
- list.each { |n, tasks| display_tasks(n, tasks) unless tasks.empty? }
+ list.each { |n, commands| display_commands(n, commands) unless commands.empty? }
end
- def display_tasks(namespace, list) #:nodoc:
+ def display_commands(namespace, list) #:nodoc:
list.sort!{ |a,b| a[0] <=> b[0] }
say shell.set_color(namespace, :blue, true)
@@ -303,6 +303,7 @@ def display_tasks(namespace, list) #:nodoc:
print_table(list, :truncate => true)
say
end
+ alias display_tasks display_commands
def show_modules #:nodoc:
info = []
View
424 lib/thor/util.rb
@@ -16,251 +16,255 @@ module Sandbox #:nodoc:
#
module Util
- # Receives a namespace and search for it in the Thor::Base subclasses.
- #
- # ==== Parameters
- # namespace<String>:: The namespace to search for.
- #
- def self.find_by_namespace(namespace)
- namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/
- Thor::Base.subclasses.find { |klass| klass.namespace == namespace }
- end
+ class << self
- # Receives a constant and converts it to a Thor namespace. Since Thor tasks
- # can be added to a sandbox, this method is also responsable for removing
- # the sandbox namespace.
- #
- # This method should not be used in general because it's used to deal with
- # older versions of Thor. On current versions, if you need to get the
- # namespace from a class, just call namespace on it.
- #
- # ==== Parameters
- # constant<Object>:: The constant to be converted to the thor path.
- #
- # ==== Returns
- # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz"
- #
- def self.namespace_from_thor_class(constant)
- constant = constant.to_s.gsub(/^Thor::Sandbox::/, "")
- constant = snake_case(constant).squeeze(":")
- constant
- end
+ # Receives a namespace and search for it in the Thor::Base subclasses.
+ #
+ # ==== Parameters
+ # namespace<String>:: The namespace to search for.
+ #
+ def find_by_namespace(namespace)
+ namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/
+ Thor::Base.subclasses.find { |klass| klass.namespace == namespace }
+ end
- # Given the contents, evaluate it inside the sandbox and returns the
- # namespaces defined in the sandbox.
- #
- # ==== Parameters
- # contents<String>
- #
- # ==== Returns
- # Array[Object]
- #
- def self.namespaces_in_content(contents, file=__FILE__)
- old_constants = Thor::Base.subclasses.dup
- Thor::Base.subclasses.clear
+ # Receives a constant and converts it to a Thor namespace. Since Thor
+ # commands can be added to a sandbox, this method is also responsable for
+ # removing the sandbox namespace.
+ #
+ # This method should not be used in general because it's used to deal with
+ # older versions of Thor. On current versions, if you need to get the
+ # namespace from a class, just call namespace on it.
+ #
+ # ==== Parameters
+ # constant<Object>:: The constant to be converted to the thor path.
+ #
+ # ==== Returns
+ # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz"
+ #
+ def namespace_from_thor_class(constant)
+ constant = constant.to_s.gsub(/^Thor::Sandbox::/, "")
+ constant = snake_case(constant).squeeze(":")
+ constant
+ end
- load_thorfile(file, contents)
+ # Given the contents, evaluate it inside the sandbox and returns the
+ # namespaces defined in the sandbox.
+ #
+ # ==== Parameters
+ # contents<String>
+ #
+ # ==== Returns
+ # Array[Object]
+ #
+ def namespaces_in_content(contents, file=__FILE__)
+ old_constants = Thor::Base.subclasses.dup
+ Thor::Base.subclasses.clear
- new_constants = Thor::Base.subclasses.dup
- Thor::Base.subclasses.replace(old_constants)
+ load_thorfile(file, contents)
- new_constants.map!{ |c| c.namespace }
- new_constants.compact!
- new_constants
- end
+ new_constants = Thor::Base.subclasses.dup
+ Thor::Base.subclasses.replace(old_constants)
- # Returns the thor classes declared inside the given class.
- #
- def self.thor_classes_in(klass)
- stringfied_constants = klass.constants.map { |c| c.to_s }
- Thor::Base.subclasses.select do |subclass|
- next unless subclass.name
- stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", ''))
+ new_constants.map!{ |c| c.namespace }
+ new_constants.compact!
+ new_constants
end
- end
-
- # Receives a string and convert it to snake case. SnakeCase returns snake_case.
- #
- # ==== Parameters
- # String
- #
- # ==== Returns
- # String
- #
- def self.snake_case(str)
- return str.downcase if str =~ /^[A-Z_]+$/
- str.gsub(/\B[A-Z]/, '_\&').squeeze('_') =~ /_*(.*)/
- return $+.downcase
- end
-
- # Receives a string and convert it to camel case. camel_case returns CamelCase.
- #
- # ==== Parameters
- # String
- #
- # ==== Returns
- # String
- #
- def self.camel_case(str)
- return str if str !~ /_/ && str =~ /[A-Z]+.*/
- str.split('_').map { |i| i.capitalize }.join
- end
- # Receives a namespace and tries to retrieve a Thor or Thor::Group class
- # from it. It first searches for a class using the all the given namespace,
- # if it's not found, removes the highest entry and searches for the class
- # again. If found, returns the highest entry as the class name.
- #
- # ==== Examples
- #
- # class Foo::Bar < Thor
- # def baz
- # end
- # end
- #
- # class Baz::Foo < Thor::Group
- # end
- #
- # Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default task
- # Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil
- # Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz"
- #
- # ==== Parameters
- # namespace<String>
- #
- def self.find_class_and_task_by_namespace(namespace, fallback = true)
- if namespace.include?(?:) # look for a namespaced task
- pieces = namespace.split(":")
- task = pieces.pop
- klass = Thor::Util.find_by_namespace(pieces.join(":"))
- end
- unless klass # look for a Thor::Group with the right name
- klass, task = Thor::Util.find_by_namespace(namespace), nil
+ # Returns the thor classes declared inside the given class.
+ #
+ def thor_classes_in(klass)
+ stringfied_constants = klass.constants.map { |c| c.to_s }
+ Thor::Base.subclasses.select do |subclass|
+ next unless subclass.name
+ stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", ''))
+ end
end
- if !klass && fallback # try a task in the default namespace
- task = namespace
- klass = Thor::Util.find_by_namespace('')
+
+ # Receives a string and convert it to snake case. SnakeCase returns snake_case.
+ #
+ # ==== Parameters
+ # String
+ #
+ # ==== Returns
+ # String
+ #
+ def snake_case(str)
+ return str.downcase if str =~ /^[A-Z_]+$/
+ str.gsub(/\B[A-Z]/, '_\&').squeeze('_') =~ /_*(.*)/
+ return $+.downcase
end
- return klass, task
- end
- # Receives a path and load the thor file in the path. The file is evaluated
- # inside the sandbox to avoid namespacing conflicts.
- #
- def self.load_thorfile(path, content=nil, debug=false)
- content ||= File.binread(path)
+ # Receives a string and convert it to camel case. camel_case returns CamelCase.
+ #
+ # ==== Parameters
+ # String
+ #
+ # ==== Returns
+ # String
+ #
+ def camel_case(str)
+ return str if str !~ /_/ && str =~ /[A-Z]+.*/
+ str.split('_').map { |i| i.capitalize }.join
+ end
- begin
- Thor::Sandbox.class_eval(content, path)
- rescue Exception => e
- $stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}")
- if debug
- $stderr.puts(*e.backtrace)
- else
- $stderr.puts(e.backtrace.first)
+ # Receives a namespace and tries to retrieve a Thor or Thor::Group class
+ # from it. It first searches for a class using the all the given namespace,
+ # if it's not found, removes the highest entry and searches for the class
+ # again. If found, returns the highest entry as the class name.
+ #
+ # ==== Examples
+ #
+ # class Foo::Bar < Thor
+ # def baz
+ # end
+ # end
+ #
+ # class Baz::Foo < Thor::Group
+ # end
+ #
+ # Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default command
+ # Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil
+ # Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz"
+ #
+ # ==== Parameters
+ # namespace<String>
+ #
+ def find_class_and_command_by_namespace(namespace, fallback = true)
+ if namespace.include?(?:) # look for a namespaced command
+ pieces = namespace.split(":")
+ command = pieces.pop
+ klass = Thor::Util.find_by_namespace(pieces.join(":"))
+ end
+ unless klass # look for a Thor::Group with the right name
+ klass, command = Thor::Util.find_by_namespace(namespace), nil
+ end
+ if !klass && fallback # try a command in the default namespace
+ command = namespace
+ klass = Thor::Util.find_by_namespace('')
end
+ return klass, command
end
- end
+ alias find_class_and_task_by_namespace find_class_and_command_by_namespace
+
+ # Receives a path and load the thor file in the path. The file is evaluated
+ # inside the sandbox to avoid namespacing conflicts.
+ #
+ def load_thorfile(path, content=nil, debug=false)
+ content ||= File.binread(path)
- def self.user_home
- @@user_home ||= if ENV["HOME"]
- ENV["HOME"]
- elsif ENV["USERPROFILE"]
- ENV["USERPROFILE"]
- elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
- File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"])
- elsif ENV["APPDATA"]
- ENV["APPDATA"]
- else
begin
- File.expand_path("~")
- rescue
- if File::ALT_SEPARATOR
- "C:/"
+ Thor::Sandbox.class_eval(content, path)
+ rescue Exception => e
+ $stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}")
+ if debug
+ $stderr.puts(*e.backtrace)
else
- "/"
+ $stderr.puts(e.backtrace.first)
end
end
end
- end
- # Returns the root where thor files are located, depending on the OS.
- #
- def self.thor_root
- File.join(user_home, ".thor").gsub(/\\/, '/')
- end
+ def user_home
+ @@user_home ||= if ENV["HOME"]
+ ENV["HOME"]
+ elsif ENV["USERPROFILE"]
+ ENV["USERPROFILE"]
+ elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
+ File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"])
+ elsif ENV["APPDATA"]
+ ENV["APPDATA"]
+ else
+ begin
+ File.expand_path("~")
+ rescue
+ if File::ALT_SEPARATOR
+ "C:/"
+ else
+ "/"
+ end
+ end
+ end
+ end
+
+ # Returns the root where thor files are located, depending on the OS.
+ #
+ def thor_root
+ File.join(user_home, ".thor").gsub(/\\/, '/')
+ end
- # Returns the files in the thor root. On Windows thor_root will be something
- # like this:
- #
- # C:\Documents and Settings\james\.thor
- #
- # If we don't #gsub the \ character, Dir.glob will fail.
- #
- def self.thor_root_glob
- files = Dir["#{escape_globs(thor_root)}/*"]
+ # Returns the files in the thor root. On Windows thor_root will be something
+ # like this:
+ #
+ # C:\Documents and Settings\james\.thor
+ #
+ # If we don't #gsub the \ character, Dir.glob will fail.
+ #
+ def thor_root_glob
+ files = Dir["#{escape_globs(thor_root)}/*"]
- files.map! do |file|
- File.directory?(file) ? File.join(file, "main.thor") : file
+ files.map! do |file|
+ File.directory?(file) ? File.join(file, "main.thor") : file
+ end
end
- end
- # Where to look for Thor files.
- #
- def self.globs_for(path)
- path = escape_globs(path)
- ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
- end
+ # Where to look for Thor files.
+ #
+ def globs_for(path)
+ path = escape_globs(path)
+ ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
+ end
- # Return the path to the ruby interpreter taking into account multiple
- # installations and windows extensions.
- #
- def self.ruby_command
- @ruby_command ||= begin
- ruby_name = RbConfig::CONFIG['ruby_install_name']
- ruby = File.join(RbConfig::CONFIG['bindir'], ruby_name)
- ruby << RbConfig::CONFIG['EXEEXT']
+ # Return the path to the ruby interpreter taking into account multiple
+ # installations and windows extensions.
+ #
+ def ruby_command
+ @ruby_command ||= begin
+ ruby_name = RbConfig::CONFIG['ruby_install_name']
+ ruby = File.join(RbConfig::CONFIG['bindir'], ruby_name)
+ ruby << RbConfig::CONFIG['EXEEXT']
- # avoid using different name than ruby (on platforms supporting links)
- if ruby_name != 'ruby' && File.respond_to?(:readlink)
- begin
- alternate_ruby = File.join(RbConfig::CONFIG['bindir'], 'ruby')
- alternate_ruby << RbConfig::CONFIG['EXEEXT']
+ # avoid using different name than ruby (on platforms supporting links)
+ if ruby_name != 'ruby' && File.respond_to?(:readlink)
+ begin
+ alternate_ruby = File.join(RbConfig::CONFIG['bindir'], 'ruby')
+ alternate_ruby << RbConfig::CONFIG['EXEEXT']
- # ruby is a symlink
- if File.symlink? alternate_ruby
- linked_ruby = File.readlink alternate_ruby
+ # ruby is a symlink
+ if File.symlink? alternate_ruby
+ linked_ruby = File.readlink alternate_ruby
- # symlink points to 'ruby_install_name'
- ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
+ # symlink points to 'ruby_install_name'
+ ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
+ end
+ rescue NotImplementedError
+ # just ignore on windows
end
- rescue NotImplementedError
- # just ignore on windows
end
+
+ # escape string in case path to ruby executable contain spaces.
+ ruby.sub!(/.*\s.*/m, '"\&"')
+ ruby
end
+ end
- # escape string in case path to ruby executable contain spaces.
- ruby.sub!(/.*\s.*/m, '"\&"')
- ruby
+ # Returns a string that has had any glob characters escaped.
+ # The glob characters are `* ? { } [ ]`.
+ #
+ # ==== Examples
+ #
+ # Thor::Util.escape_globs('[apps]') # => '\[apps\]'
+ #
+ # ==== Parameters
+ # String
+ #
+ # ==== Returns
+ # String
+ #
+ def escape_globs(path)
+ path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
end
- end
- # Returns a string that has had any glob characters escaped.
- # The glob characters are `* ? { } [ ]`.
- #
- # ==== Examples
- #
- # Thor::Util.escape_globs('[apps]') # => '\[apps\]'
- #
- # ==== Parameters
- # String
- #
- # ==== Returns
- # String
- #
- def self.escape_globs(path)
- path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
end
-
end
end
View
8 spec/actions/directory_spec.rb
@@ -56,15 +56,15 @@ def exists_and_identical?(source_path, destination_path)
end
it "copies only the first level files if recursive" do
- invoke! ".", "tasks", :recursive => false
+ invoke! ".", "commands", :recursive => false
- file = File.join(destination_root, "tasks", "group.thor")
+ file = File.join(destination_root, "commands", "group.thor")
expect(File.exists?(file)).to be_true
- file = File.join(destination_root, "tasks", "doc")
+ file = File.join(destination_root, "commands", "doc")
expect(File.exists?(file)).to be_false
- file = File.join(destination_root, "tasks", "doc", "README")
+ file = File.join(destination_root, "commands", "doc", "README")
expect(File.exists?(file)).to be_false
end
View
24 spec/actions/file_manipulation_spec.rb
@@ -52,13 +52,13 @@ def file
describe "#copy_file" do
it "copies file from source to default destination" do
- action :copy_file, "task.thor"
- exists_and_identical?("task.thor", "task.thor")
+ action :copy_file, "command.thor"
+ exists_and_identical?("command.thor", "command.thor")
end
it "copies file from source to the specified destination" do
- action :copy_file, "task.thor", "foo.thor"
- exists_and_identical?("task.thor", "foo.thor")
+ action :copy_file, "command.thor", "foo.thor"
+ exists_and_identical?("command.thor", "foo.thor")
end
it "copies file from the source relative to the current path" do
@@ -76,26 +76,26 @@ def file
end
it "logs status" do
- expect(action(:copy_file, "task.thor")).to eq(" create task.thor\n")
+ expect(action(:copy_file, "command.thor")).to eq(" create command.thor\n")
end
it "accepts a block to change output" do
- action :copy_file, "task.thor" do |content|
+ action :copy_file, "command.thor" do |content|
"OMG" + content
end
- expect(File.read(File.join(destination_root, "task.thor"))).to match(/^OMG/)
+ expect(File.read(File.join(destination_root, "command.thor"))).to match(/^OMG/)
end
end
describe "#link_file" do
it "links file from source to default destination" do
- action :link_file, "task.thor"
- exists_and_identical?("task.thor", "task.thor")
+ action :link_file, "command.thor"
+ exists_and_identical?("command.thor", "command.thor")
end
it "links file from source to the specified destination" do
- action :link_file, "task.thor", "foo.thor"
- exists_and_identical?("task.thor", "foo.thor")
+ action :link_file, "command.thor", "foo.thor"
+ exists_and_identical?("command.thor", "foo.thor")
end
it "links file from the source relative to the current path" do
@@ -106,7 +106,7 @@ def file
end
it "logs status" do
- expect(action(:link_file, "task.thor")).to eq(" create task.thor\n")
+ expect(action(:link_file, "command.thor")).to eq(" create command.thor\n")
end
end
View
42 spec/base_spec.rb
@@ -45,10 +45,10 @@ def hello
end
end
- describe "#no_tasks" do
- it "avoids methods being added as tasks" do
- expect(MyScript.tasks.keys).to include("animal")
- expect(MyScript.tasks.keys).not_to include("this_is_not_a_task")
+ describe "#no_commands" do
+ it "avoids methods being added as commands" do
+ expect(MyScript.commands.keys).to include("animal")
+ expect(MyScript.commands.keys).not_to include("this_is_not_a_command")
end
end
@@ -198,37 +198,37 @@ def hello
end
it "tracks a single subclass across multiple files" do
- thorfile = File.join(File.dirname(__FILE__), "fixtures", "task.thor")
+ thorfile = File.join(File.dirname(__FILE__), "fixtures", "command.thor")
expect(Thor::Base.subclass_files[File.expand_path(thorfile)]).to include(Amazing)
expect(Thor::Base.subclass_files[File.expand_path(__FILE__)]).to include(Amazing)
end
end
- describe "#tasks" do
- it "returns a list with all tasks defined in this class" do
+ describe "#commands" do
+ it "returns a list with all commands defined in this class" do
expect(MyChildScript.new).to respond_to("animal")
- expect(MyChildScript.tasks.keys).to include("animal")
+ expect(MyChildScript.commands.keys).to include("animal")
end
- it "raises an error if a task with reserved word is defined" do