prompter 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/LICENSE +20 -0
- data/README.rdoc +54 -0
- data/Rakefile +60 -0
- data/VERSION +1 -0
- data/examples/wizard.rb +43 -0
- data/lib/prompter.rb +314 -0
- data/prompter.gemspec +27 -0
- data/test/ask.irt +38 -0
- data/test/choose.irt +29 -0
- data/test/irt_helper.rb +2 -0
- data/test/say.irt +90 -0
- data/test/yes_no.irt +10 -0
- metadata +128 -0
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Domizio Demichelis
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= Prompter
|
2
|
+
|
3
|
+
Makes your prompts easier to build and prettier to look.
|
4
|
+
|
5
|
+
== Synopsis
|
6
|
+
|
7
|
+
require 'prompter'
|
8
|
+
|
9
|
+
Prompter.new(:prefix => '** ') do |p|
|
10
|
+
p.say_notice 'You can avoid to extend your class with Prompter::Methods'
|
11
|
+
end
|
12
|
+
|
13
|
+
# or
|
14
|
+
|
15
|
+
prompter = Prompter.new
|
16
|
+
|
17
|
+
# or you can also extend your modules with:
|
18
|
+
|
19
|
+
extend Prompter::Methods
|
20
|
+
self.prefix = ' '
|
21
|
+
say 'This part uses imported method from Prompter::Methods'
|
22
|
+
|
23
|
+
ask 'Type some input:' do |input|
|
24
|
+
yes_no? "Do you want it or not?" do |yes|
|
25
|
+
if yes
|
26
|
+
say("#{input} is ok")
|
27
|
+
else
|
28
|
+
say_warning("#{input} may be dangerous")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# or
|
34
|
+
|
35
|
+
name = ask('write your name:')
|
36
|
+
yes? "are you sure?" { do_something_if_yes }
|
37
|
+
|
38
|
+
(see also the file "examples/wizard.rb")
|
39
|
+
|
40
|
+
== General Notes
|
41
|
+
|
42
|
+
Methods are callable directly on the Prompter class, on a Prompter object, included in your class as instance methods or class methods.
|
43
|
+
|
44
|
+
Some methods yield the block with the returned value, so you can use them as an easy way to construct hierarchical wizards.
|
45
|
+
|
46
|
+
Colorer styles are passable as an option to the called method, and can be redefined entirely by calling Colorer.def_*_styles.
|
47
|
+
|
48
|
+
== Documentation and Example
|
49
|
+
|
50
|
+
All the methods are yard-documented, and there is and 'example/wizard.rb' that could be useful.
|
51
|
+
|
52
|
+
== Copyright
|
53
|
+
|
54
|
+
Copyright (c) 2010 Domizio Demichelis. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
name = 'prompter'
|
2
|
+
|
3
|
+
def ensure_clean(action, force=false)
|
4
|
+
if !force && ! `git status -s`.empty?
|
5
|
+
puts <<-EOS.gsub(/^ {6}/, '')
|
6
|
+
Rake task aborted: the working tree is dirty!
|
7
|
+
If you know what you are doing you can use \`rake #{action}[force]\`"
|
8
|
+
EOS
|
9
|
+
exit(1)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Install the gem"
|
14
|
+
task :install, :force do |t, args|
|
15
|
+
ensure_clean(:install, args.force)
|
16
|
+
orig_version = version = File.read('VERSION').strip
|
17
|
+
begin
|
18
|
+
commit_id = `git log -1 --format="%h" HEAD`.strip
|
19
|
+
version = "#{orig_version}.#{commit_id}"
|
20
|
+
File.open('VERSION', 'w') {|f| f.puts version }
|
21
|
+
gem_name = "#{name}-#{version}.gem"
|
22
|
+
sh %(gem build #{name}.gemspec)
|
23
|
+
sh %(gem install #{gem_name} --local)
|
24
|
+
puts <<-EOS.gsub(/^ {6}/, '')
|
25
|
+
|
26
|
+
*******************************************************************************
|
27
|
+
* NOTICE *
|
28
|
+
*******************************************************************************
|
29
|
+
* The version id of locally installed gems is comparable to a --pre version: *
|
30
|
+
* i.e. it is alphabetically ordered (not numerically ordered), besides it *
|
31
|
+
* includes the sah1 commit id which is not aphabetically ordered, so be sure *
|
32
|
+
* your application picks the version you really intend to use *
|
33
|
+
*******************************************************************************
|
34
|
+
|
35
|
+
EOS
|
36
|
+
ensure
|
37
|
+
remove_entry_secure gem_name, true
|
38
|
+
File.open('VERSION', 'w') {|f| f.puts orig_version }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc %(Remove all the "#{name}" installed gems and executables and install this version)
|
43
|
+
task :clean_install, :force do |t, args|
|
44
|
+
ensure_clean(:install, args.force)
|
45
|
+
sh %(gem uninstall #{name} --all --ignore-dependencies --executables)
|
46
|
+
Rake::Task['install'].invoke(args.force)
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "Push the gem to rubygems.org"
|
50
|
+
task :push, :force do |t, args|
|
51
|
+
begin
|
52
|
+
ensure_clean(:install, args.force)
|
53
|
+
version = File.read('VERSION').strip
|
54
|
+
gem_name = "#{name}-#{version}.gem"
|
55
|
+
sh %(gem build #{name}.gemspec)
|
56
|
+
sh %(gem push #{gem_name})
|
57
|
+
ensure
|
58
|
+
remove_entry_secure gem_name, true
|
59
|
+
end
|
60
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/examples/wizard.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
require 'prompter'
|
4
|
+
|
5
|
+
|
6
|
+
Prompter.new(:prefix => '--- ') do |p|
|
7
|
+
p.say_notice 'You can avoid to extend your class with Prompter::Methods'
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
extend Prompter::Methods
|
13
|
+
|
14
|
+
self.prefix = '*** '
|
15
|
+
|
16
|
+
say 'This part uses imported method from Prompter::Methods'
|
17
|
+
|
18
|
+
yes_no?( 'Do you want to go on or not?') do |yes|
|
19
|
+
if yes
|
20
|
+
say 'Very good from you!'
|
21
|
+
choose('Do you want a, b or c?', /^a|b|c$/i, :hint => '[a|<enter>=b|c]', :default => 'b') do |choice|
|
22
|
+
case choice
|
23
|
+
when 'a'
|
24
|
+
say 'You have chosen A, but that is not good. END'
|
25
|
+
when 'b'
|
26
|
+
say 'You have chosen B. That is a good option!'
|
27
|
+
ask('Which name do you wanna have?', :hint => '[<enter>=user]', :default => 'user') do |name|
|
28
|
+
say "You have chosen '#{name}' and that's ok!"
|
29
|
+
end
|
30
|
+
when 'c'
|
31
|
+
say 'You have chosen C. Game over.'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
list = %w[alfa beta gamma delta]
|
36
|
+
choose_index('You should choose among this items:', list, :echo => false) do |index|
|
37
|
+
say "You have chosen '#{list[index]}', at index #{index}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
say '', :prefix => ''
|
42
|
+
say_notice 'The example is over'
|
43
|
+
|
data/lib/prompter.rb
ADDED
@@ -0,0 +1,314 @@
|
|
1
|
+
require 'colorer'
|
2
|
+
|
3
|
+
# @author Domizio Demichelis
|
4
|
+
#
|
5
|
+
class Prompter
|
6
|
+
|
7
|
+
VERSION = File.read(File.expand_path('../../VERSION', __FILE__)).strip
|
8
|
+
|
9
|
+
Colorer.def_custom_styles :say_style => nil,
|
10
|
+
:say_echo_style => nil,
|
11
|
+
:say_notice_style => :yellow,
|
12
|
+
:say_warning_style => :red,
|
13
|
+
:ask_style => :magenta,
|
14
|
+
:hint_style => :green
|
15
|
+
|
16
|
+
# Standard constructor, also accepts a block
|
17
|
+
#
|
18
|
+
# @param [Hash] opts The options to create a Prompter object.
|
19
|
+
# @option opts [String] :prefix The prefix string
|
20
|
+
# @option opts [Boolean] :echo when true adds a line with the result
|
21
|
+
#
|
22
|
+
def initialize(opts={})
|
23
|
+
@prefix = opts[:prefix]
|
24
|
+
@echo = opts[:echo] || true
|
25
|
+
yield self if block_given?
|
26
|
+
end
|
27
|
+
|
28
|
+
module Methods
|
29
|
+
|
30
|
+
attr_writer :echo, :prefix
|
31
|
+
|
32
|
+
# The echo instance option (true by default)
|
33
|
+
def echo
|
34
|
+
@echo ||= true
|
35
|
+
end
|
36
|
+
|
37
|
+
def prefix
|
38
|
+
@prefix ||= ''
|
39
|
+
end
|
40
|
+
|
41
|
+
# Shows a message
|
42
|
+
#
|
43
|
+
# @param [String] message Your message
|
44
|
+
#
|
45
|
+
# @param [Hash] opts the standard opts to pass along
|
46
|
+
# @option opts [String] :default The default choice when the user hits <enter> instead of any content
|
47
|
+
# @option opts [String] :prefix The prefix string
|
48
|
+
# @option opts [Boolean] :echo Adds a line showing the input (=> input)
|
49
|
+
# @option opts [String] :hint A string to show the available choices
|
50
|
+
# @option opts [Symbol] :style The Colorer style name to use for this prompt
|
51
|
+
# @option opts [Boolean] :force_new_line Forces the addition of a new line (otherwise determined by the end of the prompt string)
|
52
|
+
#
|
53
|
+
def say(message="", opts={})
|
54
|
+
message = message.to_s
|
55
|
+
opts = { :force_new_line => (message !~ /( |\t)$/),
|
56
|
+
:style => :say_style,
|
57
|
+
:prefix => prefix }.merge opts
|
58
|
+
message = message.send opts[:style] unless opts[:style].nil?
|
59
|
+
message = (opts[:prefix]||'') + message
|
60
|
+
$stdout.send((opts[:force_new_line] ? :puts : :print), message)
|
61
|
+
$stdout.flush
|
62
|
+
end
|
63
|
+
|
64
|
+
# Shows a colored message. It uses :say passing the :say_notice_style :style option
|
65
|
+
#
|
66
|
+
# @see #say
|
67
|
+
#
|
68
|
+
def say_notice(message="", opts={})
|
69
|
+
opts = { :style => :say_notice_style }.merge opts
|
70
|
+
say message, opts
|
71
|
+
end
|
72
|
+
|
73
|
+
# Shows a red colored message. It uses :say passing the :say_warning_style :style option,
|
74
|
+
# besides it adds an audible bell character to the message. Pass :mute => true to mute.
|
75
|
+
#
|
76
|
+
# @see #say
|
77
|
+
#
|
78
|
+
def say_warning(message="", opts={})
|
79
|
+
opts = { :style => :say_warning_style }.merge opts
|
80
|
+
message = "\a" + message unless opts[:mute]
|
81
|
+
say message, opts
|
82
|
+
end
|
83
|
+
|
84
|
+
# Asks for an input
|
85
|
+
#
|
86
|
+
# @param [String] prompt Your question
|
87
|
+
#
|
88
|
+
# @param [Hash] opts the standard opts to pass along (see #say
|
89
|
+
#
|
90
|
+
# for block {|input| ... }
|
91
|
+
# @yield [input] yields the block with the user input
|
92
|
+
# @yieldparam [String] input user input
|
93
|
+
# @return [String] The user input
|
94
|
+
#
|
95
|
+
def ask(prompt, opts={})
|
96
|
+
opts = { :style => :ask_style,
|
97
|
+
:hint => '',
|
98
|
+
:default => '' }.merge opts
|
99
|
+
force_new_line = !!opts.delete(:force_new_line) unless opts[:hint].empty?
|
100
|
+
prompt = prompt + ' ' unless opts[:force_new_line]
|
101
|
+
say prompt, opts
|
102
|
+
say_hint(opts[:hint], opts.merge({:force_new_line => !!force_new_line})) unless opts[:hint].empty?
|
103
|
+
input = $stdin.gets || '' # multilines ended at start generate a nil
|
104
|
+
input.strip!
|
105
|
+
input = opts[:default].to_s if input.empty?
|
106
|
+
opts.delete(:style) # :style is not passed
|
107
|
+
say_echo input, opts
|
108
|
+
block_given? ? yield(input) : input
|
109
|
+
end
|
110
|
+
|
111
|
+
# Asks for a multiline input
|
112
|
+
#
|
113
|
+
# @param [String] prompt Your question
|
114
|
+
#
|
115
|
+
# @param [Hash] opts the standard opts to pass along (see #say, plus the followings)
|
116
|
+
# @option opts [String] :input_end Used to end the input (default nil: requires ^D to end the input)
|
117
|
+
# @option opts [Boolean] :force_new_line Default to true
|
118
|
+
#
|
119
|
+
# for block {|input| ... }
|
120
|
+
# @yield [input] yields the block with the user input
|
121
|
+
# @yieldparam [String] input user input
|
122
|
+
# @return [String] The user input (with the eventual :input_end line removed)
|
123
|
+
#
|
124
|
+
def ask_multiline(prompt, opts={})
|
125
|
+
opts = { :input_end => nil,
|
126
|
+
:force_new_line => true,
|
127
|
+
:hint => %([end the input by typing "#{opts[:input_end] || '^D'}" in a new line]) }.merge opts
|
128
|
+
old_separator = $/
|
129
|
+
$/ = opts.delete(:input_end)
|
130
|
+
input = ask(prompt, opts).sub(/\n#{$/}$/, '')
|
131
|
+
$/ = old_separator
|
132
|
+
block_given? ? yield(input) : input
|
133
|
+
end
|
134
|
+
|
135
|
+
# Chooses among different choices
|
136
|
+
#
|
137
|
+
# @param [String] prompt Your question
|
138
|
+
# @param [RegExp, Proc] validation Validates the input
|
139
|
+
#
|
140
|
+
# @param [Hash] opts the standard opts to pass along (see #say)
|
141
|
+
#
|
142
|
+
# @yield [input] yields the block with the user-chosen input
|
143
|
+
# @yieldparam [String] input The user input
|
144
|
+
# @return [String] The user-chosen input
|
145
|
+
#
|
146
|
+
def choose(prompt, validation, opts={}, &block)
|
147
|
+
choice = ask prompt, opts
|
148
|
+
if valid_choice?(validation, choice)
|
149
|
+
block_given? ? yield(choice) : choice
|
150
|
+
else
|
151
|
+
say_warning 'Unknown choice!'
|
152
|
+
choose(prompt, validation, opts, &block)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Chooses many among different choices
|
157
|
+
#
|
158
|
+
# @param [String] prompt Your question
|
159
|
+
# @param [RegExp, Proc] validation Validates the input
|
160
|
+
#
|
161
|
+
# @param [Hash] opts the standard opts to pass along (see #say, plus the followings)
|
162
|
+
# @option opts [String, RegExp] :split Used to split the input (see String#split)
|
163
|
+
#
|
164
|
+
# @yield [input] yields the block with the user-chosen array of input
|
165
|
+
# @yieldparam [Array] input The user array of input
|
166
|
+
# @return [Array] The user-chosen array of input
|
167
|
+
#
|
168
|
+
def choose_many(prompt, validation, opts={}, &block)
|
169
|
+
choices = ask(prompt, opts).split(opts[:split])
|
170
|
+
if choices.all? {|c| valid_choice?(validation, c)}
|
171
|
+
block_given? ? yield(choices) : choices
|
172
|
+
else
|
173
|
+
say_warning 'One or more choices are unknown!'
|
174
|
+
choose_many(prompt, validation, opts, &block)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
# Asks a yes/no question and yields the block with the resulting Boolean
|
180
|
+
#
|
181
|
+
# @param [Hash] opts the standard opts to pass along (see #say)
|
182
|
+
#
|
183
|
+
# @yield yields the block always with a Boolean
|
184
|
+
# @yieldparam [Boolean]
|
185
|
+
# @return [Boolean] true for 'y' and false for 'n'
|
186
|
+
#
|
187
|
+
def yes_no?(prompt, opts={})
|
188
|
+
opts = { :hint => '[y|n]' }.merge opts
|
189
|
+
choice = choose(prompt, /^y|n$/i, opts)
|
190
|
+
result = choice.match(/^y$/i) ? true : false
|
191
|
+
block_given? ? yield(result) : result
|
192
|
+
end
|
193
|
+
|
194
|
+
# Asks a yes/no question and yields the block only when the answer is yes
|
195
|
+
#
|
196
|
+
# @param [String] prompt Your question
|
197
|
+
#
|
198
|
+
# @param [Hash] opts the standard opts to pass along (see #say)
|
199
|
+
#
|
200
|
+
# @yield yields the block when the answer is 'y'
|
201
|
+
# @return [Boolean] true for 'y' and false for 'n'
|
202
|
+
#
|
203
|
+
def yes?(prompt, opts={})
|
204
|
+
result = yes_no? prompt, opts
|
205
|
+
(block_given? && result) ? yield : result
|
206
|
+
end
|
207
|
+
|
208
|
+
# Asks a yes/no question and yields the block only when the answer is no
|
209
|
+
#
|
210
|
+
# @param [String] prompt Your question
|
211
|
+
#
|
212
|
+
# @param [Hash] opts the standard opts to pass along (see #say)
|
213
|
+
#
|
214
|
+
# @yield yields the block when the answer is no
|
215
|
+
# @return [Boolean] true for 'y' and false for 'n'
|
216
|
+
#
|
217
|
+
def no?(prompt, opts={})
|
218
|
+
result = yes_no? prompt, opts
|
219
|
+
(block_given? && !result) ? yield : result
|
220
|
+
end
|
221
|
+
|
222
|
+
# Chooses among different choices in an indexed list
|
223
|
+
#
|
224
|
+
# @param [String] prompt Your question
|
225
|
+
# @param [Array] list The list of choices
|
226
|
+
#
|
227
|
+
# @param [Hash] opts the standard opts to pass along (see #say)
|
228
|
+
#
|
229
|
+
# @yield yields the block with the user-chosen input
|
230
|
+
# @yieldparam [Integer] index The index number
|
231
|
+
# @return [Integer] The index number from the list referring to the user-chosen input
|
232
|
+
#
|
233
|
+
def choose_index(prompt, list, opts={})
|
234
|
+
opts = list_choices(prompt, list, opts)
|
235
|
+
choice = choose ">", lambda{|v| (1..list.size).map(&:to_s).include?(v) }, opts
|
236
|
+
index = choice.to_i-1
|
237
|
+
block_given? ? yield(index) : index
|
238
|
+
end
|
239
|
+
|
240
|
+
# Chooses many among different choices in an indexed list
|
241
|
+
#
|
242
|
+
# @param [String] prompt Your question
|
243
|
+
# @param [Array] list The list of choices
|
244
|
+
#
|
245
|
+
# @param [Hash] opts the standard opts to pass along (see #say, plus the followings)
|
246
|
+
# @option opts [String, RegExp] :split Used to split the input (see String#split)
|
247
|
+
#
|
248
|
+
# @yield [input] yields the block with the user-chosen array of input
|
249
|
+
# @yieldparam [Array] indexes The user-chosen array of indexes
|
250
|
+
# @return [Array] The user-chosen array of indexes
|
251
|
+
#
|
252
|
+
def choose_many_index(prompt, list, opts={})
|
253
|
+
opts = list_choices(prompt, list, opts, true)
|
254
|
+
choices = choose_many ">", lambda{|v| (1..list.size).map(&:to_s).include?(v) }, opts
|
255
|
+
indexes = choices.map {|i| i.to_i-1 }
|
256
|
+
block_given? ? yield(indexes) : indexes
|
257
|
+
end
|
258
|
+
|
259
|
+
protected
|
260
|
+
|
261
|
+
# used internally to show a feedback of the input
|
262
|
+
def say_echo(result, opts={})
|
263
|
+
opts = { :style => :say_echo_style,
|
264
|
+
:echo => echo,
|
265
|
+
:prefix => ' ' * prefix.to_s.size }.merge opts
|
266
|
+
say( ('=> ' + result.inspect), opts ) if opts[:echo]
|
267
|
+
result
|
268
|
+
end
|
269
|
+
|
270
|
+
# used internally to show the hints
|
271
|
+
def say_hint(hint, opts={})
|
272
|
+
return if hint.empty?
|
273
|
+
opts.merge!( { :style => :hint_style} ) # hint is always :hint_style
|
274
|
+
opts = {:prefix => '' }.merge opts
|
275
|
+
hint = hint + ' ' unless opts[:force_new_line]
|
276
|
+
say hint, opts
|
277
|
+
end
|
278
|
+
|
279
|
+
private
|
280
|
+
|
281
|
+
def valid_choice?(validation, choice)
|
282
|
+
(validation.is_a?(Regexp) && validation.match(choice)) ||
|
283
|
+
(validation.is_a?(Proc) && validation.call(choice))
|
284
|
+
end
|
285
|
+
|
286
|
+
def list_choices(prompt, list, opts={}, many=false)
|
287
|
+
hint = many ? "[choose one or more in range 1..#{list.size} (#{opts[:split].nil? ? '<space>' : opts[:split].inspect} splitted)]" :
|
288
|
+
"[choose one in range 1..#{list.size}]"
|
289
|
+
opts = { :style => :ask_style,
|
290
|
+
:hint => hint }.merge opts
|
291
|
+
say prompt, opts
|
292
|
+
list.each_with_index do |item, index|
|
293
|
+
say_hint (index+1).to_s.rjust(count_digits(list.size)) + '.', :prefix => ' ' * (prefix.to_s.length)
|
294
|
+
say item, :prefix => ''
|
295
|
+
end
|
296
|
+
opts
|
297
|
+
end
|
298
|
+
|
299
|
+
def count_digits(number)
|
300
|
+
num = number.abs
|
301
|
+
count = 0
|
302
|
+
while num >= 1
|
303
|
+
num = num / 10
|
304
|
+
count += 1
|
305
|
+
end
|
306
|
+
count
|
307
|
+
end
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
extend Methods
|
312
|
+
include Methods
|
313
|
+
|
314
|
+
end
|
data/prompter.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
name = File.basename( __FILE__, '.gemspec' )
|
2
|
+
version = File.read(File.expand_path('../VERSION', __FILE__)).strip
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
|
7
|
+
s.authors = ["Domizio Demichelis"]
|
8
|
+
s.email = 'dd.nexus@gmail.com'
|
9
|
+
s.homepage = "http://github.com/ddnexus/#{name}"
|
10
|
+
s.summary = 'Makes your prompts easier to build and prettier to look'
|
11
|
+
s.description = 'A few helpers to create colored, multistep and hierarchical wizards'
|
12
|
+
|
13
|
+
s.add_runtime_dependency('colorer', [">= 0.7.0"])
|
14
|
+
s.add_runtime_dependency('yard', [">= 0.6.3"])
|
15
|
+
s.add_development_dependency('irt', [">= 1.0.9"])
|
16
|
+
|
17
|
+
s.files = `git ls-files -z`.split("\0")
|
18
|
+
|
19
|
+
s.name = name
|
20
|
+
s.version = version
|
21
|
+
s.date = Date.today.to_s
|
22
|
+
|
23
|
+
s.required_rubygems_version = ">= 1.3.6"
|
24
|
+
s.has_rdoc = 'yard'
|
25
|
+
s.require_paths = ["lib"]
|
26
|
+
|
27
|
+
end
|
data/test/ask.irt
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
extend Prompter::Methods
|
2
|
+
|
3
|
+
desc "intaractive ask"
|
4
|
+
say "You should see the next line in :ask_style"
|
5
|
+
ask "Please, write the word 'pippo':"
|
6
|
+
_eql?( "pippo" )
|
7
|
+
|
8
|
+
Colorer.def_basic_styles :red, true
|
9
|
+
desc "intaractive default ask"
|
10
|
+
say "You should see the next line in :red, and padded with 4 spaces"
|
11
|
+
ask "Please, type <enter>:", :default => 'default', :style => :red, :prefix => ' '
|
12
|
+
_eql?( "default" )
|
13
|
+
|
14
|
+
desc "ask_multiline default"
|
15
|
+
say "Please, enter some multiline data"
|
16
|
+
ml = ask_multiline "Add your data below..."
|
17
|
+
_eql?( ml )
|
18
|
+
say "<START-INPUT>#{ml}<END-INPUT>"
|
19
|
+
|
20
|
+
desc "ask_multiline with <END> input_end, no hints"
|
21
|
+
say "Please, enter some multiline data"
|
22
|
+
ml = ask_multiline "Add your data below (no hints)... and type <END> to end the input",
|
23
|
+
:input_end => '<END>',
|
24
|
+
:hint => ''
|
25
|
+
_eql?( ml )
|
26
|
+
say "<START-INPUT>#{ml}<END-INPUT>"
|
27
|
+
|
28
|
+
desc "ask_multiline with <END> input_end and hints"
|
29
|
+
say "Please, enter some multiline data"
|
30
|
+
ml = ask_multiline "Add your data below...",
|
31
|
+
:hint => '[end the input by typing <END> in a new line]',
|
32
|
+
:input_end => '<END>'
|
33
|
+
_eql?( ml )
|
34
|
+
say "<START-INPUT>#{ml}<END-INPUT>"
|
35
|
+
|
36
|
+
|
37
|
+
irt
|
38
|
+
|
data/test/choose.irt
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
extend Prompter::Methods
|
2
|
+
|
3
|
+
desc "simple choice with lambda"
|
4
|
+
choose "Choose from a, b or c (choose something different from a|b|c first, then choose 'b')", lambda{|v| v.match(/^(a|b|c)$/i)}, :hint => "[a|b|c]"
|
5
|
+
_eql?( "b" )
|
6
|
+
|
7
|
+
desc "simple choice with default and RE"
|
8
|
+
choose "Choose from [a|b|c] (type <enter> for 'b')", /^(a|b|c)$/i, :default => "b"
|
9
|
+
_eql?( "b" )
|
10
|
+
|
11
|
+
desc "choose index"
|
12
|
+
choose_index "Chose one of... (type '3')", %w[alpha beta gamma delta]
|
13
|
+
_eql?( 2 )
|
14
|
+
|
15
|
+
desc "chose many"
|
16
|
+
choose_many "Chose one or more among [a|b|c] (type 'b c')", /^(a|b|c)$/i
|
17
|
+
_eql?( %w[b c] )
|
18
|
+
|
19
|
+
desc "chose many different split"
|
20
|
+
choose_many "Chose one or more among [a b c] (type 'b;c')", /^(a|b|c)$/i, :split => ';'
|
21
|
+
_eql?( %w[b c] )
|
22
|
+
|
23
|
+
desc "chose many index"
|
24
|
+
choose_many_index "Chose one or more... (type '2 3')", %w[alpha beta gamma delta]
|
25
|
+
_eql?( [1, 2] )
|
26
|
+
|
27
|
+
desc "chose many index different split RE"
|
28
|
+
choose_many_index "Chose one or more... (type '2;3')", %w[alpha beta gamma delta], :split => /;/
|
29
|
+
_eql?( [1, 2] )
|
data/test/irt_helper.rb
ADDED
data/test/say.irt
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
|
2
|
+
desc "say no options"
|
3
|
+
capture {Prompter.say "test"}
|
4
|
+
_eql?( "test\n" )
|
5
|
+
|
6
|
+
desc "say with final space"
|
7
|
+
capture {Prompter.say "test "}
|
8
|
+
_eql?( "test " )
|
9
|
+
|
10
|
+
desc "say without force_new_line"
|
11
|
+
capture {Prompter.say "test", :force_new_line => false}
|
12
|
+
_eql?( "test" )
|
13
|
+
|
14
|
+
desc "prefix default"
|
15
|
+
Prompter.prefix = "--- "
|
16
|
+
capture { Prompter.say "prefix test" }
|
17
|
+
_eql? <<EOS
|
18
|
+
--- prefix test
|
19
|
+
EOS
|
20
|
+
|
21
|
+
desc "prefix override"
|
22
|
+
capture { Prompter.say "prefix test", :prefix => ""}
|
23
|
+
_eql? <<EOS
|
24
|
+
prefix test
|
25
|
+
EOS
|
26
|
+
|
27
|
+
desc "style override"
|
28
|
+
Colorer.def_basic_styles :magenta
|
29
|
+
capture { Prompter.say "style override", :style => :magenta }
|
30
|
+
_eql?( "--- \e[0m\e[35mstyle override\e[0m\n" )
|
31
|
+
|
32
|
+
class ExtendedByPrompter
|
33
|
+
extend Prompter::Methods
|
34
|
+
include Prompter::Methods
|
35
|
+
|
36
|
+
def self.something
|
37
|
+
say "something easy"
|
38
|
+
end
|
39
|
+
|
40
|
+
def something
|
41
|
+
say "something easy"
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.other_padded
|
45
|
+
say "something not padded", :prefix => ""
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
ExtendedByPrompter.prefix = "*** "
|
51
|
+
desc "prefix new default in extended class"
|
52
|
+
capture { ExtendedByPrompter.something }
|
53
|
+
_eql?( "*** something easy\n" )
|
54
|
+
|
55
|
+
desc "prefix override in extended class"
|
56
|
+
capture { ExtendedByPrompter.other_padded }
|
57
|
+
_eql? <<EOS
|
58
|
+
something not padded
|
59
|
+
EOS
|
60
|
+
|
61
|
+
obj = ExtendedByPrompter.new
|
62
|
+
desc "object prefix is default"
|
63
|
+
obj.prefix
|
64
|
+
_eql?( "" )
|
65
|
+
|
66
|
+
desc "object method included"
|
67
|
+
capture { obj.something }
|
68
|
+
_eql? <<EOS
|
69
|
+
something easy
|
70
|
+
EOS
|
71
|
+
|
72
|
+
desc "say no style"
|
73
|
+
capture { Prompter.say "no style", :style => nil }
|
74
|
+
_eql? <<EOS
|
75
|
+
--- no style
|
76
|
+
EOS
|
77
|
+
|
78
|
+
desc "alert sound with say_warning"
|
79
|
+
Prompter.say_warning "You should hear a sound with this message"
|
80
|
+
Prompter.yes_no? "Did you hear it?"
|
81
|
+
_eql?( true )
|
82
|
+
|
83
|
+
desc "silend say_warning"
|
84
|
+
Prompter.say_warning "This should be silent", :mute=>true
|
85
|
+
Prompter.yes_no? "Was it silent?"
|
86
|
+
_eql?( true )
|
87
|
+
|
88
|
+
desc "alert sound with yes/no question"
|
89
|
+
Prompter.yes_no? "\aThis is embedded in the question: did you hear it"
|
90
|
+
_eql?( true )
|
data/test/yes_no.irt
ADDED
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: prompter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Domizio Demichelis
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-27 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: colorer
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 7
|
33
|
+
- 0
|
34
|
+
version: 0.7.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: yard
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 1
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 6
|
49
|
+
- 3
|
50
|
+
version: 0.6.3
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: irt
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 5
|
62
|
+
segments:
|
63
|
+
- 1
|
64
|
+
- 0
|
65
|
+
- 9
|
66
|
+
version: 1.0.9
|
67
|
+
type: :development
|
68
|
+
version_requirements: *id003
|
69
|
+
description: A few helpers to create colored, multistep and hierarchical wizards
|
70
|
+
email: dd.nexus@gmail.com
|
71
|
+
executables: []
|
72
|
+
|
73
|
+
extensions: []
|
74
|
+
|
75
|
+
extra_rdoc_files: []
|
76
|
+
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- LICENSE
|
80
|
+
- README.rdoc
|
81
|
+
- Rakefile
|
82
|
+
- VERSION
|
83
|
+
- examples/wizard.rb
|
84
|
+
- lib/prompter.rb
|
85
|
+
- prompter.gemspec
|
86
|
+
- test/ask.irt
|
87
|
+
- test/choose.irt
|
88
|
+
- test/irt_helper.rb
|
89
|
+
- test/say.irt
|
90
|
+
- test/yes_no.irt
|
91
|
+
has_rdoc: yard
|
92
|
+
homepage: http://github.com/ddnexus/prompter
|
93
|
+
licenses: []
|
94
|
+
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
hash: 3
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
hash: 23
|
115
|
+
segments:
|
116
|
+
- 1
|
117
|
+
- 3
|
118
|
+
- 6
|
119
|
+
version: 1.3.6
|
120
|
+
requirements: []
|
121
|
+
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 1.3.7
|
124
|
+
signing_key:
|
125
|
+
specification_version: 3
|
126
|
+
summary: Makes your prompts easier to build and prettier to look
|
127
|
+
test_files: []
|
128
|
+
|