gli 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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