gli 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +47 -0
- data/lib/gli.rb +56 -8
- data/lib/support/initconfig.rb +35 -0
- metadata +3 -2
data/README.rdoc
CHANGED
@@ -47,6 +47,14 @@ This sets a description of your program. This can be as long as you want.
|
|
47
47
|
|
48
48
|
program_description 'Support program for bootstrapping GLI-based programs'
|
49
49
|
|
50
|
+
This sets a config file for your program. The config file can be used to store default values for command
|
51
|
+
line options and command-specific options on a per-user (or per-site) basis. The format is YAML-based.
|
52
|
+
Using an absolute path will result in the configuraiton file being located there. Without an absolute path,
|
53
|
+
the file will be located relative to the current user's home directory (which is what is being done here).
|
54
|
+
|
55
|
+
config_file '.glirc'
|
56
|
+
|
57
|
+
the configuration file
|
50
58
|
This describes a command line switch "-n" that is global to all commands and specified before
|
51
59
|
the command name on the command line.
|
52
60
|
|
@@ -128,11 +136,50 @@ What this doesn't give you:
|
|
128
136
|
* A way to indicate a required argument or required number of arguments
|
129
137
|
* A way to do default switches to 'true' and therefore accept things like <tt>--no-force</tt>
|
130
138
|
|
139
|
+
== Configuration File
|
140
|
+
|
141
|
+
The configuration file format is a very simple means of customizing the execution of your command on a per-user
|
142
|
+
or per-site basis. The idea is that commonly used values that aren't the commands' default can be stored in the configuration
|
143
|
+
file so that users do not need to specify them on the command line. The search order for the value of a particular
|
144
|
+
flag then becomes:
|
145
|
+
|
146
|
+
1. Command line invocation
|
147
|
+
2. Configuration File value
|
148
|
+
3. Default value in the application
|
149
|
+
|
150
|
+
Note that since there is no way to switch _off_ switches, setting them to default to true in the configuration file
|
151
|
+
cannot be "undone" on the command line. A future version may allow this.
|
152
|
+
|
153
|
+
The configuration file format is YAML based and can be bootstrapped via the +initconfig+ command to your application.
|
154
|
+
This command is automatically created and added to your application's commands when you declare that there is a
|
155
|
+
config file. When invoked, all global options set on the command line are configured
|
156
|
+
inside the configuration file. Further, a blank area for each
|
157
|
+
command of your application is created, to allow the user edit the config file ith command-specific default values.
|
158
|
+
|
159
|
+
---
|
160
|
+
# Global options are here
|
161
|
+
:f: foo
|
162
|
+
:g: blah
|
163
|
+
# Command-specific options are under 'commands'
|
164
|
+
commands:
|
165
|
+
# defaults for the "doit" command
|
166
|
+
:doit:
|
167
|
+
:g: bar
|
168
|
+
:s: true
|
169
|
+
# defaults for the "gonow" command
|
170
|
+
:gonow:
|
171
|
+
:g: foobar
|
172
|
+
:f: barfoo
|
173
|
+
|
174
|
+
This allows you to design your application to have it's behavior _entirely_ affected by command line options, with sensible
|
175
|
+
defaults stored in a configuration file.
|
176
|
+
|
131
177
|
== Reference
|
132
178
|
|
133
179
|
|
134
180
|
[+action+] Specify the action to take when a command is executed from the command line. This is only usable in a command block on the command object (e.g. <tt>c.action</tt>). This takes a block that yields three parameters: a hash of global options specified on the commandline, a hash of command-specific options specified on the command line, and an array of arguments parsed after the options were set on the command line. So, a command like <tt>git --git-dir=/tmp commit -a -m 'Foo bar' foo.c bar.c</tt> would result in the global hash containing <tt>:'git-dir' => '/tmp'</tt>, the options hash containing <tt>:a => true, :m => 'Foo bar'</tt> and the arguments array being <tt>['foo.c', 'bar.c']</tt>
|
135
181
|
[+arg_name+] Describe the name of the argument to the next flag or command. This can be used at the global level or inside a command block on the command object (e.g. <tt>c.arg_name</tt>)
|
182
|
+
[+config_file+] Name the configuration file for your applicaiton. This can either be an absolute path to where the applicaiton will find the configuration file, or a relative path, that will be interpretted as relative to the user's home directory. Default is +nil+, which means no configuration file will be used. Declaring this creates a special +initconfig+ command that can bootstrap this configuration file for your users.
|
136
183
|
[+command+] Declare a command. This takes a symbol or array of symbols and a block. The block yields one argument, the command itself.
|
137
184
|
[+default_value+] Indicate the default value of the next flag. This can be used at the global level or inside a command block on the command object (e.g. <tt>c.default_value</tt>)
|
138
185
|
[+desc+] Describe the next flag, switch, or command you will declare. This can be used at the global level or inside a command block on the command object (e.g. <tt>c.desc</tt>)
|
data/lib/gli.rb
CHANGED
@@ -5,6 +5,8 @@ require 'gli/flag.rb'
|
|
5
5
|
require 'gli/options.rb'
|
6
6
|
require 'support/help.rb'
|
7
7
|
require 'support/rdoc.rb'
|
8
|
+
require 'support/initconfig.rb'
|
9
|
+
require 'etc'
|
8
10
|
|
9
11
|
# A means to define and parse a command line interface that works as
|
10
12
|
# Git's does, in that you specify global options, a command name, command
|
@@ -12,18 +14,20 @@ require 'support/rdoc.rb'
|
|
12
14
|
module GLI
|
13
15
|
extend self
|
14
16
|
|
15
|
-
VERSION = '0.
|
17
|
+
VERSION = '1.0.0'
|
16
18
|
|
17
19
|
@@program_name = $0.split(/\//)[-1]
|
18
20
|
@@post_block = nil
|
19
21
|
@@pre_block = nil
|
20
22
|
@@error_block = nil
|
23
|
+
@@config_file = nil
|
21
24
|
|
22
25
|
# Reset the GLI module internal data structures; mostly for testing
|
23
26
|
def reset
|
24
27
|
switches.clear
|
25
28
|
flags.clear
|
26
29
|
commands.clear
|
30
|
+
@@config_file = nil
|
27
31
|
clear_nexts
|
28
32
|
end
|
29
33
|
|
@@ -54,6 +58,18 @@ module GLI
|
|
54
58
|
clear_nexts
|
55
59
|
end
|
56
60
|
|
61
|
+
# Sets the config file. If not an absolute path
|
62
|
+
# sets the path to the user's home directory
|
63
|
+
def config_file(filename)
|
64
|
+
if filename =~ /^\//
|
65
|
+
@@config_file = filename
|
66
|
+
else
|
67
|
+
@@config_file = Etc.getpwuid.dir + '/' + filename
|
68
|
+
end
|
69
|
+
commands[:initconfig] = InitConfig.new(@@config_file)
|
70
|
+
@@config_file
|
71
|
+
end
|
72
|
+
|
57
73
|
# Define a command.
|
58
74
|
def command(*names)
|
59
75
|
command = Command.new([names].flatten,@@next_desc,@@next_arg_name,@@next_long_desc)
|
@@ -93,7 +109,8 @@ module GLI
|
|
93
109
|
commands[:rdoc] = rdoc if !commands[:rdoc]
|
94
110
|
commands[:help] = DefaultHelpCommand.new(rdoc) if !commands[:help]
|
95
111
|
begin
|
96
|
-
|
112
|
+
config = parse_config
|
113
|
+
global_options,command,options,arguments = parse_options(args,config)
|
97
114
|
proceed = true
|
98
115
|
proceed = @@pre_block.call(global_options,command,options,arguments) if @@pre_block
|
99
116
|
if proceed
|
@@ -111,6 +128,16 @@ module GLI
|
|
111
128
|
end
|
112
129
|
end
|
113
130
|
|
131
|
+
def parse_config
|
132
|
+
return nil if @@config_file.nil?
|
133
|
+
require 'yaml'
|
134
|
+
if File.exist?(@@config_file)
|
135
|
+
File.open(@@config_file) { |f| YAML::load(f) }
|
136
|
+
else
|
137
|
+
{}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
114
141
|
def program_name(override=nil)
|
115
142
|
if override
|
116
143
|
@@program_name = override
|
@@ -123,8 +150,14 @@ module GLI
|
|
123
150
|
# * Command
|
124
151
|
# * command options (as a Hash)
|
125
152
|
# * arguments (as an Array)
|
126
|
-
def parse_options(args)
|
127
|
-
|
153
|
+
def parse_options(args,config=nil)
|
154
|
+
command_configs = {}
|
155
|
+
if config.nil?
|
156
|
+
config = {}
|
157
|
+
else
|
158
|
+
command_configs = config.delete(GLI::InitConfig::COMMANDS_KEY) if !config.nil?
|
159
|
+
end
|
160
|
+
global_options,command,options,arguments = parse_options_helper(args.clone,config,nil,Options.new,Array.new,command_configs)
|
128
161
|
flags.each { |name,flag| global_options[name] = flag.default_value if !global_options[name] }
|
129
162
|
command.flags.each { |name,flag| options[name] = flag.default_value if !options[name] }
|
130
163
|
return [global_options,command,options,arguments]
|
@@ -164,6 +197,7 @@ module GLI
|
|
164
197
|
# [command] the Command that has been identified (or nil if not identified yet)
|
165
198
|
# [command_options] options for Command
|
166
199
|
# [arguments] the arguments for Command
|
200
|
+
# [command_configs] the configuration file for all commands, used as defaults
|
167
201
|
#
|
168
202
|
# This works by finding the first non-switch/flag argument, and taking that sublist and trying to pick out
|
169
203
|
# flags and switches. After this is done, one of the following is true:
|
@@ -176,7 +210,7 @@ module GLI
|
|
176
210
|
#
|
177
211
|
# Once the command has been found, we start looking for command-specific flags and switches.
|
178
212
|
# When those have been found, we know the rest of the argument list is arguments for the command
|
179
|
-
def parse_options_helper(args,global_options,command,command_options,arguments)
|
213
|
+
def parse_options_helper(args,global_options,command,command_options,arguments,command_configs)
|
180
214
|
non_flag_i = find_non_flag_index(args)
|
181
215
|
all_flags = false
|
182
216
|
if non_flag_i == 0
|
@@ -185,7 +219,12 @@ module GLI
|
|
185
219
|
command_name = args.shift
|
186
220
|
command = find_command(command_name)
|
187
221
|
raise "Unknown command '#{command_name}'" if !command
|
188
|
-
return parse_options_helper(args,
|
222
|
+
return parse_options_helper(args,
|
223
|
+
global_options,
|
224
|
+
command,
|
225
|
+
default_command_options(command,command_configs),
|
226
|
+
arguments,
|
227
|
+
command_configs)
|
189
228
|
else
|
190
229
|
return global_options,command,command_options,arguments + args
|
191
230
|
end
|
@@ -224,7 +263,7 @@ module GLI
|
|
224
263
|
return [global_options,command,command_options,arguments] if rest.empty?
|
225
264
|
# If we have no more options we've parsed them all
|
226
265
|
# and rest may have more
|
227
|
-
return parse_options_helper(rest,global_options,command,command_options,arguments)
|
266
|
+
return parse_options_helper(rest,global_options,command,command_options,arguments,command_configs)
|
228
267
|
else
|
229
268
|
if command
|
230
269
|
check = rest
|
@@ -245,12 +284,21 @@ module GLI
|
|
245
284
|
command = find_command(command_name)
|
246
285
|
raise "Unknown command '#{command_name}'" if !command
|
247
286
|
|
248
|
-
return parse_options_helper(rest,
|
287
|
+
return parse_options_helper(rest,
|
288
|
+
global_options,
|
289
|
+
command,
|
290
|
+
default_command_options(command,command_configs),
|
291
|
+
arguments,
|
292
|
+
command_configs)
|
249
293
|
end
|
250
294
|
end
|
251
295
|
|
252
296
|
end
|
253
297
|
|
298
|
+
def default_command_options(command,command_configs)
|
299
|
+
options = (command_configs && command_configs[command.name.to_sym]) || {}
|
300
|
+
end
|
301
|
+
|
254
302
|
def find_command(name)
|
255
303
|
sym = name.to_sym
|
256
304
|
return commands[name.to_sym] if commands[sym]
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'gli'
|
2
|
+
require 'gli/command'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module GLI
|
6
|
+
class InitConfig < Command
|
7
|
+
COMMANDS_KEY = 'commands'
|
8
|
+
|
9
|
+
def initialize(config_file_name)
|
10
|
+
@filename = config_file_name
|
11
|
+
super(:initconfig,"Initialize the config file using current global options",nil,'Initializes a configuration file where you can set default options for command line flags, but globally and on a per-command basis. These defaults override the built-in defaults and allow you to omit commonly-used command line flags when invoking this program')
|
12
|
+
|
13
|
+
self.desc 'force overwrite of existing config file'
|
14
|
+
self.switch :force
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute(global_options,options,arguments)
|
18
|
+
if options[:force] || !File.exist?(@filename)
|
19
|
+
config = global_options
|
20
|
+
config[COMMANDS_KEY] = {}
|
21
|
+
GLI.commands.each do |name,command|
|
22
|
+
if (command != self) && (name != :rdoc) && (name != :help)
|
23
|
+
config[COMMANDS_KEY][name.to_sym] = {} if command != self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
File.open(@filename,'w') do |file|
|
27
|
+
YAML.dump(config,file)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
puts "Not overwriting existing config file #{@filename}"
|
31
|
+
puts 'Use --force to override'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Copeland
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-12-
|
12
|
+
date: 2009-12-24 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -32,6 +32,7 @@ files:
|
|
32
32
|
- lib/support/help.rb
|
33
33
|
- lib/support/rdoc.rb
|
34
34
|
- lib/support/scaffold.rb
|
35
|
+
- lib/support/initconfig.rb
|
35
36
|
- bin/gli
|
36
37
|
- README.rdoc
|
37
38
|
- gli.rdoc
|