gli 1.0.0 → 1.1.0
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.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
|