This module holds several utilities:
1) Methods to convert thor namespaces to constants and vice-versa.
Bundler::Thor::Util.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz"
2) Loading thor files and sandboxing:
Bundler::Thor::Util.load_thorfile("~/.thor/foo")
Receives a string and convert it to camel case. camel_case
returns CamelCase.
String
String
# File bundler/vendor/thor/lib/thor/util.rb, line 104 def camel_case(str) return str if str !~ /_/ && str =~ /[A-Z]+.*/ str.split("_").map(&:capitalize).join end
Returns a string that has had any glob characters escaped. The glob characters are `* ? { } [ ]`.
Bundler::Thor::Util.escape_globs('[apps]') # => '\[apps\]'
String
String
# File bundler/vendor/thor/lib/thor/util.rb, line 263 def escape_globs(path) path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&') end
Receives a namespace and search for it in the Bundler::Thor::Base
subclasses.
The namespace to search for.
# File bundler/vendor/thor/lib/thor/util.rb, line 24 def find_by_namespace(namespace) namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/ Bundler::Thor::Base.subclasses.detect { |klass| klass.namespace == namespace } end
Receives a namespace and tries to retrieve a Bundler::Thor or Bundler::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.
class Foo::Bar < Bundler::Thor def baz end end class Baz::Foo < Bundler::Thor::Group end Bundler::Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default command Bundler::Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil Bundler::Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz"
namespace<String>
# File bundler/vendor/thor/lib/thor/util.rb, line 131 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 = Bundler::Thor::Util.find_by_namespace(pieces.join(":")) end unless klass # look for a Bundler::Thor::Group with the right name klass = Bundler::Thor::Util.find_by_namespace(namespace) command = nil end if !klass && fallback # try a command in the default namespace command = namespace klass = Bundler::Thor::Util.find_by_namespace("") end [klass, command] end
Where to look for Bundler::Thor files.
# File bundler/vendor/thor/lib/thor/util.rb, line 212 def globs_for(path) path = escape_globs(path) ["#{path}/Bundler::Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"] end
Receives a path and load the thor file in the path. The file is evaluated inside the sandbox to avoid namespacing conflicts.
# File bundler/vendor/thor/lib/thor/util.rb, line 152 def load_thorfile(path, content = nil, debug = false) content ||= File.binread(path) begin Bundler::Thor::Sandbox.class_eval(content, path) rescue StandardError => 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
Receives a constant and converts it to a Bundler::Thor namespace. Since Bundler::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 Bundler::Thor. On current versions, if you need to get the namespace from a class, just call namespace on it.
The constant to be converted to the thor path.
If we receive Foo::Bar::Baz it returns “foo:bar:baz”
# File bundler/vendor/thor/lib/thor/util.rb, line 43 def namespace_from_thor_class(constant) constant = constant.to_s.gsub(/^Bundler::Thor::Sandbox::/, "") constant = snake_case(constant).squeeze(":") constant end
Given the contents, evaluate it inside the sandbox and returns the namespaces defined in the sandbox.
contents<String>
# File bundler/vendor/thor/lib/thor/util.rb, line 58 def namespaces_in_content(contents, file = __FILE__) old_constants = Bundler::Thor::Base.subclasses.dup Bundler::Thor::Base.subclasses.clear load_thorfile(file, contents) new_constants = Bundler::Thor::Base.subclasses.dup Bundler::Thor::Base.subclasses.replace(old_constants) new_constants.map!(&:namespace) new_constants.compact! new_constants end
Return the path to the ruby interpreter taking into account multiple installations and windows extensions.
# File bundler/vendor/thor/lib/thor/util.rb, line 220 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"] # 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 end rescue NotImplementedError # rubocop:disable HandleExceptions # just ignore on windows end end # escape string in case path to ruby executable contain spaces. ruby.sub!(/.*\s.*/m, '"\&"') ruby end end
Returns the thor classes declared inside the given class.
# File bundler/vendor/thor/lib/thor/util.rb, line 74 def thor_classes_in(klass) stringfied_constants = klass.constants.map(&:to_s) Bundler::Thor::Base.subclasses.select do |subclass| next unless subclass.name stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", "")) end end
Returns the root where thor files are located, depending on the OS.
# File bundler/vendor/thor/lib/thor/util.rb, line 191 def thor_root File.join(user_home, ".thor").tr('\\', "/") 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.
# File bundler/vendor/thor/lib/thor/util.rb, line 202 def thor_root_glob files = Dir["#{escape_globs(thor_root)}/*"] files.map! do |file| File.directory?(file) ? File.join(file, "main.thor") : file end end
# File bundler/vendor/thor/lib/thor/util.rb, line 167 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