remi-simplecli 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +118 -0
- data/examples/hello-cli +44 -0
- data/lib/simplecli.rb +180 -0
- metadata +56 -0
data/README
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
== SimpleCLI
|
2
|
+
|
3
|
+
Super Simple RubyGems-like CLI
|
4
|
+
|
5
|
+
SimpleCLI gives you a stupidly simple way to implement command-line
|
6
|
+
interfaces like that of RubyGems with a basic interface like:
|
7
|
+
|
8
|
+
gem command [options]
|
9
|
+
|
10
|
+
SimpleCLI gives you a way of defining your commands (or actions) so
|
11
|
+
they'll automatically show up when you run <tt>`yourapp commands`</tt>
|
12
|
+
|
13
|
+
SimpleCLI also makes it really easy to add documentation to each of
|
14
|
+
your commands (or actions)
|
15
|
+
|
16
|
+
=== Example
|
17
|
+
|
18
|
+
Here's a super simple SimpleCLI example:
|
19
|
+
|
20
|
+
#! /usr/bin/env ruby
|
21
|
+
|
22
|
+
require File.dirname(__FILE__) + '/../lib/simplecli'
|
23
|
+
|
24
|
+
class Hello
|
25
|
+
include SimpleCLI
|
26
|
+
|
27
|
+
def usage
|
28
|
+
puts <<doco
|
29
|
+
|
30
|
+
Hello CLI
|
31
|
+
|
32
|
+
Usage:
|
33
|
+
#{ script_name } command [options]
|
34
|
+
|
35
|
+
Futher help:
|
36
|
+
#{ script_name } commands # list all available commands
|
37
|
+
#{ script_name } help <COMMAND> # show help for COMMAND
|
38
|
+
#{ script_name } help # show this help message
|
39
|
+
|
40
|
+
doco
|
41
|
+
end
|
42
|
+
|
43
|
+
def sayhello_help
|
44
|
+
<<doco
|
45
|
+
Usage: #{ script_name } sayhello [SAY]
|
46
|
+
|
47
|
+
Arguments:
|
48
|
+
SAY: Something to say (default 'Hello World!')
|
49
|
+
|
50
|
+
Summary:
|
51
|
+
Says hello!
|
52
|
+
doco
|
53
|
+
end
|
54
|
+
def sayhello *args
|
55
|
+
puts args.empty? ? "Hello World!" : args.join(' ')
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
# POSTAMBLE
|
61
|
+
if __FILE__ == $0
|
62
|
+
Hello.new( ARGV, :default => 'sayhello' ).run
|
63
|
+
end
|
64
|
+
|
65
|
+
Example usage:
|
66
|
+
|
67
|
+
<b><tt>$ ./hello-cli</b></tt>
|
68
|
+
|
69
|
+
Hello CLI
|
70
|
+
|
71
|
+
Usage:
|
72
|
+
hello-cli command [options]
|
73
|
+
|
74
|
+
Futher help:
|
75
|
+
hello-cli commands # list all available commands
|
76
|
+
hello-cli help <COMMAND> # show help for COMMAND
|
77
|
+
hello-cli help # show this help message
|
78
|
+
|
79
|
+
<b><tt>$ ./hello-cli commands</b></tt>
|
80
|
+
|
81
|
+
hello-cli commands are:
|
82
|
+
|
83
|
+
DEFAULT COMMAND sayhello
|
84
|
+
|
85
|
+
commands List all 'hello-cli' commands
|
86
|
+
help Provide help documentation for a command
|
87
|
+
sayhello Says hello!
|
88
|
+
|
89
|
+
For help on a particular command, use 'hello-cli help COMMAND'.
|
90
|
+
|
91
|
+
<b><tt>$ ./hello-cli help</b></tt>
|
92
|
+
|
93
|
+
Usage: hello-cli help COMMAND
|
94
|
+
|
95
|
+
Summary:
|
96
|
+
Provide help documentation for a command
|
97
|
+
|
98
|
+
<b><tt>$ ./hello-cli help sayhello</b></tt>
|
99
|
+
|
100
|
+
Usage: hello-cli sayhello [SAY]
|
101
|
+
|
102
|
+
Arguments:
|
103
|
+
SAY: Something to say (default 'Hello World!')
|
104
|
+
|
105
|
+
Summary:
|
106
|
+
Says hello!
|
107
|
+
|
108
|
+
<b><tt>$ ./hello-cli sayhello</b></tt>
|
109
|
+
|
110
|
+
Hello World!
|
111
|
+
|
112
|
+
<b><tt>$ ./hello-cli sayhello Hi There</b></tt>
|
113
|
+
|
114
|
+
Hi There
|
115
|
+
|
116
|
+
<b><tt>$ ./hello-cli Hi There</b></tt> <tt># this works because sayhello is configured as the default command</tt>
|
117
|
+
|
118
|
+
Hi There
|
data/examples/hello-cli
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/simplecli'
|
4
|
+
|
5
|
+
class Hello
|
6
|
+
include SimpleCLI
|
7
|
+
|
8
|
+
def usage
|
9
|
+
puts <<doco
|
10
|
+
|
11
|
+
Hello CLI
|
12
|
+
|
13
|
+
Usage:
|
14
|
+
#{ script_name } command [options]
|
15
|
+
|
16
|
+
Futher help:
|
17
|
+
#{ script_name } commands # list all available commands
|
18
|
+
#{ script_name } help <COMMAND> # show help for COMMAND
|
19
|
+
#{ script_name } help # show this help message
|
20
|
+
|
21
|
+
doco
|
22
|
+
end
|
23
|
+
|
24
|
+
def sayhello_help
|
25
|
+
<<doco
|
26
|
+
Usage: #{ script_name } sayhello [SAY]
|
27
|
+
|
28
|
+
Arguments:
|
29
|
+
SAY: Something to say (default 'Hello World!')
|
30
|
+
|
31
|
+
Summary:
|
32
|
+
Says hello!
|
33
|
+
doco
|
34
|
+
end
|
35
|
+
def sayhello *args
|
36
|
+
puts args.empty? ? "Hello World!" : args.join(' ')
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# POSTAMBLE
|
42
|
+
if __FILE__ == $0
|
43
|
+
Hello.new( ARGV, :default => 'sayhello' ).run
|
44
|
+
end
|
data/lib/simplecli.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
#
|
2
|
+
# Stupidly simple way to get a CLI that handles:
|
3
|
+
# myapp somecommand --blah=5 args --more stuff -y
|
4
|
+
#
|
5
|
+
# All it does is, if the "command" (or "action") passed
|
6
|
+
# has a method with the same name, the rest of the args
|
7
|
+
# are passed to the method.
|
8
|
+
#
|
9
|
+
# If you provide a command_help method that returns help
|
10
|
+
# info as a String, that'll be used when you call:
|
11
|
+
# myapp help somecommand
|
12
|
+
#
|
13
|
+
# If you provide a 'Summary:\n blah blah blah' bit in
|
14
|
+
# your help_somecommand, it'll be used as the command's
|
15
|
+
# summary and your command will show up when you:
|
16
|
+
# myapp commands
|
17
|
+
#
|
18
|
+
# To use, include in your class
|
19
|
+
#
|
20
|
+
# NOTE: if you use the 'default' command functionality,
|
21
|
+
# we don'e even bother to check to see if we respond_to?
|
22
|
+
# what you provide as a default command, incase it
|
23
|
+
# uses method missing or something. So it's *YOUR*
|
24
|
+
# responsibility to provide this method
|
25
|
+
#
|
26
|
+
# Conventionally, your 'default' method should simple pass
|
27
|
+
# along the arguments to another defined and documented command!
|
28
|
+
#
|
29
|
+
module SimpleCLI
|
30
|
+
attr_accessor :options
|
31
|
+
attr_reader :args, :command, :command_args
|
32
|
+
|
33
|
+
def initialize args = [], options = {}
|
34
|
+
@args = args
|
35
|
+
@options = options
|
36
|
+
parse!
|
37
|
+
end
|
38
|
+
|
39
|
+
# figure out what command to run, arguments to pass it, etc
|
40
|
+
#
|
41
|
+
# call #run afterwards, to run. or call parse! to parse and run
|
42
|
+
#
|
43
|
+
# typically, you shouldn't call this yourself. call parse when you
|
44
|
+
# want to RE-parse the arguments passed in, because initialize auto-parses
|
45
|
+
#
|
46
|
+
# typical:
|
47
|
+
# Bin.new( ARGV ).run
|
48
|
+
# Bin.new( ARGV, :default => 'some_default_method ).run
|
49
|
+
#
|
50
|
+
# use this is you want to ...
|
51
|
+
# bin = Bin.new ARGV
|
52
|
+
# bin.options[:default] = 'some_default_method'
|
53
|
+
# bin.instance_eval { 'do some custom stuff that might change the command to run, etc' }
|
54
|
+
# bin.parse!
|
55
|
+
# bin.run
|
56
|
+
#
|
57
|
+
def parse!
|
58
|
+
args = @args.clone
|
59
|
+
|
60
|
+
@default_command = @options[:default].to_s if @options.keys.include? :default
|
61
|
+
@commands = all_commands
|
62
|
+
|
63
|
+
if not args.empty? and @commands.map{|c|c.downcase}.include? args.first.downcase
|
64
|
+
@command = args.shift.downcase
|
65
|
+
else
|
66
|
+
@command = (args.empty?) ? 'usage' : ( @default_command || 'usage' )
|
67
|
+
end
|
68
|
+
|
69
|
+
@command_args = args
|
70
|
+
end
|
71
|
+
|
72
|
+
# run command determined by parse
|
73
|
+
def run
|
74
|
+
begin
|
75
|
+
self.send @command, *@command_args
|
76
|
+
rescue ArgumentError => ex
|
77
|
+
puts "'#{@command}' called with wrong number of arguments\n\n"
|
78
|
+
puts help_for( @command )
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# returns names of all defined 'command' methods
|
83
|
+
#
|
84
|
+
# only returns methods with methodname_help sister methods,
|
85
|
+
# inotherwords: only returns DOCUMENTED methods
|
86
|
+
# ... this should get you to document that command!
|
87
|
+
def all_commands
|
88
|
+
self.methods.sort.grep( /_help/ ).collect{ |help_method| help_method.gsub( /(.*)_help/ , '\1' ) }
|
89
|
+
end
|
90
|
+
|
91
|
+
# returns help String for command
|
92
|
+
def help_for command
|
93
|
+
help_method = "#{ command }_help".to_sym
|
94
|
+
self.send( help_method ) if self.respond_to? help_method
|
95
|
+
end
|
96
|
+
|
97
|
+
# returns summary String for command (extracted from help_for command)
|
98
|
+
#
|
99
|
+
# Looks for
|
100
|
+
# Summary:
|
101
|
+
# some summary text here, on a new line after 'Summary:'
|
102
|
+
#
|
103
|
+
def summary_for command
|
104
|
+
doco = help_for command
|
105
|
+
if doco
|
106
|
+
match = /Summary:\n*(.*)/.match doco
|
107
|
+
if match and match.length > 1
|
108
|
+
match[1].strip
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# default usage message, called if we can't figure out what command to run
|
114
|
+
#
|
115
|
+
# override in your app by re-defining - it should puts the message (or do whatever) itself!
|
116
|
+
# this method doesn't return a string, like blah_help methods (which are called by #help).
|
117
|
+
# usage is called, all by itself ... so it needs to print itself!
|
118
|
+
#
|
119
|
+
def usage *args
|
120
|
+
puts "default usage message. please define a 'usage' method returning a new message."
|
121
|
+
end
|
122
|
+
|
123
|
+
# shortcut to pretty file name of script, which can be used in your help doco
|
124
|
+
def script_name
|
125
|
+
File.basename $0
|
126
|
+
end
|
127
|
+
|
128
|
+
# HELP
|
129
|
+
def help_help
|
130
|
+
<<doco
|
131
|
+
Usage: #{ script_name } help COMMAND
|
132
|
+
|
133
|
+
Summary:
|
134
|
+
Provide help documentation for a command
|
135
|
+
doco
|
136
|
+
end
|
137
|
+
def help *args
|
138
|
+
command = args.shift
|
139
|
+
if command.nil?
|
140
|
+
puts help_for( :help )
|
141
|
+
elsif (doco = help_for command)
|
142
|
+
puts doco
|
143
|
+
else
|
144
|
+
puts "No documentation found for command: #{command}"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# COMMANDS
|
149
|
+
def commands_help
|
150
|
+
<<doco
|
151
|
+
Usage: #{ script_name } commands
|
152
|
+
|
153
|
+
Summary:
|
154
|
+
List all '#{ script_name }' commands
|
155
|
+
doco
|
156
|
+
end
|
157
|
+
def commands *no_args
|
158
|
+
before_spaces = 4
|
159
|
+
after_spaces = 18
|
160
|
+
text = all_commands.inject(''){ |all,cmd| all << "\n#{' ' * before_spaces}#{cmd}#{' ' * (after_spaces - cmd.length)}#{summary_for(cmd)}" }
|
161
|
+
puts <<doco
|
162
|
+
#{ script_name } commands are:
|
163
|
+
|
164
|
+
DEFAULT COMMAND #{ @default_command || 'not set' }
|
165
|
+
#{ text }
|
166
|
+
|
167
|
+
For help on a particular command, use '#{ script_name } help COMMAND'.
|
168
|
+
doco
|
169
|
+
|
170
|
+
#If you've made a command and it's not showing up here, you
|
171
|
+
#need to make help method named 'COMMAND_help' that returns
|
172
|
+
#your commands help documentation.
|
173
|
+
#
|
174
|
+
#[NOT YET IMPLEMENTED:]
|
175
|
+
#Commands may be abbreviated, so long as they are unumbiguous.
|
176
|
+
#e.g. 'snip h commands' is short for 'snip help commands'.
|
177
|
+
#doco
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: remi-simplecli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- remi Taylor
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-04-27 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: SimpleCLI gives you a stupidly simple way to implement command-line interfaces like that of RubyGems
|
17
|
+
email: remi@remitaylor.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- lib/simplecli.rb
|
27
|
+
- examples/hello-cli
|
28
|
+
has_rdoc: true
|
29
|
+
homepage: http://github.com/remi/simplecli
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options:
|
32
|
+
- --main
|
33
|
+
- README
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: "0"
|
41
|
+
version:
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
requirements: []
|
49
|
+
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.0.1
|
52
|
+
signing_key:
|
53
|
+
specification_version: 2
|
54
|
+
summary: Super Simple RubyGems-like CLI
|
55
|
+
test_files: []
|
56
|
+
|