123456789_123456789_123456789_123456789_123456789_

Class: Bundler::Thor::Runner

Do not use. This class is for internal use only.
Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: Bundler::Thor
Defined in: lib/bundler/vendor/thor/lib/thor/runner.rb

Overview

rubocop:disable ClassLength

Constant Summary

::Bundler::Thor - Inherited

AmbiguousTaskError, DynamicTask, HELP_MAPPINGS, HiddenTask, TEMPLATE_EXTNAME, THOR_RESERVED_WORDS, Task, UndefinedTaskError, VERSION

Class Attribute Summary

Class Method Summary

::Bundler::Thor - Inherited

.check_unknown_options!

Extend check unknown options to accept a hash of conditions.

.command_help

Prints help information for the given command.

.default_command

Sets the default command when thor is executed without an explicit command to be called.

.default_task

Alias for default_command.

.desc

Defines the usage and the description of the next command.

.disable_required_check!

Disable the check for required options for the given commands.

.help

Prints help information for this class.

.long_desc

Defines the long description of the next command.

.map

Maps an input to a command.

.method_option

Adds an option to the set of method options.

.method_options

Declares the options for the next command to be declared.

.option

Alias for method_option.

.options

Alias for method_options.

.package_name

Allows for custom “Command” package naming.

.printable_commands

Returns commands ready to be printed.

.printable_tasks
.register

Registers another ::Bundler::Thor subclass as a command.

.stop_on_unknown_option!

Stop parsing of options as soon as an unknown option or a regular argument is encountered.

.subcommand, .subcommand_classes, .subcommands,
.subtask

Alias for subcommand.

.subtasks

Alias for subcommands.

.task_help

Alias for command_help.

.banner

The banner for this class.

.create_task

Alias for create_command.

.find_command_possibilities

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.

.find_task_possibilities
.normalize_task_name
.retrieve_task_name
.subcommand_help,
.subtask_help

Alias for subcommand_help.

.check_unknown_options?

Overwrite check_unknown_options? to take subcommands and options into account.

.disable_required_check?, .stop_on_unknown_option?, .baseclass, .create_command,
.disable_required_check

help command has the required check disabled by default.

.dispatch

The method responsible for dispatching given the args.

.dynamic_command_class, .initialize_added,
.normalize_command_name

receives a (possibly nil) command name and returns a name that is in the commands hash.

.retrieve_command_name

Retrieve the command name from given args.

.stop_on_unknown_option

Instance Attribute Summary

Instance Method Summary

::Bundler::Thor - Inherited

Base - Included

#initialize

It receives arguments in an Array and two hashes, one for options and other for configuration.

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args)

If a command is not found on Runner, method missing is invoked and Runner is then responsible for finding the command in all classes.

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 36

def method_missing(meth, *args)
  meth = meth.to_s
  initialize_thorfiles(meth)
  klass, command = Bundler::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 => shell)
end

Class Attribute Details

.exit_on_failure?Boolean (readonly)

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 16

def self.exit_on_failure?
  true
end

Class Method Details

Instance Method Details

#display_commands(namespace, list) (private) Also known as: #display_tasks

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 299

def display_commands(namespace, list) #:nodoc:
  list.sort! { |a, b| a[0] <=> b[0] }

  say shell.set_color(namespace, :blue, true)
  say "-" * namespace.size

  print_table(list, :truncate => true)
  say
end

#display_klasses(with_modules = false, show_internal = false, klasses = Bundler::Thor::Base.subclasses) (private)

Display information about the given klasses. If with_module is given, it shows a table with information extracted from the yaml file.

Raises:

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 278

def display_klasses(with_modules = false, show_internal = false, klasses = Bundler::Thor::Base.subclasses)
  klasses -= [Bundler::Thor, Bundler::Thor::Runner, Bundler::Thor::Group] unless show_internal

  raise Error, "No Bundler::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?(Bundler::Thor::Group) }

  # Get classes which inherit from Bundler::Thor
  (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) }

  # Get classes which inherit from Bundler::Thor::Base
  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, commands| display_commands(n, commands) unless commands.empty? }
