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.
Files changed (4) hide show
  1. data/README.rdoc +47 -0
  2. data/lib/gli.rb +56 -8
  3. data/lib/support/initconfig.rb +35 -0
  4. metadata +3 -2
@@ -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.3.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
- global_options,command,options,arguments = parse_options(args)
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
- global_options,command,options,arguments = parse_options_helper(args.clone,Options.new,nil,Options.new,Array.new)
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,global_options,command,command_options,arguments)
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,global_options,command,command_options,arguments)
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.0.0
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-19 00:00:00 -05:00
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