keybox 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.
@@ -0,0 +1,120 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # color_scheme.rb
4
+ #
5
+ # Created by Jeremy Hinegardner on 2007-01-24
6
+ # Copyright 2007. All rights reserved
7
+ #
8
+ # This is Free Software. See LICENSE and COPYING for details
9
+
10
+ require 'highline'
11
+
12
+ class HighLine
13
+ #
14
+ # ColorScheme objects encapsulate a named set of colors to be used in the
15
+ # HighLine.colors() method call. For example, by applying a ColorScheme that
16
+ # has a <tt>:warning</tt> color then the following could be used:
17
+ #
18
+ # colors("This is a warning", :warning)
19
+ #
20
+ # A ColorScheme contains named sets of HighLine color constants.
21
+ #
22
+ # Example: Instantiating a color scheme, applying it to HighLine,
23
+ # and using it:
24
+ #
25
+ # ft = HighLine::ColorScheme.new do |cs|
26
+ # cs[:headline] = [ :bold, :yellow, :on_black ]
27
+ # cs[:horizontal_line] = [ :bold, :white ]
28
+ # cs[:even_row] = [ :green ]
29
+ # cs[:odd_row] = [ :magenta ]
30
+ # end
31
+ #
32
+ # HighLine.color_scheme = ft
33
+ # say("<%= color('Headline', :headline) %>")
34
+ # say("<%= color('-'*20, :horizontal_line) %>")
35
+ # i = true
36
+ # ("A".."D").each do |row|
37
+ # if i then
38
+ # say("<%= color('#{row}', :even_row ) %>")
39
+ # else
40
+ # say("<%= color('#{row}', :odd_row) %>")
41
+ # end
42
+ # i = !i
43
+ # end
44
+ #
45
+ #
46
+ class ColorScheme
47
+ #
48
+ # Create an instance of HighLine::ColorScheme. The customization can
49
+ # happen as a passed in Hash or via the yielded block. Key's are
50
+ # converted to <tt>:symbols</tt> and values are converted to HighLine
51
+ # constants.
52
+ #
53
+ def initialize( h = nil )
54
+ @scheme = Hash.new
55
+ load_from_hash(h) unless h.nil?
56
+ yield self if block_given?
57
+ end
58
+
59
+ # Load multiple colors from key/value pairs.
60
+ def load_from_hash( h )
61
+ h.each_pair do |color_tag, constants|
62
+ self[color_tag] = constants
63
+ end
64
+ end
65
+
66
+ # Does this color scheme include the given tag name?
67
+ def include?( color_tag )
68
+ @scheme.keys.include?(to_symbol(color_tag))
69
+ end
70
+
71
+ # Allow the scheme to be accessed like a Hash.
72
+ def []( color_tag )
73
+ @scheme[to_symbol(color_tag)]
74
+ end
75
+
76
+ # Allow the scheme to be set like a Hash.
77
+ def []=( color_tag, constants )
78
+ @scheme[to_symbol(color_tag)] = constants.map { |c| to_constant(c) }
79
+ end
80
+
81
+ private
82
+
83
+ # Return a normalized representation of a color name.
84
+ def to_symbol( t )
85
+ t.to_s.downcase
86
+ end
87
+
88
+ # Return a normalized representation of a color setting.
89
+ def to_constant( v )
90
+ v = v.to_s if v.is_a?(Symbol)
91
+ if v.is_a?(String) then
92
+ HighLine.const_get(v.upcase)
93
+ else
94
+ v
95
+ end
96
+ end
97
+ end
98
+
99
+ # A sample ColorScheme.
100
+ class SampleColorScheme < ColorScheme
101
+ #
102
+ # Builds the sample scheme with settings for <tt>:critical</tt>,
103
+ # <tt>:error</tt>, <tt>:warning</tt>, <tt>:notice</tt>, <tt>:info</tt>,
104
+ # <tt>:debug</tt>, <tt>:row_even</tt>, and <tt>:row_odd</tt> colors.
105
+ #
106
+ def initialize( h = nil )
107
+ scheme = {
108
+ :critical => [ :yellow, :on_red ],
109
+ :error => [ :bold, :red ],
110
+ :warning => [ :bold, :yellow ],
111
+ :notice => [ :bold, :magenta ],
112
+ :info => [ :bold, :cyan ],
113
+ :debug => [ :bold, :green ],
114
+ :row_even => [ :cyan ],
115
+ :row_odd => [ :magenta ]
116
+ }
117
+ super(scheme)
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,43 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # import.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-04-26.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+ #
8
+ # This is Free Software. See LICENSE and COPYING for details.
9
+
10
+ require "highline"
11
+ require "forwardable"
12
+
13
+ $terminal = HighLine.new
14
+
15
+ #
16
+ # <tt>require "highline/import"</tt> adds shortcut methods to Kernel, making
17
+ # agree(), ask(), choose() and say() globally available. This is handy for
18
+ # quick and dirty input and output. These methods use the HighLine object in
19
+ # the global variable <tt>$terminal</tt>, which is initialized to used
20
+ # <tt>$stdin</tt> and <tt>$stdout</tt> (you are free to change this).
21
+ # Otherwise, these methods are identical to their HighLine counterparts, see that
22
+ # class for detailed explanations.
23
+ #
24
+ module Kernel
25
+ extend Forwardable
26
+ def_delegators :$terminal, :agree, :ask, :choose, :say
27
+ end
28
+
29
+ class Object
30
+ #
31
+ # Tries this object as a _first_answer_ for a HighLine::Question. See that
32
+ # attribute for details.
33
+ #
34
+ # *Warning*: This Object will be passed to String() before set.
35
+ #
36
+ def or_ask( *args, &details )
37
+ ask(*args) do |question|
38
+ question.first_answer = String(self) unless nil?
39
+
40
+ details.call(question) unless details.nil?
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,395 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # menu.rb
4
+ #
5
+ # Created by Gregory Thomas Brown on 2005-05-10.
6
+ # Copyright 2005. All rights reserved.
7
+ #
8
+ # This is Free Software. See LICENSE and COPYING for details.
9
+
10
+ require "highline/question"
11
+
12
+ class HighLine
13
+ #
14
+ # Menu objects encapsulate all the details of a call to HighLine.choose().
15
+ # Using the accessors and Menu.choice() and Menu.choices(), the block passed
16
+ # to HighLine.choose() can detail all aspects of menu display and control.
17
+ #
18
+ class Menu < Question
19
+ #
20
+ # Create an instance of HighLine::Menu. All customization is done
21
+ # through the passed block, which should call accessors and choice() and
22
+ # choices() as needed to define the Menu. Note that Menus are also
23
+ # Questions, so all that functionality is available to the block as
24
+ # well.
25
+ #
26
+ def initialize( )
27
+ #
28
+ # Initialize Question objects with ignored values, we'll
29
+ # adjust ours as needed.
30
+ #
31
+ super("Ignored", [ ], &nil) # avoiding passing the block along
32
+
33
+ @items = [ ]
34
+ @hidden_items = [ ]
35
+ @help = Hash.new("There's no help for that topic.")
36
+
37
+ @index = :number
38
+ @index_suffix = ". "
39
+ @select_by = :index_or_name
40
+ @flow = :rows
41
+ @list_option = nil
42
+ @header = nil
43
+ @prompt = "? "
44
+ @layout = :list
45
+ @shell = false
46
+ @nil_on_handled = false
47
+
48
+ # Override Questions responses, we'll set our own.
49
+ @responses = { }
50
+ # Context for action code.
51
+ @highline = nil
52
+
53
+ yield self if block_given?
54
+
55
+ init_help if @shell and not @help.empty?
56
+ update_responses # rebuild responses based on our settings
57
+ end
58
+
59
+ #
60
+ # An _index_ to append to each menu item in display. See
61
+ # Menu.index=() for details.
62
+ #
63
+ attr_reader :index
64
+ #
65
+ # The String placed between an _index_ and a menu item. Defaults to
66
+ # ". ". Switches to " ", when _index_ is set to a String (like "-").
67
+ #
68
+ attr_accessor :index_suffix
69
+ #
70
+ # The _select_by_ attribute controls how the user is allowed to pick a
71
+ # menu item. The available choices are:
72
+ #
73
+ # <tt>:index</tt>:: The user is allowed to type the numerical
74
+ # or alphetical index for their selection.
75
+ # <tt>:index_or_name</tt>:: Allows both methods from the
76
+ # <tt>:index</tt> option and the
77
+ # <tt>:name</tt> option.
78
+ # <tt>:name</tt>:: Menu items are selected by typing a portion
79
+ # of the item name that will be
80
+ # auto-completed.
81
+ #
82
+ attr_accessor :select_by
83
+ #
84
+ # This attribute is passed directly on as the mode to HighLine.list() by
85
+ # all the preset layouts. See that method for appropriate settings.
86
+ #
87
+ attr_accessor :flow
88
+ #
89
+ # This setting is passed on as the third parameter to HighLine.list()
90
+ # by all the preset layouts. See that method for details of its
91
+ # effects. Defaults to +nil+.
92
+ #
93
+ attr_accessor :list_option
94
+ #
95
+ # Used by all the preset layouts to display title and/or introductory
96
+ # information, when set. Defaults to +nil+.
97
+ #
98
+ attr_accessor :header
99
+ #
100
+ # Used by all the preset layouts to ask the actual question to fetch a
101
+ # menu selection from the user. Defaults to "? ".
102
+ #
103
+ attr_accessor :prompt
104
+ #
105
+ # An ERb _layout_ to use when displaying this Menu object. See
106
+ # Menu.layout=() for details.
107
+ #
108
+ attr_reader :layout
109
+ #
110
+ # When set to +true+, responses are allowed to be an entire line of
111
+ # input, including details beyond the command itself. Only the first
112
+ # "word" of input will be matched against the menu choices, but both the
113
+ # command selected and the rest of the line will be passed to provided
114
+ # action blocks. Defaults to +false+.
115
+ #
116
+ attr_accessor :shell
117
+ #
118
+ # When +true+, any selected item handled by provided action code, will
119
+ # return +nil+, instead of the results to the action code. This may
120
+ # prove handy when dealing with mixed menus where only the names of
121
+ # items without any code (and +nil+, of course) will be returned.
122
+ # Defaults to +false+.
123
+ #
124
+ attr_accessor :nil_on_handled
125
+
126
+ #
127
+ # Adds _name_ to the list of available menu items. Menu items will be
128
+ # displayed in the order they are added.
129
+ #
130
+ # An optional _action_ can be associated with this name and if provided,
131
+ # it will be called if the item is selected. The result of the method
132
+ # will be returned, unless _nil_on_handled_ is set (when you would get
133
+ # +nil+ instead). In _shell_ mode, a provided block will be passed the
134
+ # command chosen and any details that followed the command. Otherwise,
135
+ # just the command is passed. The <tt>@highline</tt> variable is set to
136
+ # the current HighLine context before the action code is called and can
137
+ # thus be used for adding output and the like.
138
+ #
139
+ def choice( name, help = nil, &action )
140
+ @items << [name, action]
141
+
142
+ @help[name.to_s.downcase] = help unless help.nil?
143
+ end
144
+
145
+ #
146
+ # A shortcut for multiple calls to the sister method choice(). <b>Be
147
+ # warned:</b> An _action_ set here will apply to *all* provided
148
+ # _names_. This is considered to be a feature, so you can easily
149
+ # hand-off interface processing to a different chunk of code.
150
+ #
151
+ def choices( *names, &action )
152
+ names.each { |n| choice(n, &action) }
153
+ end
154
+
155
+ # Identical to choice(), but the item will not be listed for the user.
156
+ def hidden( name, help = nil, &action )
157
+ @hidden_items << [name, action]
158
+
159
+ @help[name.to_s.downcase] = help unless help.nil?
160
+ end
161
+
162
+ #
163
+ # Sets the indexing style for this Menu object. Indexes are appended to
164
+ # menu items, when displayed in list form. The available settings are:
165
+ #
166
+ # <tt>:number</tt>:: Menu items will be indexed numerically, starting
167
+ # with 1. This is the default method of indexing.
168
+ # <tt>:letter</tt>:: Items will be indexed alphabetically, starting
169
+ # with a.
170
+ # <tt>:none</tt>:: No index will be appended to menu items.
171
+ # <i>any String</i>:: Will be used as the literal _index_.
172
+ #
173
+ # Setting the _index_ to <tt>:none</tt> a literal String, also adjusts
174
+ # _index_suffix_ to a single space and _select_by_ to <tt>:none</tt>.
175
+ # Because of this, you should make a habit of setting the _index_ first.
176
+ #
177
+ def index=( style )
178
+ @index = style
179
+
180
+ # Default settings.
181
+ if @index == :none or @index.is_a?(String)
182
+ @index_suffix = " "
183
+ @select_by = :name
184
+ end
185
+ end
186
+
187
+ #
188
+ # Initializes the help system by adding a <tt>:help</tt> choice, some
189
+ # action code, and the default help listing.
190
+ #
191
+ def init_help( )
192
+ return if @items.include?(:help)
193
+
194
+ topics = @help.keys.sort
195
+ help_help = @help.include?("help") ? @help["help"] :
196
+ "This command will display helpful messages about " +
197
+ "functionality, like this one. To see the help for " +
198
+ "a specific topic enter:\n\thelp [TOPIC]\nTry asking " +
199
+ "for help on any of the following:\n\n" +
200
+ "<%= list(#{topics.inspect}, :columns_across) %>"
201
+ choice(:help, help_help) do |command, topic|
202
+ topic.strip!
203
+ topic.downcase!
204
+ if topic.empty?
205
+ @highline.say(@help["help"])
206
+ else
207
+ @highline.say("= #{topic}\n\n#{@help[topic]}")
208
+ end
209
+ end
210
+ end
211
+
212
+ #
213
+ # Used to set help for arbitrary topics. Use the topic <tt>"help"</tt>
214
+ # to override the default message.
215
+ #
216
+ def help( topic, help )
217
+ @help[topic] = help
218
+ end
219
+
220
+ #
221
+ # Setting a _layout_ with this method also adjusts some other attributes
222
+ # of the Menu object, to ideal defaults for the chosen _layout_. To
223
+ # account for that, you probably want to set a _layout_ first in your
224
+ # configuration block, if needed.
225
+ #
226
+ # Accepted settings for _layout_ are:
227
+ #
228
+ # <tt>:list</tt>:: The default _layout_. The _header_ if set
229
+ # will appear at the top on its own line with
230
+ # a trailing colon. Then the list of menu
231
+ # items will follow. Finally, the _prompt_
232
+ # will be used as the ask()-like question.
233
+ # <tt>:one_line</tt>:: A shorter _layout_ that fits on one line.
234
+ # The _header_ comes first followed by a
235
+ # colon and spaces, then the _prompt_ with menu
236
+ # items between trailing parenthesis.
237
+ # <tt>:menu_only</tt>:: Just the menu items, followed up by a likely
238
+ # short _prompt_.
239
+ # <i>any ERb String</i>:: Will be taken as the literal _layout_. This
240
+ # String can access <tt>@header</tt>,
241
+ # <tt>@menu</tt> and <tt>@prompt</tt>, but is
242
+ # otherwise evaluated in the typical HighLine
243
+ # context, to provide access to utilities like
244
+ # HighLine.list() primarily.
245
+ #
246
+ # If set to either <tt>:one_line</tt>, or <tt>:menu_only</tt>, _index_
247
+ # will default to <tt>:none</tt> and _flow_ will default to
248
+ # <tt>:inline</tt>.
249
+ #
250
+ def layout=( new_layout )
251
+ @layout = new_layout
252
+
253
+ # Default settings.
254
+ case @layout
255
+ when :one_line, :menu_only
256
+ self.index = :none
257
+ @flow = :inline
258
+ end
259
+ end
260
+
261
+ #
262
+ # This method returns all possible options for auto-completion, based
263
+ # on the settings of _index_ and _select_by_.
264
+ #
265
+ def options( )
266
+ # add in any hidden menu commands
267
+ @items.concat(@hidden_items)
268
+
269
+ by_index = if @index == :letter
270
+ l_index = "`"
271
+ @items.map { "#{l_index.succ!}" }
272
+ else
273
+ (1 .. @items.size).collect { |s| String(s) }
274
+ end
275
+ by_name = @items.collect { |c| c.first }
276
+
277
+ case @select_by
278
+ when :index then
279
+ by_index
280
+ when :name
281
+ by_name
282
+ else
283
+ by_index + by_name
284
+ end
285
+ ensure
286
+ # make sure the hidden items are removed, before we return
287
+ @items.slice!(@items.size - @hidden_items.size, @hidden_items.size)
288
+ end
289
+
290
+ #
291
+ # This method processes the auto-completed user selection, based on the
292
+ # rules for this Menu object. If an action was provided for the
293
+ # selection, it will be executed as described in Menu.choice().
294
+ #
295
+ def select( highline_context, selection, details = nil )
296
+ # add in any hidden menu commands
297
+ @items.concat(@hidden_items)
298
+
299
+ # Find the selected action.
300
+ name, action = if selection =~ /^\d+$/
301
+ @items[selection.to_i - 1]
302
+ else
303
+ l_index = "`"
304
+ index = @items.map { "#{l_index.succ!}" }.index(selection)
305
+ @items.find { |c| c.first == selection } or @items[index]
306
+ end
307
+
308
+ # Run or return it.
309
+ if not @nil_on_handled and not action.nil?
310
+ @highline = highline_context
311
+ if @shell
312
+ action.call(name, details)
313
+ else
314
+ action.call(name)
315
+ end
316
+ elsif action.nil?
317
+ name
318
+ else
319
+ nil
320
+ end
321
+ ensure
322
+ # make sure the hidden items are removed, before we return
323
+ @items.slice!(@items.size - @hidden_items.size, @hidden_items.size)
324
+ end
325
+
326
+ #
327
+ # Allows Menu objects to pass as Arrays, for use with HighLine.list().
328
+ # This method returns all menu items to be displayed, complete with
329
+ # indexes.
330
+ #
331
+ def to_ary( )
332
+ case @index
333
+ when :number
334
+ @items.map { |c| "#{@items.index(c) + 1}#{@index_suffix}#{c.first}" }
335
+ when :letter
336
+ l_index = "`"
337
+ @items.map { |c| "#{l_index.succ!}#{@index_suffix}#{c.first}" }
338
+ when :none
339
+ @items.map { |c| "#{c.first}" }
340
+ else
341
+ @items.map { |c| "#{index}#{@index_suffix}#{c.first}" }
342
+ end
343
+ end
344
+
345
+ #
346
+ # Allows Menu to behave as a String, just like Question. Returns the
347
+ # _layout_ to be rendered, which is used by HighLine.say().
348
+ #
349
+ def to_str( )
350
+ case @layout
351
+ when :list
352
+ '<%= if @header.nil? then '' else "#{@header}:\n" end %>' +
353
+ "<%= list( @menu, #{@flow.inspect},
354
+ #{@list_option.inspect} ) %>" +
355
+ "<%= @prompt %>"
356
+ when :one_line
357
+ '<%= if @header.nil? then '' else "#{@header}: " end %>' +
358
+ "<%= @prompt %>" +
359
+ "(<%= list( @menu, #{@flow.inspect},
360
+ #{@list_option.inspect} ) %>)" +
361
+ "<%= @prompt[/\s*$/] %>"
362
+ when :menu_only
363
+ "<%= list( @menu, #{@flow.inspect},
364
+ #{@list_option.inspect} ) %><%= @prompt %>"
365
+ else
366
+ @layout
367
+ end
368
+ end
369
+
370
+ #
371
+ # This method will update the intelligent responses to account for
372
+ # Menu specific differences. This overrides the work done by
373
+ # Question.build_responses().
374
+ #
375
+ def update_responses( )
376
+ append_default unless default.nil?
377
+ @responses = { :ambiguous_completion =>
378
+ "Ambiguous choice. " +
379
+ "Please choose one of #{options.inspect}.",
380
+ :ask_on_error =>
381
+ "? ",
382
+ :invalid_type =>
383
+ "You must enter a valid #{options}.",
384
+ :no_completion =>
385
+ "You must choose one of " +
386
+ "#{options.inspect}.",
387
+ :not_in_range =>
388
+ "Your answer isn't within the expected range " +
389
+ "(#{expected_range}).",
390
+ :not_valid =>
391
+ "Your answer isn't valid (must match " +
392
+ "#{@validate.inspect})." }.merge(@responses)
393
+ end
394
+ end
395
+ end