0
@@ -3,8 +3,25 @@ require "open-uri"
0
+ # Array[Class]:: All the classes in the object space.
0
+ ObjectSpace.each_object(Class) {|o| klasses << o}
0
def self.constant_to_thor_path(str)
0
snake_case(str).squeeze(":")
0
@@ -15,12 +32,19 @@ class Thor::Util
0
make_constant(to_constant(str))
0
def self.to_constant(str)
0
str.gsub(/:(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
0
+ def self.constants_in_contents(str)
0
+ klasses = self.constants.dup
0
+ ret = self.constants - klasses
0
+ ret.each {|k| self.send(:remove_const, k)}
0
def self.make_constant(str)
0
@@ -44,37 +68,57 @@ class Thor::Runner < Thor
0
["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
0
- def initialize_thorfiles
0
- thorfiles.each {|f| load f unless Thor.subclass_files.keys.include?(File.expand_path(f))}
0
+ def initialize_thorfiles(include_system = true)
0
+ thorfiles(include_system).each {|f| load f unless Thor.subclass_files.keys.include?(File.expand_path(f))}
0
map "-T" => :list, "-i" => :install, "-u" => :update
0
- desc "install NAME [AS]", "install a Thor file into your system tasks, optionally named for future updates"
0
- def install(name, as = name)
0
+ desc "install NAME", "install a Thor file into your system tasks, optionally named for future updates"
0
+ method_options :as => :optional
0
+ def install(name, opts)
0
contents = open(name).read
0
rescue OpenURI::HTTPError
0
puts "The URI you provided: `#{name}' was invalid"
0
puts "`#{name}' is not a valid file"
0
+ puts "Your Thorfile contains: "
0
+ print "Do you wish to continue [y/N]? "
0
+ response = Readline.readline
0
+ return unless response =~ /^\s*y/i
0
+ constants = Thor::Util.constants_in_contents(contents)
0
name = name =~ /\.thor$/ ? name : "#{name}.thor"
0
- thor_root = File.join(ENV["HOME"], ".thor")
0
+ as = opts["as"] || begin
0
+ first_line = contents.split("\n")[0]
0
+ (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil
0
+ print "Please specify a name for #{name} in the system repository [#{name}]: "
0
+ as = Readline.readline
0
+ as = name if as.empty?
0
FileUtils.mkdir_p thor_root
0
yaml_file = File.join(thor_root, "thor.yml")
0
FileUtils.touch(yaml_file)
0
- yaml =
YAML.load_file(yaml_file) || {}0
- yaml[as] = {:filename => Digest::MD5.hexdigest(name
), :location => name}
0
+ yaml[as] = {:filename => Digest::MD5.hexdigest(name
+ as), :location => name, :constants => constants}
0
- File.open(yaml_file, "w") do |file|
0
- file.puts yaml.to_yaml
0
puts "Storing thor file in your system repository"
0
@@ -83,28 +127,43 @@ class Thor::Runner < Thor
0
+ desc "uninstall NAME", "uninstall a named Thor module"
0
+ puts "There was no module by that name installed"
0
+ puts "Uninstalling #{name}."
0
+ file = File.join(thor_root, "#{yaml[name][:filename]}.thor")
0
desc "update NAME", "update a Thor file from its original location"
0
- thor_root = File.join(ENV["HOME"], ".thor")
0
- yaml_file = File.join(thor_root, "thor.yml")
0
- yaml = YAML.load_file(yaml_file) || {}
0
if !yaml[name] || !yaml[name][:location]
0
puts "`#{name}' was not found in the system repository"
0
puts "Updating `#{name}' from #{yaml[name][:location]}"
0
- install(yaml[name][:location],
name)
0
+ install(yaml[name][:location],
"as" => name)
0
- Dir["#{ENV["HOME"]}/.thor/**/*.thor"].each do |f|
0
+ Dir["#{ENV["HOME"]}/.thor/**/*.thor"].each do |f|
0
load f unless Thor.subclass_files.keys.include?(File.expand_path(f))
0
desc "list [SEARCH]", "list the available thor tasks"
0
- method_options :force => :boolean
0
search = /.*#{search}.*/
0
@@ -113,7 +172,7 @@ class Thor::Runner < Thor
0
def method_missing(meth, *args)
0
+ initialize_thorfiles
(false)0
puts "Thor tasks must contain a :"
0
@@ -122,19 +181,30 @@ class Thor::Runner < Thor
0
thor_klass = meth.split(":")[0...-1].join(":")
0
to_call = meth.split(":").last
0
+ thor_root = File.join(ENV["HOME"], ".thor")
0
+ yaml_file = File.join(thor_root, "thor.yml")
0
+ yaml = YAML.load_file(yaml_file) || {}
0
+ klass_str = Thor::Util.to_constant(thor_klass)
0
+ files = yaml.inject([]) { |a,(k,v)| a << v[:filename] if v[:constants].include?(klass_str); a }
0
+ load File.join(thor_root, "#{f}.thor")
0
klass = Thor::Util.constant_from_thor_path(thor_klass)
0
puts "There was no available namespace `#{thor_klass}'."
0
unless klass.ancestors.include?(Thor)
0
puts "`#{thor_klass}' is not a Thor module"
0
- ARGV.replace [to_call, *args].compact
0
+ ARGV.replace [to_call, *(args + ARGV)].compact
0
@@ -145,8 +215,48 @@ class Thor::Runner < Thor
0
- klasses = Thor.subclasses.reject {|x| x == Thor::Runner}
0
+ File.join(ENV["HOME"], ".thor")
0
+ yaml_file = File.join(thor_root, "thor.yml")
0
+ YAML.load_file(yaml_file) || {}
0
+ yaml_file = File.join(thor_root, "thor.yml")
0
+ File.open(yaml_file, "w") {|f| f.puts yaml.to_yaml }
0
+ def display_klasses(with_modules = false)
0
+ klasses = Thor.subclasses - [Thor::Runner]
0
+ puts "No thorfiles available"
0
+ max_name = yaml.max {|(xk,xv),(yk,yv)| xk.size <=> yk.size }.first.size
0
+ print "%-#{max_name + 4}s" % "Name"
0
+ print "%-#{max_name + 4}s" % "----"
0
+ yaml.each do |name, info|
0
+ print "%-#{max_name + 4}s" % name
0
+ puts info[:constants].map {|c| Thor::Util.constant_to_thor_path(c)}.join(", ")
0
# Calculate the largest base class name
0
max_base = klasses.max do |x,y|
0
Thor::Util.constant_to_thor_path(x.name).size <=> Thor::Util.constant_to_thor_path(y.name).size
0
@@ -188,7 +298,7 @@ class Thor::Runner < Thor
0
+ def thorfiles
(include_system = true)0
system_thorfiles = Dir["#{ENV["HOME"]}/.thor/**/*.thor"]
0
@@ -199,7 +309,7 @@ class Thor::Runner < Thor
0
path = File.dirname(path)
0
- thorfiles +
system_thorfiles0
+ thorfiles +
(include_system ? system_thorfiles : [])
Comments
No one has commented yet.