easyprompt 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/easyprompt.rb +178 -0
- metadata +48 -0
data/lib/easyprompt.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'lafcadio'
|
2
|
+
|
3
|
+
# EasyPrompt is a utility for command-line scripts. It handles prompts and default values, and also provides a testing facility for mocking out the command-line user.
|
4
|
+
#
|
5
|
+
# For example, here's an irb session that illustrates what EasyPrompt does:
|
6
|
+
#
|
7
|
+
# irb(main):001:0> require 'easyprompt'
|
8
|
+
# => true
|
9
|
+
# irb(main):002:0> prompt = EasyPrompt.new
|
10
|
+
# => #<EasyPrompt:0x5a42a0 @stdout=#<EasyPrompt::MockableStdout:0x5a3e04>>
|
11
|
+
# irb(main):003:0> fname = prompt.ask( "What's your first name?" )
|
12
|
+
# What's your first name? John
|
13
|
+
# => "John"
|
14
|
+
# irb(main):004:0> lname = prompt.ask( "What's your last name?", "Doe" )
|
15
|
+
# What's your last name? [Doe]
|
16
|
+
# => "Doe"
|
17
|
+
# irb(main):005:0> correct = prompt.ask( "Is your name #{ fname } #{ lname }?", true, :boolean )
|
18
|
+
# Is your name John Doe? [y]
|
19
|
+
# => true
|
20
|
+
#
|
21
|
+
# In the first example, we ask for the user's first name and get "John" as the response. In the second example, we supply the default of "Doe", which the user chooses by just pressing the "Enter" key. In the third example, we supply the default of +true+, which the user chooses as well. We received the boolean value +true+ as opposed to the string "true" or "y", because we specified <tt>:boolean</tt> as the +response_class+.
|
22
|
+
class EasyPrompt
|
23
|
+
Version = '0.1.0'
|
24
|
+
|
25
|
+
def initialize; @stdout = MockableStdout.get_mockable_stdout; end
|
26
|
+
|
27
|
+
# Asks the user for input.
|
28
|
+
# msg:: The prompt that tells the user what information to enter next.
|
29
|
+
# default:: The default value that will be returned if the user enters a newline (usually by pressing "Enter") without typing any information. The default value will be displayed in square brackets after +msg+.
|
30
|
+
# response_class:: The sort of value that EasyPrompt#ask should return. Valid response classes are:
|
31
|
+
# [:string] This is the default.
|
32
|
+
# [:boolean] Values will be turned into <tt>true</tt> or <tt>false</tt> depending on whether the user enters "y" or "n".
|
33
|
+
def ask( msg, default = nil, response_class = :string )
|
34
|
+
@stdout.write( prompt( msg, default, response_class ) + ' ' )
|
35
|
+
stdin = MockableStdin.get_mockable_stdin
|
36
|
+
response = stdin.gets
|
37
|
+
response.chomp!
|
38
|
+
if response == ''
|
39
|
+
response = default
|
40
|
+
else
|
41
|
+
response = response =~ /^y/i if response_class == :boolean
|
42
|
+
end
|
43
|
+
response
|
44
|
+
end
|
45
|
+
|
46
|
+
def prompt( msg, default = nil, response_class = :string ) #:nodoc:
|
47
|
+
prompt = msg
|
48
|
+
unless default.nil?
|
49
|
+
if response_class == :boolean
|
50
|
+
default_str = default ? 'y' : 'n'
|
51
|
+
else
|
52
|
+
default_str = default.to_s
|
53
|
+
end
|
54
|
+
prompt += " [#{ default_str }]"
|
55
|
+
end
|
56
|
+
prompt
|
57
|
+
end
|
58
|
+
|
59
|
+
# The MockCommandLineUser can be used if you want to unit-test the command-line part of a program.
|
60
|
+
#
|
61
|
+
# irb(main):001:0> require 'easyprompt'
|
62
|
+
# => true
|
63
|
+
# irb(main):002:0> user = EasyPrompt::MockCommandLineUser.new
|
64
|
+
# => #<EasyPrompt::MockCommandLineUser:0x595818 @match_count={},
|
65
|
+
# @mock_stdout=#<StringIO:0x5949b8>, @mock_stdin=#<StringIO:0x595750>,
|
66
|
+
# @responses={}>
|
67
|
+
# irb(main):003:0> prompt = EasyPrompt.new
|
68
|
+
# => #<EasyPrompt:0x57d894 @stdout=#<StringIO:0x5949b8>>
|
69
|
+
# irb(main):004:0> prompt.ask( "Prepared for this one?" )
|
70
|
+
# RuntimeError: Can't match "Prepared for this one? "
|
71
|
+
# from /usr/local/lib/ruby/site_ruby/1.8/easyprompt.rb:79:in `match_regexp'
|
72
|
+
# from /usr/local/lib/ruby/site_ruby/1.8/easyprompt.rb:95:in `update'
|
73
|
+
# from /usr/local/lib/ruby/1.8/observer.rb:185:in `notify_observers'
|
74
|
+
# from /usr/local/lib/ruby/1.8/observer.rb:184:in `each'
|
75
|
+
# from /usr/local/lib/ruby/1.8/observer.rb:184:in `notify_observers'
|
76
|
+
# from /usr/local/lib/ruby/site_ruby/1.8/easyprompt.rb:128:in `gets'
|
77
|
+
# from /usr/local/lib/ruby/site_ruby/1.8/easyprompt.rb:36:in `ask'
|
78
|
+
# from (irb):4
|
79
|
+
# irb(main):005:0> user.set_response( /about this one/, "sure!" )
|
80
|
+
# => ["sure!", nil]
|
81
|
+
# irb(main):006:0> prompt.ask( "How about this one?" )
|
82
|
+
# => "sure!"
|
83
|
+
# irb(main):007:0> user.set_response( /twice/, "no", 1 )
|
84
|
+
# => ["no", 1]
|
85
|
+
# irb(main):008:0> prompt.ask( "Can I ask you this twice?" )
|
86
|
+
# => "no"
|
87
|
+
# irb(main):009:0> prompt.ask( "Can I ask you this twice?" )
|
88
|
+
# RuntimeError: Exceeded limit of 1 for (?-mix:twice)
|
89
|
+
# from /usr/local/lib/ruby/site_ruby/1.8/easyprompt.rb:101:in `update'
|
90
|
+
# from /usr/local/lib/ruby/1.8/observer.rb:185:in `notify_observers'
|
91
|
+
# from /usr/local/lib/ruby/1.8/observer.rb:184:in `each'
|
92
|
+
# from /usr/local/lib/ruby/1.8/observer.rb:184:in `notify_observers'
|
93
|
+
# from /usr/local/lib/ruby/site_ruby/1.8/easyprompt.rb:128:in `gets'
|
94
|
+
# from /usr/local/lib/ruby/site_ruby/1.8/easyprompt.rb:36:in `ask'
|
95
|
+
# from (irb):9
|
96
|
+
class MockCommandLineUser
|
97
|
+
# Initializes the MockCommandLineUser. Once a MockCommandLineUser has been
|
98
|
+
# instantiated, it will automatically intercept the calls that EasyPrompt
|
99
|
+
# makes to STDIN and STDOUT. Future calls to EasyPrompt#ask will check
|
100
|
+
# against the list of responses contained in MockCommandLineUser; if there
|
101
|
+
# is no match, an error will be raised. Use set_response to add a response.
|
102
|
+
def initialize
|
103
|
+
@responses = {}
|
104
|
+
@match_count = Hash.new( 1 )
|
105
|
+
context = Lafcadio::Context.instance
|
106
|
+
@mock_stdin = StringIO.new
|
107
|
+
@mock_stdin.add_observer( self )
|
108
|
+
context.set_resource( MockableStdin, @mock_stdin )
|
109
|
+
@mock_stdout = StringIO.new
|
110
|
+
context.set_resource( MockableStdout, @mock_stdout )
|
111
|
+
end
|
112
|
+
|
113
|
+
def match_regexp #:nodoc:
|
114
|
+
arg = @mock_stdout.string
|
115
|
+
@mock_stdout.string = ''
|
116
|
+
matching = @responses.map { |regexp, response_pair |
|
117
|
+
( loc = arg =~ regexp ) ? [ regexp, loc ] : nil
|
118
|
+
}
|
119
|
+
matching.compact!
|
120
|
+
fail "Can't match \"#{ arg }\"" if matching.empty?
|
121
|
+
( matching.sort_by { |regexp, loc| loc } ).last.first
|
122
|
+
end
|
123
|
+
|
124
|
+
def respond( response ) #:nodoc:
|
125
|
+
response = response.instance_of?( String ) ? response : response.call
|
126
|
+
@mock_stdin.string = ''
|
127
|
+
@mock_stdin.puts( response )
|
128
|
+
@mock_stdin.rewind
|
129
|
+
end
|
130
|
+
|
131
|
+
# Adds a response to the list of responses.
|
132
|
+
# input_regexp:: The regexp that each EasyPrompt#ask prompt is compared to.
|
133
|
+
# response:: The value returned.
|
134
|
+
# limit:: The maximum number of times this response can be used.
|
135
|
+
def set_response( input_regexp, response, limit = nil )
|
136
|
+
@responses[input_regexp] = [ response, limit ]
|
137
|
+
end
|
138
|
+
|
139
|
+
def update #:nodoc:
|
140
|
+
regexp = match_regexp
|
141
|
+
if regexp && ( @responses[regexp].last.nil? ||
|
142
|
+
@match_count[regexp] <= @responses[regexp].last )
|
143
|
+
respond( @responses[regexp].first )
|
144
|
+
@match_count[regexp] += 1
|
145
|
+
elsif regexp
|
146
|
+
raise "Exceeded limit of #{ @responses[regexp].last } for #{ regexp }"
|
147
|
+
else
|
148
|
+
raise "Can't find a response for " + arg
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class MockableStdin < Lafcadio::ContextualService #:nodoc:
|
154
|
+
def method_missing( symbol, *args )
|
155
|
+
$stdin.send( symbol, *args )
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class MockableStdout < Lafcadio::ContextualService #:nodoc:
|
160
|
+
def method_missing( symbol, *args )
|
161
|
+
$stdout.send( symbol, *args )
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# EasyPrompt modifies StringIO to be Observable; whenever gets is called, the
|
167
|
+
# StringIO's observers are notified.
|
168
|
+
class StringIO
|
169
|
+
include Observable
|
170
|
+
|
171
|
+
alias_method :old_gets, :gets
|
172
|
+
|
173
|
+
def gets
|
174
|
+
changed
|
175
|
+
notify_observers
|
176
|
+
old_gets
|
177
|
+
end
|
178
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.1
|
3
|
+
specification_version: 1
|
4
|
+
name: easyprompt
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2005-01-13
|
8
|
+
summary: EasyPrompt is a utility for command-line scripts.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
author: Francis Hwang
|
12
|
+
email: sera@fhwang.net
|
13
|
+
homepage: http://easyprompt.rubyforge.org/
|
14
|
+
rubyforge_project:
|
15
|
+
description: "EasyPrompt is a utility for command-line scripts. It handles prompts and default
|
16
|
+
values, and also provides a testing facility for mocking out the command-line
|
17
|
+
user."
|
18
|
+
autorequire: easyprompt
|
19
|
+
default_executable:
|
20
|
+
bindir: bin
|
21
|
+
has_rdoc: false
|
22
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
23
|
+
requirements:
|
24
|
+
-
|
25
|
+
- ">"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.0.0
|
28
|
+
version:
|
29
|
+
platform: ruby
|
30
|
+
files:
|
31
|
+
- lib/easyprompt.rb
|
32
|
+
test_files: []
|
33
|
+
rdoc_options: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
requirements: []
|
38
|
+
dependencies:
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: lafcadio
|
41
|
+
version_requirement:
|
42
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
43
|
+
requirements:
|
44
|
+
-
|
45
|
+
- ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.6.0
|
48
|
+
version:
|