[PATCH v2 43/44] ruby: add simpler option parser

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Felipe Contreras <felipe.contreras@xxxxxxxxx>
---

Notes:
    We could use Git's internap parseopt, but the resulting code in Ruby wouldn't
    look very good, and the complexity to bind it wouldn't be trivial either (I
    tried).
    
    Instead, let's use the advantage of Ruby blocks to set the variables to their
    right values and try to keep the code simple, and add more features as they are
    needed later on.

 git-rb-setup.rb  |  75 ++++++++++++++++++++++++++++++++
 t/t10000-ruby.sh | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 203 insertions(+)

diff --git a/git-rb-setup.rb b/git-rb-setup.rb
index 6f283da..cd2502f 100644
--- a/git-rb-setup.rb
+++ b/git-rb-setup.rb
@@ -32,3 +32,78 @@ class String
     return self[prefix.length..-1]
   end
 end
+
+class ParseOpt
+  attr_writer :usage
+
+  class Option
+    attr_reader :short, :long, :help
+
+    def initialize(short, long, help, &block)
+      @block = block
+      @short = short
+      @long = long
+      @help = help
+    end
+
+    def call(v)
+      @block.call(v)
+    end
+  end
+
+  def initialize
+    @list = {}
+  end
+
+  def on(short = nil, long = nil, help: nil, &block)
+    opt = Option.new(short, long, help, &block)
+    @list[short] = opt if short
+    @list[long] = opt if long
+  end
+
+  def parse
+    if ARGV.member?('-h') or ARGV.member?('--help')
+      usage
+      exit 0
+    end
+    seen_dash = false
+    ARGV.delete_if do |cur|
+      opt = val = nil
+      next false if cur[0] != '-' or seen_dash
+      case cur
+      when '--'
+        seen_dash = true
+        next true
+      when /^--no-(.+)$/
+        opt = @list[$1]
+        val = false
+      when /^-([^-])(.+)?$/, /^--(.+?)(?:=(.+))?$/
+        opt = @list[$1]
+        val = $2 || true
+      end
+      if opt
+        opt.call(val)
+        true
+      else
+        usage
+        exit 1
+      end
+    end
+  end
+
+  def usage
+    def fmt(prefix, str)
+      return str ? prefix + str : nil
+    end
+    puts 'usage: %s' % @usage
+    @list.values.uniq.each do |opt|
+      s = '    '
+      s << ''
+      s << [fmt('-', opt.short), fmt('--', opt.long)].compact.join(', ')
+      s << ''
+      s << '%*s%s' % [26 - s.size, '', opt.help] if opt.help
+      puts s
+    end
+  end
+
+end
diff --git a/t/t10000-ruby.sh b/t/t10000-ruby.sh
index e5a397c..a365849 100755
--- a/t/t10000-ruby.sh
+++ b/t/t10000-ruby.sh
@@ -102,4 +102,132 @@ test_expect_success 'test Commit' '
 	test_cmp expected actual
 '
 
+test_expect_success 'test ParseOpt' '
+	cat > parse-script <<"EOF"
+	$str = "default"
+	$num = 0
+	$bool = false
+
+	opts = ParseOpt.new
+	opts.usage = "git foo"
+
+	opts.on("b", "bool", help: "Boolean") do |v|
+	  $bool = v
+	end
+
+	opts.on("s", "string", help: "String") do |v|
+	  $str = v
+	end
+
+	opts.on("n", "number", help: "Number") do |v|
+	  $num = v.to_i
+	end
+
+	opts.parse
+
+	p(ARGV)
+	p({ :bool => $bool, :str => $str, :num => $num })
+	EOF
+
+	git ruby parse-script > actual &&
+	cat > expected <<-EOF &&
+	[]
+	{:bool=>false, :str=>"default", :num=>0}
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script --bool > actual &&
+	cat > expected <<-EOF &&
+	[]
+	{:bool=>true, :str=>"default", :num=>0}
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script -b > actual &&
+	cat > expected <<-EOF &&
+	[]
+	{:bool=>true, :str=>"default", :num=>0}
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script --string=foo > actual &&
+	cat > expected <<-EOF &&
+	[]
+	{:bool=>false, :str=>"foo", :num=>0}
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script -sfoo > actual &&
+	cat > expected <<-EOF &&
+	[]
+	{:bool=>false, :str=>"foo", :num=>0}
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script --number=10 > actual &&
+	cat > expected <<-EOF &&
+	[]
+	{:bool=>false, :str=>"default", :num=>10}
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script --bool --string=bar --number=-20 > actual &&
+	cat > expected <<-EOF &&
+	[]
+	{:bool=>true, :str=>"bar", :num=>-20}
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script --help > actual &&
+	cat > expected <<-EOF &&
+	usage: git foo
+	    -b, --bool            Boolean
+	    -s, --string          String
+	    -n, --number          Number
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script --help > actual &&
+	cat > expected <<-EOF &&
+	usage: git foo
+	    -b, --bool            Boolean
+	    -s, --string          String
+	    -n, --number          Number
+	EOF
+	test_cmp expected actual &&
+
+	test_must_fail git ruby parse-script --bad > actual &&
+	cat > expected <<-EOF &&
+	usage: git foo
+	    -b, --bool            Boolean
+	    -s, --string          String
+	    -n, --number          Number
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script one --bool two --string=bar three --number=-20 mambo > actual &&
+	cat > expected <<-EOF &&
+	["one", "two", "three", "mambo"]
+	{:bool=>true, :str=>"bar", :num=>-20}
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script one --bool two -- --three four > actual &&
+	cat > expected <<-EOF &&
+	["one", "two", "--three", "four"]
+	{:bool=>true, :str=>"default", :num=>0}
+	EOF
+	test_cmp expected actual &&
+
+	git ruby parse-script one --bool --no-bool > actual &&
+	cat > expected <<-EOF &&
+	["one"]
+	{:bool=>false, :str=>"default", :num=>0}
+	EOF
+	cat actual
+	test_cmp expected actual &&
+
+	true
+'
+
 test_done
-- 
1.8.4-fc

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]