easyprompt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/easyprompt.rb +178 -0
  2. 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: