rubikon 0.2.1 → 0.3.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.
@@ -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