clive 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,2 @@
1
+ lib/**/*.rb
2
+ bin/*
data/.gitignore ADDED
@@ -0,0 +1,25 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ .yardoc
23
+ doc
24
+ ideas.rb
25
+ research
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Joshua Hawxwell
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # clive
2
+
3
+ Clive is a DSL for creating a command line interface. It is for people who, like me, love [OptionParser's](http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html) syntax and love [GLI's](http://github.com/davetron5000/gli) commands.
4
+
5
+ ## Install
6
+
7
+ Install with:
8
+
9
+ (sudo) gem install clive
10
+
11
+
12
+ ## How To
13
+
14
+ A simple example to start:
15
+
16
+ require 'clive'
17
+
18
+ opts = {}
19
+ c = Clive.new do
20
+ switch(:v, :verbose, "Run verbosely") {opts[:verbose] = true}
21
+ end
22
+ c.parse(ARGV)
23
+ p opts
24
+
25
+ This creates a very simple interface which can have one switch, you can then use the long or short form to call the block.
26
+
27
+ my_file -v
28
+ #=> {:verbose => true}
29
+ my_file --verbose
30
+ #=> {:verbose => true}
31
+
32
+
33
+ ### Switches
34
+
35
+ As we've seen above switches are created using #switch. You can provide as little information as you want. `switch(:v) {}` creates a switch that responds only to `-v`, or `switch(:verbose) {}` creates a switch that only responds to `--verbose`.
36
+
37
+ ### Flags
38
+
39
+ Flags are like switches but also take an argument:
40
+
41
+ c = Clive.new do
42
+ flag(:p, :print, "Print the argument") do |i|
43
+ p i
44
+ end
45
+ end
46
+ c.parse(ARGV)
47
+
48
+ ####
49
+
50
+ my_file --print=hello
51
+ #=> "hello"
52
+ my_file --print equalsless
53
+ #=> "equalsless"
54
+ my_file -p short
55
+ #=> "short"
56
+
57
+ The argument is then passed into the block. As you can see you can use short, long, equals, or no equals to call flags. As with switches you can call `flag(:p) {|i| ...}` which responds to `-p ...`, `flag(:print) {|i| ...}` which responds to `--print ...` or `--print=...`.
58
+
59
+ ### Commands
60
+
61
+ Commands work like in git, here's an example:
62
+
63
+ opts = {}
64
+ c = Clive.new do
65
+ command(:add) do
66
+ opts[:add] = {}
67
+ flag(:r, :require, "Require a library") {|i| opts[:add][:lib] = i}
68
+ end
69
+ end
70
+ c.parse(ARGV)
71
+ p opts
72
+
73
+ ####
74
+
75
+ my_file add -r Clive
76
+ #=> {:add => {:lib => "Clive"}}
77
+
78
+ Commands make it easy to group flags, switches and even other commands. The block for the command is executed on finding the command, this allows you to put other code within the block specific for the command, as shown above.
79
+
80
+
81
+ ### Arguments
82
+
83
+ Anything that isn't a command, switch or flag is taken as an argument. These are returned by #parse as an array.
84
+
85
+ opts = {}
86
+ c = Clive.new do
87
+ flag(:size) {|i| opts[:size] = i}
88
+ end
89
+ args = c.parse(ARGV)
90
+ p args
91
+
92
+ ####
93
+
94
+ my_file --size big /usr/bin
95
+ #=> ["/usr/bin"]
96
+
97
+ ### Putting It All Together
98
+
99
+ require 'clive'
100
+
101
+ opts = {}
102
+ c = Clive.new do
103
+ switch(:v, :verbose, "Run verbosely") {opts[:verbose] = true}
104
+
105
+ command(:add, "Add a new project")) do
106
+ opts[:add] = {}
107
+
108
+ switch(:force, "Force overwrite") {opts[:add][:force] = true}
109
+ flag(:framework, "Add framework") do |i|
110
+ opts[:add][:framework] ||= []
111
+ opts[:add][:framework] << i
112
+ end
113
+
114
+ command(:init, "Initialize the project after creating") do
115
+ switch(:m, :minimum, "Use minimum settings") {opts[:add][:min] = true}
116
+ flag(:width) {|i| opts[:add][:width] = i.to_i}
117
+ end
118
+
119
+ end
120
+
121
+ switch(:version, "Show version") do
122
+ puts "1.0.0"
123
+ exit
124
+ end
125
+ end
126
+ args = c.parse(ARGV)
127
+ p opts
128
+ p args
129
+
130
+ ####
131
+
132
+ my_file --version
133
+ #=> 1.0.0
134
+ my_file -v add --framework=blueprint init -m -w 200 ~/Desktop/new_thing ~/Desktop/another_thing
135
+ #=> {:verbose => true, :add => {:framework => ["blueprint"], :min => true, :width => 200}}
136
+ #=> ["~/Desktop/new_thing", "~/Desktop/another_thing"]
137
+
138
+ ## Note on Patches/Pull Requests
139
+
140
+ * Fork the project.
141
+ * Make your feature addition or bug fix.
142
+ * Add tests for it. This is important so I don't break it in a
143
+ future version unintentionally.
144
+ * Commit, do not mess with rakefile, version, or history.
145
+ (if you want to have your own version, that is fine but bump version in a commit by itself so I can ignore when I pull)
146
+ * Send me a pull request. Bonus points for topic branches.
147
+
148
+ ## Copyright
149
+
150
+ Copyright (c) 2010 Joshua Hawxwell. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "clive"
8
+ gem.summary = %Q{Imagine if optparse and gli had a son called clive.}
9
+ gem.description = %Q{Clive is a DSL for creating a command line interface. It is for people who, like me, love OptionParser's syntax and love GLI's commands.}
10
+ gem.email = "m@hawx.me"
11
+ gem.homepage = "http://github.com/hawx/clive"
12
+ gem.authors = ["Joshua Hawxwell"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ gem.add_development_dependency "yard", ">= 0"
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/test_*.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+ task :test => :check_dependencies
43
+
44
+ task :default => :test
45
+
46
+ begin
47
+ require 'yard'
48
+ YARD::Rake::YardocTask.new
49
+ rescue LoadError
50
+ task :yardoc do
51
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
52
+ end
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/clive.rb ADDED
@@ -0,0 +1,45 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require 'clive/tokens'
4
+ require 'clive/ext'
5
+ require 'clive/switches'
6
+ require 'clive/flags'
7
+ require 'clive/commands'
8
+
9
+ # Clive is a simple dsl for creating command line interfaces
10
+ #
11
+ # @example Simple Example
12
+ #
13
+ # opts = {}
14
+ # c = Clive.new do
15
+ # switch(:v, :verbose, "Run verbosely") {
16
+ # opts[:verbose] = true
17
+ # }
18
+ # end
19
+ # c.parse(ARGV)
20
+ #
21
+ class Clive
22
+
23
+ attr_accessor :base
24
+
25
+ def initialize(&block)
26
+ @base = Command.new(true, &block)
27
+ end
28
+
29
+ def parse(argv)
30
+ @base.run(argv)
31
+ end
32
+
33
+ def switches
34
+ @base.switches
35
+ end
36
+
37
+ def commands
38
+ @base.commands
39
+ end
40
+
41
+ def flags
42
+ @base.flags
43
+ end
44
+
45
+ end
@@ -0,0 +1,224 @@
1
+ class Clive
2
+
3
+ # A string which describes the command to execute
4
+ # eg. git add
5
+ # git pull
6
+ #
7
+ class Command
8
+
9
+ attr_accessor :switches, :flags, :commands
10
+ attr_accessor :name, :desc, :block, :argv
11
+ attr_accessor :base
12
+
13
+ # Create a new Command instance
14
+ #
15
+ # @overload initialize(base, &block)
16
+ # Creates a new base Command to house everything else
17
+ # @param [Boolean] base whether the command is the base
18
+ #
19
+ # @overload initialize(name, desc, &block)
20
+ # Creates a new Command as part of the base Command
21
+ # @param [Symbol] name the name of the command
22
+ # @param [String] desc the description of the command
23
+ #
24
+ # @yield A block to run, containing switches, flags and commands
25
+ #
26
+ def initialize(*args, &block)
27
+ @argv = []
28
+ @switches = Clive::Array.new
29
+ @flags = Clive::Array.new
30
+ @commands = Clive::Array.new
31
+
32
+ if args.length == 1 && args[0] == true
33
+ @base = true
34
+ self.instance_eval(&block)
35
+ else
36
+ @base = false
37
+ args.each do |i|
38
+ case i
39
+ when Symbol
40
+ @name = i.to_s
41
+ when String
42
+ @desc = i
43
+ end
44
+ end
45
+ @block = block
46
+ end
47
+ end
48
+
49
+ # Run the block that was passed to find switches, flags, etc.
50
+ #
51
+ # This should only be called if the command has been called
52
+ # as the block could contain other actions to perform only
53
+ # when called.
54
+ #
55
+ def find
56
+ return nil if @base
57
+ self.instance_eval(&@block)
58
+ end
59
+
60
+ # Parse the ARGV passed from the command line, and run
61
+ #
62
+ # @param [Array] argv the command line input, usually just ARGV
63
+ # @return [Array] any arguments that were present in the input but not used
64
+ #
65
+ def run(argv)
66
+ tokens = argv
67
+ tokens = tokenize(argv) if @base
68
+
69
+ r = []
70
+ tokens.each do |i|
71
+ k, v = i[0], i[1]
72
+ case k
73
+ when :command
74
+ v.run(i[2])
75
+ when :switch
76
+ v.run
77
+ when :flag
78
+ v.run(i[2])
79
+ when :argument
80
+ r << v
81
+ end
82
+ end
83
+ r
84
+ end
85
+
86
+ # Turns the command line input into a series of tokens.
87
+ # It will only raise errors if this is the base command instance.
88
+ #
89
+ # @param [Array] argv the command line input
90
+ # @return [Array] a series of tokens
91
+ #
92
+ # @example
93
+ #
94
+ # c.tokenize(["add", "-al", "--verbose"])
95
+ # #=> [[:command, #<Clive::Command>, ...args...], [:switch, "a",
96
+ # #<Clive::Switch>], [:switch, "l", #<Clive::Switch>], [:switch,
97
+ # "verbose", #<Clive::Switch>]]
98
+ #
99
+ def tokenize(argv)
100
+ tokens = []
101
+ pre = Tokens.to_tokens(argv)
102
+ command = nil
103
+ @argv = argv unless @base
104
+
105
+ pre.each do |i|
106
+ k, v = i[0], i[1]
107
+ case k
108
+ when :word
109
+ if @commands[v]
110
+ command = @commands[v]
111
+ pre -= [[:word, v]]
112
+ end
113
+ end
114
+ end
115
+
116
+ if command
117
+ command.find
118
+ # tokenify the command
119
+ tokens << [:command, command, command.tokenize(Tokens.to_array(pre))]
120
+ pre = Tokens.to_tokens(command.argv)
121
+ end
122
+
123
+ pre.each do |i|
124
+ k, v = i[0], i[1]
125
+ case k
126
+ when :short, :long
127
+ if switch = @switches[v]
128
+ tokens << [:switch, switch]
129
+ pre -= [[k, v]] unless @base
130
+ elsif flag = @flags[v]
131
+ tokens << [:flag, flag]
132
+ pre -= [[k, v]] unless @base
133
+ else
134
+ raise "error, flag/switch '#{v}' does not exist" if @base
135
+ end
136
+ when :word
137
+ if tokens.last
138
+ case tokens.last[0]
139
+ when :flag
140
+ tokens.last[2] = v
141
+ else
142
+ tokens << [:argument, v] if @base
143
+ end
144
+ end
145
+ end
146
+ end
147
+ @argv = Tokens.to_array(pre)
148
+
149
+ tokens
150
+ end
151
+
152
+ #### CREATION HELPERS ####
153
+
154
+ # Add a new switch to +@switches+
155
+ #
156
+ # @overload switch(short, long, desc, &block)
157
+ # Creates a new switch
158
+ # @param [Symbol] short single character for short switch, eg. +:v+ => +-v+
159
+ # @param [Symbol] long longer switch to be used, eg. +:verbose+ => +--verbose+
160
+ # @param [String] desc the description for the switch
161
+ #
162
+ # @yield A block to run if the switch is triggered
163
+ #
164
+ def switch(*args, &block)
165
+ short, long, desc = nil, nil, nil
166
+ args.each do |i|
167
+ if i.is_a? String
168
+ desc = i
169
+ elsif i.length == 1
170
+ short = i.to_s
171
+ else
172
+ long = i.to_s
173
+ end
174
+ end
175
+ @switches << Switch.new(short, long, desc, &block)
176
+ end
177
+
178
+ # Add a new command to +@commands+
179
+ #
180
+ # @overload command(name, desc, &block)
181
+ # Creates a new command
182
+ # @param [Symbol] name the name of the command, eg. +:add+ for +git add+
183
+ # @param [String] desc description of the command
184
+ #
185
+ # @yield A block to run when the command is called, can contain switches
186
+ # and flags
187
+ #
188
+ def command(*args, &block)
189
+ name, desc = nil, nil
190
+ args.each do |i|
191
+ if i.is_a? String
192
+ desc = i
193
+ else
194
+ name = i
195
+ end
196
+ end
197
+ @commands << Command.new(name, desc, &block)
198
+ end
199
+
200
+ # Add a new flag to +@flags+
201
+ #
202
+ # @overload flag(short, long, desc, &block)
203
+ # Creates a new flag
204
+ # @param [Symbol] short single character for short flag, eg. +:t+ => +-t 10+
205
+ # @param [Symbol] long longer switch to be used, eg. +:tries+ => +--tries=10+
206
+ # @param [String] desc the description for the flag
207
+ #
208
+ # @yield [String] A block to be run if switch is triggered
209
+ def flag(*args, &block)
210
+ short, long, desc = nil, nil, nil
211
+ args.each do |i|
212
+ if i.is_a? String
213
+ desc = i
214
+ elsif i.length == 1
215
+ short = i.to_s
216
+ else
217
+ long = i.to_s
218
+ end
219
+ end
220
+ @flags << Flag.new(short, long, desc, &block)
221
+ end
222
+
223
+ end
224
+ end
data/lib/clive/ext.rb ADDED
@@ -0,0 +1,29 @@
1
+ class Clive
2
+
3
+ class Array < ::Array
4
+
5
+ # If passed a Symbol or String will get the item with that name,
6
+ # checks #long and #short if available or #name. Otherwise does
7
+ # what you expect of an Array (see Array#[])
8
+ #
9
+ # @param [Symbol, String, Integer, Range] val name or index of item to return
10
+ # @return the item that has been found
11
+ def [](val)
12
+ val = val.to_s if val.is_a? Symbol
13
+ if val.is_a? String
14
+ if self[0].respond_to?(:name)
15
+ self.find_all {|i| i.name == val}[0]
16
+ elsif self[0].respond_to?(:long)
17
+ if val.length == 1
18
+ self.find_all {|i| i.short == val}[0]
19
+ else
20
+ self.find_all {|i| i.long == val}[0]
21
+ end
22
+ end
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ class Clive
2
+
3
+ # A switch that takes an argument, with or without an equals
4
+ # eg. wget --tries=10
5
+ # wget -t 10
6
+ #
7
+ class Flag < Switch
8
+
9
+ # Runs the block that was given with an argument
10
+ #
11
+ # @param [String] arg argument to pass to the block
12
+ def run(arg)
13
+ @block.call(arg)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ class Clive
2
+
3
+ # A string that takes no argument, beginning with one or two dashes
4
+ # eg. ruby --version
5
+ # ruby -v
6
+ #
7
+ class Switch
8
+ attr_accessor :short, :long, :desc, :block
9
+
10
+ def initialize(short, long, desc, &block)
11
+ @short = short
12
+ @long = long
13
+ @desc = desc
14
+ @block = block
15
+ end
16
+
17
+ # Runs the block that was given
18
+ def run
19
+ @block.call
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,80 @@
1
+ class Clive
2
+
3
+ # A subclass of Array to allow the creation of arrays that look
4
+ # like:
5
+ #
6
+ # [[:word, 'Value'], [:long, 'verbose'], [:short, 'r']]
7
+ #
8
+ # And converting between these and ordinary arrays.
9
+ #
10
+ class Tokens < Array
11
+ attr_accessor :tokens, :array
12
+
13
+ def self.to_tokens(tokens)
14
+ Tokens.new.to_tokens(tokens)
15
+ end
16
+
17
+ def self.to_array(arr)
18
+ Tokens.new.to_array(arr)
19
+ end
20
+
21
+ # Turn into simple tokens that have been split up into logical parts
22
+ #
23
+ # @example
24
+ #
25
+ # a = Tokens.new
26
+ # a.to_tokens(["add", "-al", "--verbose"])
27
+ # #=> [[:word, "add"], [:short, "a"], [:short, "l"], [:long, "verbose"]]
28
+ #
29
+ def to_tokens(arr=@array)
30
+ @tokens = []
31
+ arr.each do |i|
32
+ if i[0..1] == "--"
33
+ if i.include?('=')
34
+ a, b = i[2..i.length].split('=')
35
+ @tokens << [:long, a] << [:word, b]
36
+ else
37
+ @tokens << [:long, i[2..i.length]]
38
+ end
39
+
40
+ elsif i[0] == "-"
41
+ i[1..i.length].split('').each do |j|
42
+ tokens << [:short, j]
43
+ end
44
+
45
+ else
46
+ @tokens << [:word, i]
47
+ end
48
+ end
49
+
50
+ @tokens
51
+ end
52
+
53
+ # Turn tokens back to a normal array
54
+ #
55
+ # @example
56
+ #
57
+ # a = Tokens.new
58
+ # a.to_array([[:word, "add"], [:short, "a"], [:short, "l"],
59
+ # [:long, "verbose"]])
60
+ # #=> ["add", "-al", "--verbose"]
61
+ #
62
+ def to_array(tokens=@tokens)
63
+ @array = []
64
+ tokens.each do |i|
65
+ k, v = i[0], i[1]
66
+ case k
67
+ when :long
68
+ @array << "--#{v}"
69
+ when :short
70
+ @array << "-#{v}"
71
+ when :word
72
+ @array << v
73
+ end
74
+ end
75
+
76
+ @array
77
+ end
78
+
79
+ end
80
+ end
data/test/bin_test ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'clive'
4
+
5
+ options = {}
6
+ c = Clive.new do
7
+
8
+ switch(:v, :verbose, "Run verbosely") {
9
+ options[:verbose] = true
10
+ }
11
+
12
+ flag(:t, :type, "Type to choose") {
13
+ p "hi"
14
+ }
15
+
16
+ flag(:long_only, "A flag with only a long") {}
17
+
18
+ command(:add, "Add something") {
19
+
20
+ p "adding stuff"
21
+
22
+ switch(:f, :full, "Use full") {
23
+ options[:full] = true
24
+ }
25
+
26
+ # Use with app-name add -e
27
+ switch(:e, :empty, "Use empty") {
28
+ options[:full] = false
29
+ }
30
+
31
+ }
32
+
33
+ end
34
+
35
+ c.parse(ARGV)
36
+ p options
37
+
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'clive'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,214 @@
1
+ require 'helper'
2
+
3
+ class TestClive < Test::Unit::TestCase
4
+
5
+ should "create flag" do
6
+ c = Clive.new do
7
+ flag(:v) {}
8
+ end
9
+ assert_equal 1, c.flags.length
10
+ assert_instance_of Clive::Flag, c.flags[0]
11
+ end
12
+
13
+ should "create switch" do
14
+ c = Clive.new do
15
+ switch(:v) {}
16
+ end
17
+ assert_equal 1, c.switches.length
18
+ assert_instance_of Clive::Switch, c.switches[0]
19
+ end
20
+
21
+ should "create command" do
22
+ c = Clive.new do
23
+ command(:add) {}
24
+ end
25
+ assert_equal 1, c.commands.length
26
+ assert_instance_of Clive::Command, c.commands[0]
27
+ end
28
+
29
+ context "When parsing input" do
30
+
31
+ should "recognise flags with equals" do
32
+ opts = {}
33
+ c = Clive.new do
34
+ flag(:type) {|i| opts[:type] = i}
35
+ end
36
+ c.parse(["--type=big"])
37
+ r = {:type => 'big'}
38
+ assert_equal r, opts
39
+ end
40
+
41
+ should "recognise flags without equals" do
42
+ opts = {}
43
+ c = Clive.new do
44
+ flag(:type) {|i| opts[:type] = i}
45
+ end
46
+ c.parse(["--type", "big"])
47
+ r = {:type => 'big'}
48
+ assert_equal r, opts
49
+ end
50
+
51
+ should "recongise short flags" do
52
+ opts = {}
53
+ c = Clive.new do
54
+ flag(:t) {|i| opts[:type] = i}
55
+ end
56
+ c.parse(["-t", "big"])
57
+ r = {:type => 'big'}
58
+ assert_equal r, opts
59
+ end
60
+
61
+ should "recognise multiple flags" do
62
+ opts = {}
63
+ c = Clive.new do
64
+ flag(:type) {|i| opts[:type] = i}
65
+ flag(:lang) {|i| opts[:lang] = i}
66
+ flag(:e) {|i| opts[:e] = i}
67
+ end
68
+ c.parse(["--type=big", "--lang", "eng", "-e", "true"])
69
+ r = {:type => 'big', :lang => 'eng', :e => 'true'}
70
+ assert_equal r, opts
71
+ end
72
+
73
+
74
+ should "recognise switches" do
75
+ opts = {}
76
+ c = Clive.new do
77
+ switch(:v, :verbose) {opts[:verbose] = true}
78
+ end
79
+ c.parse(["--verbose"])
80
+ r = {:verbose => true}
81
+ assert_equal r, opts
82
+ end
83
+
84
+ should "recognise short switches" do
85
+ opts = {}
86
+ c = Clive.new do
87
+ switch(:v, :verbose) {opts[:verbose] = true}
88
+ end
89
+ c.parse(["-v"])
90
+ r = {:verbose => true}
91
+ assert_equal r, opts
92
+ end
93
+
94
+ should "recognise multiple switches" do
95
+ opts = {}
96
+ c = Clive.new do
97
+ switch(:v, :verbose) {opts[:verbose] = true}
98
+ switch(:r, :recursive) {opts[:recursive] = true}
99
+ end
100
+ c.parse(["--verbose", "-r"])
101
+ r = {:verbose => true, :recursive => true}
102
+ assert_equal r, opts
103
+ end
104
+
105
+ should "recognise multiple combined short switches" do
106
+ opts = {}
107
+ c = Clive.new do
108
+ switch(:v, :verbose) {opts[:verbose] = true}
109
+ switch(:r, :recursive) {opts[:recursive] = true}
110
+ end
111
+ c.parse(["-vr"])
112
+ r = {:verbose => true, :recursive => true}
113
+ assert_equal r, opts
114
+ end
115
+
116
+
117
+ should "recognise commands" do
118
+ opts = {}
119
+ c = Clive.new do
120
+ command(:add) {opts[:add] = true}
121
+ end
122
+ c.parse(["add"])
123
+ r = {:add => true}
124
+ assert_equal r, opts
125
+ end
126
+
127
+ should "recognise flags and switches within commands" do
128
+ opts = {}
129
+ c = Clive.new do
130
+ command(:add) {
131
+ opts[:add] = true
132
+
133
+ switch(:v, :verbose) {opts[:verbose] = true}
134
+ flag(:type) {|i| opts[:type] = i}
135
+ }
136
+ end
137
+ c.parse(["add", "--verbose", "--type=big"])
138
+ r = {:add => true, :verbose => true, :type => "big"}
139
+ assert_equal r, opts
140
+ end
141
+
142
+
143
+ should "parse a mixture properly" do
144
+ opts = {}
145
+ c = Clive.new do
146
+ switch(:v) {opts[:v] = true}
147
+ flag(:h) {opts[:h] = true}
148
+ command(:add) {
149
+ switch(:full) {opts[:full] = true}
150
+ }
151
+ end
152
+ c.parse(["-v", "add", "--full"])
153
+ r = {:v => true, :full => true}
154
+ assert_equal r, opts
155
+ end
156
+
157
+
158
+ should "return unused arguments" do
159
+ opts = {}
160
+ c = Clive.new do
161
+ switch(:v) {opts[:v] = true}
162
+ flag(:h) {opts[:h] = true}
163
+ command(:add) {
164
+ switch(:full) {opts[:full] = true}
165
+ }
166
+ end
167
+ result = c.parse(["-v", "add", "--full", "truearg"])
168
+ assert_equal ["truearg"], result
169
+ end
170
+
171
+ should "return multiple unused arguments" do
172
+ opts = {}
173
+ c = Clive.new do
174
+ switch(:v) {opts[:v] = true}
175
+ flag(:h) {opts[:h] = true}
176
+ command(:add) {
177
+ switch(:full) {opts[:full] = true}
178
+ }
179
+ end
180
+ result = c.parse(["-v", "onearg", "twoarg", "/usr/bin/env"])
181
+ assert_equal ["onearg", "twoarg", "/usr/bin/env"], result
182
+ end
183
+
184
+ end
185
+
186
+
187
+ context "When parsing ridiculous edge tests" do
188
+
189
+ should "parse this crazy guy" do
190
+ opts = {}
191
+ c = Clive.new do
192
+ switch(:v) {opts[:v] = true}
193
+ flag(:h) {opts[:h] = true}
194
+
195
+ command(:add) {
196
+ opts[:add] = {}
197
+ switch(:full) {opts[:add][:full] = true}
198
+ flag(:breed) {|i| opts[:add][:breed] = i}
199
+
200
+ command(:init) {
201
+ opts[:add][:init] = {}
202
+ switch(:base) {opts[:add][:init][:base] = true}
203
+ flag(:name) {|i| opts[:add][:init][:name] = i}
204
+ }
205
+ }
206
+ end
207
+ c.parse(["-v", "add", "--full", "init", "--base", "--name=Works"])
208
+ r = {:v => true, :add => {:full => true, :init => {:base => true, :name => 'Works'}} }
209
+ assert_equal r, opts
210
+ end
211
+
212
+ end
213
+
214
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clive
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Joshua Hawxwell
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-14 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: thoughtbot-shoulda
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: yard
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ description: Clive is a DSL for creating a command line interface. It is for people who, like me, love OptionParser's syntax and love GLI's commands.
50
+ email: m@hawx.me
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files:
56
+ - LICENSE
57
+ - README.md
58
+ files:
59
+ - .document
60
+ - .gitignore
61
+ - LICENSE
62
+ - README.md
63
+ - Rakefile
64
+ - VERSION
65
+ - lib/clive.rb
66
+ - lib/clive/commands.rb
67
+ - lib/clive/ext.rb
68
+ - lib/clive/flags.rb
69
+ - lib/clive/switches.rb
70
+ - lib/clive/tokens.rb
71
+ - test/bin_test
72
+ - test/helper.rb
73
+ - test/test_clive.rb
74
+ has_rdoc: true
75
+ homepage: http://github.com/hawx/clive
76
+ licenses: []
77
+
78
+ post_install_message:
79
+ rdoc_options:
80
+ - --charset=UTF-8
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: 3
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ requirements: []
102
+
103
+ rubyforge_project:
104
+ rubygems_version: 1.3.7
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Imagine if optparse and gli had a son called clive.
108
+ test_files:
109
+ - test/helper.rb
110
+ - test/test_clive.rb