end

#display_tasks(namespace, list) (private)

Alias for #display_commands.

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 308

alias_method :display_tasks, :display_commands

#help(meth = nil)

Override Bundler::Thor#help so it can give information about any class and any method.

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 22

def help(meth = nil)
  if meth && !respond_to?(meth)
    initialize_thorfiles(meth)
    klass, command = Bundler::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 => shell)
  else
    super
  end
end

#initialize_thorfiles(relevant_to = nil, skip_lookup = false) (private)

Load the Bundler::Thorfiles. If relevant_to is supplied, looks for specific files in the thor_root instead of loading them all.

By default, it also traverses the current path until find ::Bundler::Thor files, as described in thorfiles. This look up can be skipped by supplying skip_lookup true.

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 214

def initialize_thorfiles(relevant_to = nil, skip_lookup = false)
  thorfiles(relevant_to, skip_lookup).each do |f|
    Bundler::Thor::Util.load_thorfile(f, nil, options[:debug]) unless Bundler::Thor::Base.subclass_files.keys.include?(File.expand_path(f))
  end
end

#install(name)

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 47

def install(name) # rubocop:disable MethodLength
  initialize_thorfiles

  # If a directory name is provided as the argument, look for a 'main.thor'
  # command in said directory.
  begin
    if File.directory?(File.expand_path(name))
      base = File.join(name, "main.thor")
      package = :directory
      contents = open(base, &:read)
    else
      base = name
      package = :file
      contents = open(name, &:read)
    end
  rescue OpenURI::HTTPError
    raise Error, "Error opening URI '#{name}'"
  rescue Errno::ENOENT
    raise Error, "Error opening file '#{name}'"
  end

  say "Your Bundler::Thorfile contains:"
  say contents

  unless options["force"]
    return false if no?("Do you wish to continue [y/N]?")
  end

  as = options["as"] || begin
    first_line = contents.split("\n")[0]
    (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil
  end

  unless as
    basename = File.basename(name)
    as = ask("Please specify a name for #{name} in the system repository [#{basename}]:")
    as = basename if as.empty?
  end

  location = if options[:relative] || name =~ %r{^https?://}
    name
  else
    File.expand_path(name)
  end

  thor_yaml[as] = {
    :filename   => Digest(:MD5).hexdigest(name + as),
    :location   => location,
    :namespaces => Bundler::Thor::Util.namespaces_in_content(contents, base)
  }

  save_yaml(thor_yaml)
  say "Storing thor file in your system repository"
  destination = File.join(thor_root, thor_yaml[as][:filename])

  if package == :file
    File.open(destination, "w") { |f| f.puts contents }
  else
    require "fileutils"
    FileUtils.cp_r(name, destination)
  end

  thor_yaml[as][:filename] # Indicate success
end

#installed

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 157

def installed
  initialize_thorfiles(nil, true)
  display_klasses(true, options["internal"])
end

#list(search = "")

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 164

def list(search = "")
  initialize_thorfiles

  search = ".*#{search}" if options["substring"]
  search = /^#{search}.*/i
  group  = options[:group] || "standard"

  klasses = Bundler::Thor::Base.subclasses.select do |k|
    (options[:all] || k.group == group) && k.namespace =~ search
  end

  display_klasses(false, false, klasses)
end

#save_yaml(yaml) (private)

Save the yaml file. If none exists in thor root, creates one.

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 194

def save_yaml(yaml)
  yaml_file = File.join(thor_root, "thor.yml")

  unless File.exist?(yaml_file)
    require "fileutils"
    FileUtils.mkdir_p(thor_root)
    yaml_file = File.join(thor_root, "thor.yml")
    FileUtils.touch(yaml_file)
  end

  File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml }
end

#show_modules (private)

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 310

def show_modules #:nodoc:
  info = []
  labels = %w(Modules Namespaces)

  info << labels
  info << ["-" * labels[0].size, "-" * labels[1].size]

  thor_yaml.each do |name, hash|
    info << [name, hash[:namespaces].join(", ")]
  end

  print_table info
  say ""
end

#thor_root (private)

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 180

def thor_root
  Bundler::Thor::Util.thor_root
end

#thor_yaml (private)

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 184

def thor_yaml
  @thor_yaml ||= begin
    yaml_file = File.join(thor_root, "thor.yml")
    yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file)
    yaml || {}
  end
