rubikon 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,427 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2010, Sebastian Staudt
5
+
6
+ module Rubikon
7
+
8
+ module Application
9
+
10
+ # This module contains all DSL-related instance methods of
11
+ # +Application::Base+ and its subclasses. The methods of this module may be
12
+ # used to define and enhance a Rubikon application.
13
+ #
14
+ # @author Sebastian Staudt
15
+ # @see Application::Base
16
+ # @since 0.3.0
17
+ module DSLMethods
18
+
19
+ private
20
+
21
+ # Returns the arguments for the currently executed Command
22
+ #
23
+ # @return [Array]
24
+ # @since 0.2.0
25
+ #
26
+ # @example
27
+ # command :something do
28
+ # puts arguments[0]
29
+ # end
30
+ def args
31
+ unless @current_command.nil?
32
+ @current_command.arguments
33
+ else
34
+ @current_global_option.arguments
35
+ end
36
+ end
37
+ alias_method :arguments, :args
38
+
39
+ # Define a new application Command or an alias to an existing one
40
+ #
41
+ # @param [String, Hash] name The name of the Command as used in
42
+ # application parameters. This might also be a Hash where every
43
+ # key will be an alias to the corresponding value, e.g. <tt>{
44
+ # :alias => :command }</tt>.
45
+ # @param [String] description A description for this Command for use in
46
+ # the application's help screen
47
+ # @param [Proc] block A block that contains the code that should be
48
+ # executed when this Command is called, i.e. when the application
49
+ # is called with the associated parameter
50
+ #
51
+ # @return [Command]
52
+ # @since 0.2.0
53
+ def command(name, description = nil, &block)
54
+ if name.is_a? Hash
55
+ name.each do |alias_name, command_name|
56
+ command = @commands[command_name]
57
+ if command.nil?
58
+ @commands[alias_name] = command_name
59
+ else
60
+ command.aliases << alias_name
61
+ @commands[alias_name] = command
62
+ end
63
+ end
64
+ else
65
+ command = Command.new(self, name, &block)
66
+ command.description = description unless description.nil?
67
+ @commands.each do |command_alias, command_name|
68
+ if command_name == command.name
69
+ @commands[command_alias] = command
70
+ command.aliases << command_alias
71
+ end
72
+ end
73
+ @commands[command.name] = command
74
+ end
75
+
76
+ unless command.nil? || @parameters.empty?
77
+ @parameters.each do |parameter|
78
+ command << parameter
79
+ end
80
+ @parameters.clear
81
+ end
82
+
83
+ command
84
+ end
85
+
86
+ # Prints a debug message if <tt>$DEBUG</tt> is +true+, e.g. if the user
87
+ # supplied the <tt>--debug</tt> (<tt>-d</tt>) flag.
88
+ #
89
+ # @since 0.2.0
90
+ def debug(message)
91
+ ostream.puts message if $DEBUG
92
+ end
93
+
94
+ # Define the default Command of the application, i.e. the Command that is
95
+ # called if no matching Command parameter can be found
96
+ #
97
+ # @param [String] description A description for this Command for use in
98
+ # the application's help screen
99
+ # @param [Proc] block A block that contains the code that should be
100
+ # executed when this Command is called, i.e. when no command
101
+ # parameter is given to the application
102
+ #
103
+ # @return [Command] The default Command object
104
+ # @since 0.2.0
105
+ def default(description = nil, &block)
106
+ if description.is_a? Symbol
107
+ command({ :__default => description })
108
+ else
109
+ command(:__default, description, &block)
110
+ end
111
+ end
112
+
113
+ # Create a new Flag with the given name for the next Command
114
+ #
115
+ # @param [Symbol, #to_sym] name The name of the flag (without dashes).
116
+ # Dashes will be automatically added (<tt>-</tt> for
117
+ # single-character flags, <tt>--</tt> for other flags). This might
118
+ # also be a Hash where every key will be an alias to the
119
+ # corresponding value, e.g. <tt>{ :alias => :flag }</tt>.
120
+ # @param [Proc] block An optional code block that should be executed if
121
+ # this flag is used
122
+ # @since 0.2.0
123
+ #
124
+ # @example
125
+ # flag :status
126
+ # flag :st => :status
127
+ # command :something do
128
+ # ...
129
+ # end
130
+ def flag(name, &block)
131
+ if name.is_a? Hash
132
+ @parameters << name
133
+ else
134
+ @parameters << Flag.new(name, &block)
135
+ end
136
+ end
137
+
138
+ # Checks whether parameter with the given name has been supplied by the
139
+ # user on the command-line.
140
+ #
141
+ # @param [#to_sym] name The name of the parameter to check
142
+ # @since 0.2.0
143
+ #
144
+ # @example
145
+ # flag :status
146
+ # command :something do
147
+ # print_status if given? :status
148
+ # end
149
+ def given?(name)
150
+ name = name.to_sym
151
+ parameter = @global_parameters[name]
152
+ parameter = @current_command.parameters[name] if parameter.nil?
153
+ return false if parameter.nil?
154
+ parameter.active?
155
+ end
156
+
157
+ # Create a new flag with the given name to be used globally
158
+ #
159
+ # Global flags are not bound to any command and can therefore be used
160
+ # throughout the application with the same result.
161
+ #
162
+ # @param (see #flag)
163
+ # @see #flag
164
+ # @see Flag
165
+ # @since 0.2.0
166
+ #
167
+ # @example Define a global flag
168
+ # global_flag :quiet
169
+ # @example Define a global flag with a block to execute
170
+ # global_flag :quiet do
171
+ # @quiet = true
172
+ # end
173
+ # @example Define an alias to a global flag
174
+ # global_flag :q => :quiet
175
+ def global_flag(name, &block)
176
+ if name.is_a? Hash
177
+ name.each do |alias_name, flag_name|
178
+ flag = @global_parameters[flag_name]
179
+ if flag.nil?
180
+ @global_parameters[alias_name] = flag_name
181
+ else
182
+ flag.aliases << alias_name
183
+ @global_parameters[alias_name] = flag
184
+ end
185
+ end
186
+ else
187
+ flag = Flag.new(name, &block)
188
+ @global_parameters.each do |flag_alias, flag_name|
189
+ if flag_name == flag.name
190
+ @global_parameters[flag_alias] = flag
191
+ flag.aliases << flag_alias
192
+ end
193
+ end
194
+ @global_parameters[flag.name] = flag
195
+ end
196
+ end
197
+
198
+ # Create a new option with the given name to be used globally
199
+ #
200
+ # Global options are not bound to any command and can therefore be used
201
+ # throughout the application with the same result.
202
+ #
203
+ # @param (see #option)
204
+ # @see #option
205
+ # @see Option
206
+ # @since 0.2.0
207
+ #
208
+ # @example Define a global option
209
+ # global_option :user, 1
210
+ # @example Define a global option with a block to execute
211
+ # global_option :user, 1 do
212
+ # @user = args[0]
213
+ # end
214
+ # @example Define an alias to a global option
215
+ # global_option :u => :user
216
+ def global_option(name, arg_count = 0, &block)
217
+ if name.is_a? Hash
218
+ name.each do |alias_name, option_name|
219
+ option = @global_parameters[option_name]
220
+ if option.nil?
221
+ @global_parameters[alias_name] = option_name
222
+ else
223
+ option.aliases << alias_name
224
+ @global_parameters[alias_name] = option
225
+ end
226
+ end
227
+ else
228
+ option = Option.new(name, arg_count, &block)
229
+ @global_parameters.each do |option_alias, option_name|
230
+ if option_name == option.name
231
+ @global_parameters[option_alias] = option
232
+ option.aliases << option_alias
233
+ end
234
+ end
235
+ @global_parameters[option.name] = option
236
+ end
237
+ end
238
+
239
+ # Prompts the user for input
240
+ #
241
+ # @param [String, #to_s] prompt A String or other Object responding to
242
+ # +to_s+ used for displaying a prompt to the user
243
+ # @since 0.2.0
244
+ #
245
+ # @example Display a prompt "Please type something: "
246
+ # action 'interactive' do
247
+ # user_provided_value = input 'Please type something'
248
+ #
249
+ # # Do something with the data
250
+ # ...
251
+ # end
252
+ def input(prompt = '')
253
+ unless prompt.to_s.empty?
254
+ ostream << "#{prompt}: "
255
+ end
256
+ @settings[:istream].gets[0..-2]
257
+ end
258
+
259
+ # Create a new Option with the given name for the next Command
260
+ #
261
+ # @param [Symbol, #to_sym] name The name of the Option (without dashes).
262
+ # Dashes will be automatically added (+-+ for single-character
263
+ # options, +--+ for other options). This might also be a Hash
264
+ # where every key will be an alias to the corresponding value,
265
+ # e.g. <tt>{ :alias => :option }</tt>.
266
+ # @param [Numeric] arg_count The number of arguments this option takes.
267
+ # Use +0+ for no required arguments or a negative value for an
268
+ # arbitrary number of arguments
269
+ # @param [Proc] block An optional code block that should be executed if
270
+ # this option is used
271
+ # @since 0.2.0
272
+ #
273
+ # @example
274
+ # option :message,1
275
+ # option :m => :message
276
+ # command :something do
277
+ # ...
278
+ # end
279
+ def option(name, arg_count = 0, &block)
280
+ if name.is_a? Hash
281
+ @parameters << name
282
+ else
283
+ @parameters << Option.new(name.to_s, arg_count, &block)
284
+ end
285
+ end
286
+
287
+ # Convenience method for accessing the user-defined output stream
288
+ #
289
+ # Use this if you want to work directly with the output stream
290
+ #
291
+ # @return [IO] The output stream object - usually +$stdout+
292
+ # @since 0.2.0
293
+ #
294
+ # @example
295
+ # ostream.flush
296
+ def ostream
297
+ @settings[:ostream]
298
+ end
299
+
300
+ # Returns the parameters for the currently executed command
301
+ #
302
+ # @return [Array] The parameters of the currently executed command
303
+ # @see Command
304
+ # @since 0.2.0
305
+ #
306
+ # @example
307
+ # option :message, 1
308
+ # command :something do
309
+ # puts parameters[:message].args[0] if given? :message
310
+ # end
311
+ def params
312
+ @current_command.parameters
313
+ end
314
+ alias_method :parameters, :params
315
+
316
+ # Output text using +IO#<<+ of the output stream
317
+ #
318
+ # @param [String] text The text to write into the output stream
319
+ # @since 0.2.0
320
+ def put(text)
321
+ @settings[:ostream] << text
322
+ @settings[:ostream].flush
323
+ end
324
+
325
+ # Output a character using +IO#putc+ of the output stream
326
+ #
327
+ # @param [String, Numeric] char The character to write into the output
328
+ # stream
329
+ # @since 0.2.0
330
+ def putc(char)
331
+ @settings[:ostream].putc char
332
+ end
333
+
334
+ # Output a line of text using +IO#puts+ of the output stream
335
+ #
336
+ # @param [String] text The text to write into the output stream
337
+ # @since 0.2.0
338
+ def puts(text)
339
+ @settings[:ostream].puts text
340
+ end
341
+
342
+ # Displays a progress bar while the given block is executed
343
+ #
344
+ # Inside the block you have access to a instance of ProgressBar. So you
345
+ # can update the progress using <tt>ProgressBar#+</tt>.
346
+ #
347
+ # @param [Hash] options A Hash of options that should be passed to the
348
+ # ProgressBar object.
349
+ # @param [Proc] block The block to execute
350
+ # @yield [ProgressBar] The given block may be used to change the values
351
+ # of the progress bar
352
+ # @yieldparam [ProgressBar] progress The progress bar indicating the
353
+ # progress of the block
354
+ #
355
+ # @example
356
+ # progress_bar(:maximum => 5) do |progress|
357
+ # 5.times do |file|
358
+ # File.read("any#{file}.txt")
359
+ # progress.+
360
+ # end
361
+ # end
362
+ #
363
+ # @see ProgressBar
364
+ # @since 0.2.0
365
+ def progress_bar(*options, &block)
366
+ hidden_output do |ostream|
367
+ options = options[0]
368
+ options[:ostream] = ostream
369
+
370
+ progress = ProgressBar.new(options)
371
+
372
+ block.call(progress)
373
+ end
374
+ end
375
+
376
+ # Sets an application setting
377
+ #
378
+ # @param [Symbol, #to_sym] setting The name of the setting to change
379
+ # @param [Object] value The value the setting should be changed to
380
+ # @since 0.2.0
381
+ #
382
+ # Available settings
383
+ # +autorun+:: If true, let the application run as soon as its
384
+ # class is defined
385
+ # +help_banner+:: Defines a banner for the help message
386
+ # (<em>unused</em>)
387
+ # +istream+:: Defines an input stream to use
388
+ # +name+:: Defines the name of the application
389
+ # +ostream+:: Defines an output stream to use
390
+ # +raise_errors+:: If true, raise errors, otherwise fail gracefully
391
+ #
392
+ # @example
393
+ # set :name, 'My App'
394
+ # set :autorun, false
395
+ def set(setting, value)
396
+ @settings[setting.to_sym] = value
397
+ end
398
+
399
+ # Displays a throbber while the given block is executed
400
+ #
401
+ # @param [Proc] block The block to execute while the throbber is
402
+ # displayed
403
+ # @since 0.2.0
404
+ # @yield While the block is executed a throbber is displayed
405
+ #
406
+ # @example Using the throbber helper
407
+ # command :slow do
408
+ # throbber do
409
+ # # Add some long running code here
410
+ # ...
411
+ # end
412
+ # end
413
+ def throbber(&block)
414
+ hidden_output do |ostream|
415
+ code_thread = Thread.new { block.call }
416
+ throbber_thread = Throbber.new(ostream, code_thread)
417
+
418
+ code_thread.join
419
+ throbber_thread.join
420
+ end
421
+ end
422
+
423
+ end
424
+
425
+ end
426
+
427
+ end