class Thor
def self.convert_task_options(opts)
def self.convert_task_options(opts) opts.map do |key, value| if value == true "--#{key}" elsif value.is_a?(Array) value.map {|v| "--#{key} #{v.inspect}"}.join(" ") else "--#{key} #{value.inspect}" end end.join(" ") end
def self.desc(usage, description)
def self.desc(usage, description) @usage, @desc = usage, description end
def self.format_opts(opts)
def self.format_opts(opts) return "" if !opts opts.map do |opt, val| if val == true || val == "BOOLEAN" "[#{opt}]" elsif val == "REQUIRED" opt + "=" + opt.gsub(/\-/, "").upcase elsif val == "OPTIONAL" "[" + opt + "=" + opt.gsub(/\-/, "").upcase + "]" end end.join(" ") end
def self.help_list
def self.help_list return nil unless @usages @help_list ||= begin max_usage = @usages.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size max_opts = @opts.empty? ? 0 : format_opts(@opts.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last).size max_desc = @descriptions.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size Struct.new(:klass, :usages, :opts, :descriptions, :max).new( self, @usages, @opts, @descriptions, Struct.new(:usage, :opt, :desc).new(max_usage, max_opts, max_desc) ) end end
def self.inherited(klass)
def self.inherited(klass) subclass_files[File.expand_path(caller[0].split(":")[0])] << klass subclasses << klass unless subclasses.include?(klass) end
def self.install_task
def self.install_task package_task self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 desc "install", "install the gem" def install old_stderr, $stderr = $stderr.dup, File.open("/dev/null", "w") package $stderr = old_stderr system %{sudo gem install pkg/#{GEM}-#{GEM_VERSION} --no-rdoc --no-ri --no-update-sources} end RUBY end
def self.map(map)
def self.map(map) @map ||= superclass.instance_variable_get("@map") || {} @map.merge! map end
def self.method_added(meth)
def self.method_added(meth) meth = meth.to_s return if !public_instance_methods.include?(meth) || !@usage @descriptions ||= [] @usages ||= [] @opts ||= [] @descriptions.delete(@descriptions.assoc(meth)) @descriptions << [meth, @desc] @usages.delete(@usages.assoc(meth)) @usages << [meth, @usage] @opts.delete(@opts.assoc(meth)) @opts << [meth, @method_options] if @method_options @usage, @desc, @method_options = nil end
def self.method_options(opts)
def self.method_options(opts) @method_options = opts.inject({}) do |accum, (k,v)| accum.merge("--" + k.to_s => v.to_s.upcase) end end
def self.package_task
def self.package_task self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 desc "package", "package up the gem" def package FileUtils.mkdir_p(File.join(Dir.pwd, "pkg")) Gem::Builder.new(SPEC).build FileUtils.mv(SPEC.file_name, File.join(Dir.pwd, "pkg", SPEC.file_name)) end RUBY end
def self.spec_task(file_list, opts = {})
def self.spec_task(file_list, opts = {}) name = opts.delete(:name) || "spec" rcov_dir = opts.delete(:rcov_dir) || "coverage" file_list = file_list.map {|f| %["#{f}"]}.join(" ") verbose = opts.delete(:verbose) opts = {:format => "specdoc", :color => true}.merge(opts) rcov_opts = convert_task_options(opts.delete(:rcov) || {}) rcov = !rcov_opts.empty? options = convert_task_options(opts) if rcov FileUtils.rm_rf(File.join(Dir.pwd, rcov_dir)) end self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 desc("#{name}", "spec task") def #{name} cmd = "ruby " if #{rcov.inspect} cmd << "-S rcov -o #{rcov_dir} #{rcov_opts.inspect[1...-1]} " end cmd << `which spec`.chomp cmd << " -- " if #{rcov.inspect} cmd << " " cmd << #{file_list.inspect} cmd << " " cmd << #{options.inspect} puts cmd if #{verbose.inspect} system(cmd) end RUBY end
def self.start
def self.start meth = ARGV.shift params = [] while !ARGV.empty? break if ARGV.first =~ /^\-/ params << ARGV.shift end if defined?(@map) && @map[meth] meth = @map[meth].to_s end args = ARGV.dup if @opts.assoc(meth) opts = @opts.assoc(meth).last.map {|opt, val| [opt, val == true ? Getopt::BOOLEAN : Getopt.const_get(val)].flatten} options = Getopt::Long.getopts(*opts) params << options end ARGV.replace args new(meth, params).instance_variable_get("@results") end
def self.subclass_files
def self.subclass_files @subclass_files ||= Hash.new {|h,k| h[k] = []} end
def self.subclasses
def self.subclasses @subclasses ||= [] end
def help
def help list = self.class.help_list puts "Options" puts "-------" list.usages.each do |meth, use| format = "%-" + (list.max.usage + list.max.opt + 4).to_s + "s" print format % ("#{usage(meth)}") puts list.descriptions.assoc(meth)[1] end end
def initialize(op, params)
def initialize(op, params) begin op ||= "help" @results = send(op.to_sym, *params) if public_methods.include?(op) || !methods.include?(op) rescue ArgumentError puts "`#{op}' was called incorrectly. Call as `#{usage(op)}'" end end
def usage(meth)
def usage(meth) list = self.class.help_list list.usages.assoc(meth)[1] + (list.opts.assoc(meth) ? " " + self.class.format_opts(list.opts.assoc(meth)[1]) : "") end