end

#thorfiles(relevant_to = nil, skip_lookup = false) (private)

Finds Bundler::Thorfiles by traversing from your current directory down to the root directory of your system. If at any time we find a ::Bundler::Thor file, we stop.

We also ensure that system-wide Bundler::Thorfiles are loaded first, so local Bundler::Thorfiles can override them.

Example

If we start at /Users/wycats/dev/thor …

  1. /Users/wycats/dev/thor

  2. /Users/wycats/dev

  3. /Users/wycats <– we find a Bundler::Thorfile here, so we stop

Suppose we start at c:Documents and Settingsjamesdevthor …

  1. c:Documents and Settingsjamesdevthor

  2. c:Documents and Settingsjamesdev

  3. c:Documents and Settingsjames

  4. c:Documents and ::Bundler::Settings

  5. c:\ <– no Bundler::Thorfiles found!

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 242

def thorfiles(relevant_to = nil, skip_lookup = false)
  thorfiles = []

  unless skip_lookup
    Pathname.pwd.ascend do |path|
      thorfiles = Bundler::Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten
      break unless thorfiles.empty?
    end
  end

  files  = (relevant_to ? thorfiles_relevant_to(relevant_to) : Bundler::Thor::Util.thor_root_glob)
  files += thorfiles
  files -= ["#{thor_root}/thor.yml"]

  files.map! do |file|
    File.directory?(file) ? File.join(file, "main.thor") : file
  end
end

#thorfiles_relevant_to(meth) (private)

Load Bundler::Thorfiles relevant to the given method. If you provide “foo:bar” it will load all thor files in the thor.yaml that has “foo” e “foo:bar” namespaces registered.

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 265

def thorfiles_relevant_to(meth)
  lookup = [meth, meth.split(":")[0...-1].join(":")]

  files = thor_yaml.select do |_, v|
    v[:namespaces] && !(v[:namespaces] & lookup).empty?
  end

  files.map { |_, v| File.join(thor_root, (v[:filename]).to_s) }
end

#uninstall(name)

Raises:

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 119

def uninstall(name)
  raise Error, "Can't find module '#{name}'" unless thor_yaml[name]
  say "Uninstalling #{name}."
  require "fileutils"
  FileUtils.rm_rf(File.join(thor_root, (thor_yaml[name][:filename]).to_s))

  thor_yaml.delete(name)
  save_yaml(thor_yaml)

  puts "Done."
end

#update(name)

Raises:

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 132

def update(name)
  raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location]

  say "Updating '#{name}' from #{thor_yaml[name][:location]}"

  old_filename = thor_yaml[name][:filename]
  self.options = options.merge("as" => name)

  if File.directory? File.expand_path(name)
    require "fileutils"
    FileUtils.rm_rf(File.join(thor_root, old_filename))

    thor_yaml.delete(old_filename)
    save_yaml(thor_yaml)

    filename = install(name)
  else
    filename = install(thor_yaml[name][:location])
  end

  File.delete(File.join(thor_root, old_filename)) unless filename == old_filename
end

#version

[ GitHub ]

  
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 113

def version
  require "bundler/vendor/thor/lib/thor/version"
  say "Bundler::Thor #{Bundler::Thor::VERSION}"
end