Class: Bundler::Thor::Runner
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
::Bundler::Thor
|
|
Instance Chain:
self,
::Bundler::Thor ,
Base
|
|
Inherits: |
Bundler::Thor
|
Defined in: | lib/bundler/vendor/thor/lib/thor/runner.rb |
Constant Summary
::Bundler::Thor
- Inherited
AmbiguousTaskError, Correctable, DynamicTask, HELP_MAPPINGS, HiddenTask, TEMPLATE_EXTNAME, THOR_RESERVED_WORDS, Task, UndefinedTaskError, VERSION
Class Attribute Summary
- .exit_on_failure? ⇒ Boolean readonly
Class Method Summary
::Bundler::Thor
- Inherited
.at_least_one | Alias for method_at_least_one. |
.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. |
.exclusive | Alias for method_exclusive. |
.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_at_least_one | Adds and declares option group for required at least one of options in the block of arguments. |
.method_exclusive | Adds and declares option group for exclusive options in the block and arguments. |
.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 | Alias for printable_commands. |
.register | Registers another |
.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 | Alias for find_command_possibilities. |
.normalize_task_name | Alias for normalize_command_name. |
.retrieve_task_name | Alias for retrieve_command_name. |
.sort_commands! | Sort the commands, lexicographically by default. |
.subcommand_help, | |
.subtask_help | Alias for subcommand_help. |
.check_unknown_options? | Overwrite check_unknown_options? to take subcommands and options into account. |
.command_exists? | Checks if a specified command exists. |
.deprecation_warning, .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, | |
.method_at_least_one_option_names | Returns this class at least one of required options array set. |
.method_exclusive_option_names | Returns this class exclusive options array set. |
.normalize_command_name | receives a (possibly nil) command name and returns a name that is in the commands hash. |
.print_at_least_one_required_options, .print_exclusive_options, | |
.retrieve_command_name | Retrieve the command name from given args. |
.stop_on_unknown_option |
Instance Attribute Summary
Base
- Included
Instance Method Summary
-
#help(meth = nil)
Override #help so it can give information about any class and any method.
- #install(name)
- #installed
- #list(search = "")
-
#method_missing(meth, *args)
If a command is not found on
Runner
, method missing is invoked andRunner
is then responsible for finding the command in all classes. - #uninstall(name)
- #update(name)
- #version
- #display_commands(namespace, list) (also: #display_tasks) private
-
#display_klasses(with_modules = false, show_internal = false, klasses = Bundler::Thor::Base.subclasses)
private
Display information about the given klasses.
-
#display_tasks(namespace, list)
private
Alias for #display_commands.
-
#initialize_thorfiles(relevant_to = nil, skip_lookup = false)
private
Load the Thorfiles.
-
#save_yaml(yaml)
private
Save the yaml file.
- #show_modules private
- #thor_root private
- #thor_yaml private
-
#thorfiles(relevant_to = nil, skip_lookup = false)
private
Finds Thorfiles by traversing from your current directory down to the root directory of your system.
-
#thorfiles_relevant_to(meth)
private
Load Thorfiles relevant to the given method.
::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.
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 35
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 15
def self.exit_on_failure? true end
Class Method Details
.banner(command, all = false, subcommand = false)
[ GitHub ]# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 11
def self. (command, all = false, subcommand = false) "thor " + command.formatted_usage(self, all, subcommand) end
Instance Method Details
#display_commands(namespace, list) (private) Also known as: #display_tasks
[ GitHub ]#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.
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 289
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.
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 319
alias_method :display_tasks, :display_commands
#help(meth = nil)
Override Bundler::Thor#help so it can give information about any class and any method.
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 21
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 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.
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 225
def initialize_thorfiles(relevant_to = nil, skip_lookup = false) thorfiles(relevant_to, skip_lookup).each do |f| Bundler::Thor::Util.load_thorfile(f, nil, [:debug]) unless Bundler::Thor::Base.subclass_files.keys.include?(File. (f)) end end
#install(name)
[ GitHub ]# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 46
def install(name) # rubocop:disable Metrics/MethodLength initialize_thorfiles is_uri = name =~ %r{^https?\://} if is_uri base = name package = :file require "open-uri" begin contents = URI.open(name, &:read) rescue OpenURI::HTTPError raise Error, "Error opening URI '#{name}'" end else # If a directory name is provided as the argument, look for a 'main.thor' # command in said directory. begin if File.directory?(File. (name)) base = File.join(name, "main.thor") package = :directory contents = File.open(base, &:read) else base = name package = :file require "open-uri" contents = URI.open(name, &:read) end rescue Errno::ENOENT raise Error, "Error opening file '#{name}'" end end say "Your Thorfile contains:" say contents unless ["force"] return false if no?("Do you wish to continue [y/N]?") end as = ["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 [:relative] || is_uri name else File. (name) end thor_yaml[as] = { filename: Digest::SHA256.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 168
def installed initialize_thorfiles(nil, true) display_klasses(true, ["internal"]) end
#list(search = "")
[ GitHub ]# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 175
def list(search = "") initialize_thorfiles search = ".*#{search}" if ["substring"] search = /^#{search}.*/i group = [:group] || "standard" klasses = Bundler::Thor::Base.subclasses.select do |k| ( [: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.
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 205
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 321
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 ]#thor_yaml (private)
[ GitHub ]# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 195
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 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 Thorfiles are loaded first, so local Thorfiles can override them.
Example
If we start at /Users/wycats/dev/thor …
-
/Users/wycats/dev/thor
-
/Users/wycats/dev
-
/Users/wycats <– we find a Thorfile here, so we stop
Suppose we start at c:Documents and Settingsjamesdevthor …
-
c:Documents and Settingsjamesdevthor
-
c:Documents and Settingsjamesdev
-
c:Documents and Settingsjames
-
c:Documents and
::Bundler::Settings
-
c:\ <– no Thorfiles found!
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 253
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 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.
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 276
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)
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 130
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)
# File 'lib/bundler/vendor/thor/lib/thor/runner.rb', line 143
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. = .merge("as" => name) if File.directory? File. (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