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.convert_constants_to_namespaces(yaml)
TrueClass|FalseClass:: Returns true if any change to the yaml file was made.
==== Returns
TODO Deprecate this method in the future.
This was added to deal with deprecated versions of Thor.
Receives a yaml (hash) and updates all constants entries to namespace.
def self.convert_constants_to_namespaces(yaml) yaml_changed = false yaml.each do |k, v| next unless v[:constants] && v[:namespaces].nil? yaml_changed = true yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.namespace_from_thor_class(c)} end yaml_changed 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 do |klass| klass.namespace == namespace end 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)
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) content ||= File.read(path) begin Thor::Sandbox.class_eval(content, path) rescue Exception => e $stderr.puts "WARNING: unable to load thorfile #{path.inspect}: #{e.message}" end end
def self.namespace_from_thor_class(constant, remove_default=true)
String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz"
==== Returns
constant
def self.namespace_from_thor_class(constant, remove_default=true) constant = constant.to_s.gsub(/^Thor::Sandbox::/, "") constant = snake_case(constant).squeeze(":") constant.gsub!(/^default/, '') if remove_default constant end
def self.namespace_to_thor_class_and_task(namespace, raise_if_nil=true)
inherit from Thor or Thor::Group.
Thor::Error:: raised if the namespace evals to a class which does not
Thor::Error:: raised if the namespace cannot be found.
==== Errors
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.namespace_to_thor_class_and_task(namespace, raise_if_nil=true) klass, task_name = Thor::Util.find_by_namespace(namespace), nil if klass.nil? && namespace.include?(?:) namespace = namespace.split(":") task_name = namespace.pop klass = Thor::Util.find_by_namespace(namespace.join(":")) end raise Error, "could not find Thor class or task '#{namespace}'" if raise_if_nil && klass.nil? return klass, task_name 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 = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) ruby << Config::CONFIG['EXEEXT'] # 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) Thor::Base.subclasses.select do |subclass| klass.constants.include?(subclass.name.gsub("#{klass.name}::", '')) end end
def self.thor_root
Returns the root where thor files are located, dependending on the OS.
def self.thor_root File.join(user_home, ".thor") 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.gsub(/\\/, '/')}/*"] 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