Browse files

Change name to thor. Last commit to hermes repo.

  • Loading branch information...
1 parent 331ca5e commit 82ff27a67d7fa1078c231bb52b71cbd9b3e0fb37 @wycats wycats committed May 7, 2008
Showing with 152 additions and 97 deletions.
  1. +2 −2 README.markdown
  2. +13 −3 Rakefile
  3. 0 bin/thor
  4. +0 −87 lib/hermes.rb
  5. +92 −0 lib/thor.rb
  6. +45 −5 spec/{hermes_spec.rb → thor_spec.rb}
View
4 README.markdown
@@ -1,5 +1,5 @@
-hermes
-======
+thor
+====
Map options to a class. Simply create a class with the appropriate annotations, and have options automatically map
to functions and parameters.
View
16 Rakefile
@@ -1,10 +1,11 @@
require 'rubygems'
require 'rake/gempackagetask'
require 'rubygems/specification'
+require 'spec/rake/spectask'
require 'date'
-GEM = "hermes"
-GEM_VERSION = "0.9.0"
+GEM = "thor"
+GEM_VERSION = "0.9.1"
AUTHOR = "Yehuda Katz"
EMAIL = "wycats@gmail.com"
HOMEPAGE = "http://yehudakatz.com"
@@ -34,9 +35,18 @@ Rake::GemPackageTask.new(spec) do |pkg|
pkg.gem_spec = spec
end
+task :default => :spec
+desc "Run the specs"
+Spec::Rake::SpecTask.new do |t|
+ t.libs << "spec"
+ t.spec_files = FileList["spec/**/*_spec.rb"]
+ t.spec_opts << "-fs --color"
+end
+
+
desc "install the gem locally"
task :install => [:package] do
- sh %{sudo gem install pkg/#{GEM}-#{VERSION}}
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
end
desc "create a gemspec file"
View
0 bin/thor
No changes.
View
87 lib/hermes.rb
@@ -1,87 +0,0 @@
-require "#{File.dirname(__FILE__)}/getopt"
-
-module Hermes
- def self.extended(klass)
- klass.class_eval <<-RUBY, "class_cli.rb", 6
-
- def self.method_added(meth)
- return if !public_instance_methods.include?(meth.to_s) || !@@usage
- @@descriptions = defined?(@@descriptions) ? @@descriptions : []
- @@usages = defined?(@@usages) ? @@usages : []
- @@opts = defined?(@@opts) ? @@opts : []
- @@descriptions << [meth.to_s, @@desc]
- @@usages << [meth.to_s, @@usage]
- if defined?(@@method_options) && @@method_options
- @@opts << [meth.to_s, @@method_options]
- end
- @@usage, @@desc, @@method_options = nil
- end
-
- def self.map(map)
- @@map = map
- end
-
- def self.desc(usage, description)
- @@usage, @@desc = usage, description
- end
-
- 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.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
- 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
- new(meth, params).instance_variable_get("@results")
- end
-
- def initialize(op, params)
- @results = send(op.to_sym, *params) if public_methods.include?(op)
- end
-
- private
- def format_opts(opts)
- return "" unless 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
-
- public
- desc "help", "show this screen"
- def help
- puts "Options"
- puts "-------"
- 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
- @@usages.each do |meth, usage|
- format = "%-" + (max_usage + max_opts + 4).to_s + "s"
- print format % (@@usages.assoc(meth)[1] + (@@opts.assoc(meth) ? " " + format_opts(@@opts.assoc(meth)[1]) : ""))
- # print format % (@@usages.assoc(meth)[1] + @@opts.assoc(meth) ? format_opts(@@opts.assoc(meth)[1]) : ""))
- puts @@descriptions.assoc(meth)[1]
- end
- end
- RUBY
- end
-end
View
92 lib/thor.rb
@@ -0,0 +1,92 @@
+require "#{File.dirname(__FILE__)}/getopt"
+
+class Thor
+ def self.method_added(meth)
+ return if !public_instance_methods.include?(meth.to_s) || !@usage
+ @descriptions ||= []
+ @usages ||= []
+ @opts ||= []
+ @descriptions << [meth.to_s, @desc]
+ @usages << [meth.to_s, @usage]
+ @opts << [meth.to_s, @method_options] if @method_options
+ @usage, @desc, @method_options = nil
+ end
+
+ def self.map(map)
+ @map = map
+ end
+
+ def self.desc(usage, description)
+ @usage, @desc = usage, description
+ end
+
+ 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.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
+ 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
+ new(meth, params).instance_variable_get("@results")
+ end
+
+ def thor_usages
+ self.class.instance_variable_get("@usages")
+ end
+
+ def thor_descriptions
+ self.class.instance_variable_get("@descriptions")
+ end
+
+ def thor_opts
+ self.class.instance_variable_get("@opts")
+ end
+
+
+ def initialize(op, params)
+ @results = send(op.to_sym, *params) if public_methods.include?(op)
+ end
+
+ private
+ def format_opts(opts)
+ return "" unless 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
+
+ public
+ desc "help", "show this screen"
+ def help
+ puts "Options"
+ puts "-------"
+ max_usage = thor_usages.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size
+ max_opts = thor_opts.empty? ? 0 : format_opts(thor_opts.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last).size
+ max_desc = thor_descriptions.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size
+ thor_usages.each do |meth, usage|
+ format = "%-" + (max_usage + max_opts + 4).to_s + "s"
+ print format % (thor_usages.assoc(meth)[1] + (thor_opts.assoc(meth) ? " " + format_opts(thor_opts.assoc(meth)[1]) : ""))
+ puts thor_descriptions.assoc(meth)[1]
+ end
+ end
+end
View
50 spec/hermes_spec.rb → spec/thor_spec.rb
@@ -1,8 +1,28 @@
require File.dirname(__FILE__) + '/spec_helper'
-require "hermes"
+require "thor"
-class MyApp
- extend Hermes
+class StdOutCapturer
+ attr_reader :output
+
+ def initialize
+ @output = ""
+ end
+
+ def self.call_func
+ old_out = $stdout
+ output = new
+ $stdout = output
+ yield
+ $stdout = old_out
+ output.output
+ end
+
+ def write(s)
+ @output += s
+ end
+end
+
+class MyApp < Thor
map "-T" => :animal
@@ -35,7 +55,7 @@ def baz(bat, opts)
end
end
-describe "hermes" do
+describe "thor" do
it "calls a no-param method when no params are passed" do
ARGV.replace ["zoo"]
MyApp.start.should == true
@@ -83,6 +103,26 @@ def baz(bat, opts)
it "calls a method with an empty Hash for options if an optional key/value param is not provided" do
ARGV.replace ["baz", "one"]
- MyApp.start.should == ["one", {}]
+ MyApp.start.should == ["one", {}]
end
+
+ it "provides useful help info for a simple method" do
+ StdOutCapturer.call_func { ARGV.replace ["help"]; MyApp.start }.should =~ /zoo +zoo around/
+ end
+
+ it "provides useful help info for a method with one param" do
+ StdOutCapturer.call_func { ARGV.replace ["help"]; MyApp.start }.should =~ /animal TYPE +horse around/
+ end
+
+ it "provides useful help info for a method with boolean options" do
+ StdOutCapturer.call_func { ARGV.replace ["help"]; MyApp.start }.should =~ /foo BAR \-\-force +do some fooing/
+ end
+
+ it "provides useful help info for a method with required options" do
+ StdOutCapturer.call_func { ARGV.replace ["help"]; MyApp.start }.should =~ /bar BAZ BAT \-\-option1=OPTION1 +do some barring/
+ end
+
+ it "provides useful help info for a method with optional options" do
+ StdOutCapturer.call_func { ARGV.replace ["help"]; MyApp.start }.should =~ /baz BAT \[\-\-option1=OPTION1\] +do some bazzing/
+ end
end

1 comment on commit 82ff27a

@mtodd

You forgot to change the example to extend Thor instead of Hermes.

Please sign in to comment.