module Thor::Util
def self.camel_case(str)
String
==== Returns
String
==== Parameters
Receives a string and convert it to camel case. camel_case returns CamelCase.
def self.camel_case(str) return str if str !~ /_/ && str =~ /[A-Z]+.*/ str.split('_').map { |i| i.capitalize }.join end
def self.find_by_namespace(namespace)
namespace
==== Parameters
Receives a namespace and search for it in the Thor::Base subclasses.
def self.find_by_namespace(namespace) namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/ Thor::Base.subclasses.find { |klass| klass.namespace == namespace } end
def self.find_class_and_task_by_namespace(namespace, fallback = true)
namespace
==== Parameters
Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz"
Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil
Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default task
end
class Baz::Foo < Thor::Group
end
end
def baz
class Foo::Bar < Thor
==== Examples
again. If found, returns the highest entry as the class name.
if it's not found, removes the highest entry and searches for the class
from it. It first searches for a class using the all the given namespace,
Receives a namespace and tries to retrieve a Thor or Thor::Group class
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 end if !klass && fallback # try a task in the default namespace task = namespace klass = Thor::Util.find_by_namespace('') end return klass, task end
def self.globs_for(path)
Where to look for Thor files.
def self.globs_for(path) ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"] end
def self.load_thorfile(path, content=nil, debug=false)
inside the sandbox to avoid namespacing conflicts.
Receives a path and load the thor file in the path. The file is evaluated
def self.load_thorfile(path, content=nil, debug=false) content ||= File.binread(path) 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) end end end
def self.namespace_from_thor_class(constant)
String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz"
==== Returns
constant
def self.namespace_from_thor_class(constant) constant = constant.to_s.gsub(/^Thor::Sandbox::/, "") constant = snake_case(constant).squeeze(":") constant end
def self.namespaces_in_content(contents, file=__FILE__)
Array[Object]
==== Returns
contents
==== Parameters
namespaces defined in the sandbox.
Given the contents, evaluate it inside the sandbox and returns the
def self.namespaces_in_content(contents, file=__FILE__) old_constants = Thor::Base.subclasses.dup Thor::Base.subclasses.clear load_thorfile(file, contents) new_constants = Thor::Base.subclasses.dup Thor::Base.subclasses.replace(old_constants) new_constants.map!{ |c| c.namespace } new_constants.compact! new_constants end
def self.ruby_command
installations and windows extensions.
Return the path to the ruby interpreter taking into account multiple
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'] # 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 # just ignore on windows end end # escape string in case path to ruby executable contain spaces. ruby.sub!(/.*\s.*/m, '"\&"') ruby end end
def self.snake_case(str)
String
==== Returns
String
==== Parameters
Receives a string and convert it to snake case. SnakeCase returns snake_case.
def self.snake_case(str) return str.downcase if str =~ /^[A-Z_]+$/ str.gsub(/\B[A-Z]/, '_\&').squeeze('_') =~ /_*(.*)/ return $+.downcase end
def self.thor_classes_in(klass)
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}::", '')) end end
def self.thor_root
Returns the root where thor files are located, depending on the OS.
def self.thor_root File.join(user_home, ".thor").gsub(/\\/, '/') end
def self.thor_root_glob
If we don't #gsub the \ character, Dir.glob will fail.
C:\Documents and Settings\james\.thor
like this:
Returns the files in the thor root. On Windows thor_root will be something
def self.thor_root_glob files = Dir["#{thor_root}/*"] files.map! do |file| File.directory?(file) ? File.join(file, "main.thor") : file end end
def self.user_home
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:/" else "/" end end end end