cliutils 1.4.2 → 2.0.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.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/HISTORY.md +9 -0
- data/README.md +15 -639
- data/lib/cliutils/constants.rb +1 -1
- data/lib/cliutils/messaging.rb +112 -0
- data/lib/cliutils/prefs/pref.rb +113 -66
- data/lib/cliutils/prefs/pref_actions/open_url_action.rb +6 -2
- data/lib/cliutils/prefs/pref_actions/pref_action.rb +18 -9
- data/lib/cliutils/prefs/pref_behaviors/capitalize_behavior.rb +11 -0
- data/lib/cliutils/prefs/pref_behaviors/expand_filepath_behavior.rb +12 -0
- data/lib/cliutils/prefs/pref_behaviors/lowercase_behavior.rb +11 -0
- data/lib/cliutils/prefs/pref_behaviors/pref_behavior.rb +26 -0
- data/lib/cliutils/prefs/pref_behaviors/prefix_behavior.rb +11 -0
- data/lib/cliutils/prefs/pref_behaviors/suffix_behavior.rb +11 -0
- data/lib/cliutils/prefs/pref_behaviors/titlecase_behavior.rb +11 -0
- data/lib/cliutils/prefs/pref_behaviors/uppercase_behavior.rb +11 -0
- data/lib/cliutils/prefs/pref_validators/alphabetic_validator.rb +13 -0
- data/lib/cliutils/prefs/pref_validators/alphanumeric_validator.rb +14 -0
- data/lib/cliutils/prefs/pref_validators/date_validator.rb +13 -0
- data/lib/cliutils/prefs/pref_validators/datetime_validator.rb +13 -0
- data/lib/cliutils/prefs/pref_validators/filepath_exists_validator.rb +13 -0
- data/lib/cliutils/prefs/pref_validators/non_nil_validator.rb +13 -0
- data/lib/cliutils/prefs/pref_validators/number_validator.rb +13 -0
- data/lib/cliutils/prefs/pref_validators/pref_validator.rb +31 -0
- data/lib/cliutils/prefs/pref_validators/time_validator.rb +13 -0
- data/lib/cliutils/prefs/pref_validators/url_validator.rb +15 -0
- data/lib/cliutils/pretty_io.rb +0 -112
- data/lib/cliutils.rb +1 -0
- data/test/configurator_test.rb +1 -1
- data/test/hash_extensions_test.rb +1 -1
- data/test/logger_extensions_test.rb +1 -1
- data/test/messenging_test.rb +1 -1
- data/test/prefs_test.rb +1 -1
- data/test/string_extesions_test.rb +1 -1
- data/test/test_files/prefstest.yaml +29 -9
- data/test/test_helper.rb +6 -0
- metadata +22 -4
- data/lib/cliutils/prefs/pref_behavior.rb +0 -58
- data/lib/cliutils/prefs/pref_validation.rb +0 -96
data/lib/cliutils/messaging.rb
CHANGED
@@ -13,6 +13,11 @@ module CLIUtils
|
|
13
13
|
k.extend(self)
|
14
14
|
end
|
15
15
|
|
16
|
+
# Empty method so that Messaging doesn't freak
|
17
|
+
# out when passed a debug message.
|
18
|
+
# @return [void]
|
19
|
+
def debug(m); end
|
20
|
+
|
16
21
|
# Returns a default instance of LoggerDelegator that
|
17
22
|
# delegates to STDOUT only.
|
18
23
|
# @return [LoggerDelegator]
|
@@ -25,11 +30,118 @@ module CLIUtils
|
|
25
30
|
LoggerDelegator.new(STDOUT: stdout_logger)
|
26
31
|
end
|
27
32
|
|
33
|
+
# Outputs a formatted-red error message.
|
34
|
+
# @param [String] m The message to output
|
35
|
+
# @return [void]
|
36
|
+
def error(m)
|
37
|
+
puts _word_wrap(m, '# ').red
|
38
|
+
end
|
39
|
+
|
40
|
+
# Outputs a formatted-blue informational message.
|
41
|
+
# @param [String] m The message to output
|
42
|
+
# @return [void]
|
43
|
+
def info(m)
|
44
|
+
puts _word_wrap(m, '# ').blue
|
45
|
+
end
|
46
|
+
|
47
|
+
# Wraps a block in an opening and closing info message.
|
48
|
+
# @param [String] m1 The opening message to output
|
49
|
+
# @param [String] m2 The closing message to output
|
50
|
+
# @param [<True, False>] multiline Whether the message should be multiline
|
51
|
+
# @yield
|
52
|
+
# @return [void]
|
53
|
+
def info_block(m1, m2 = 'Done.', multiline = false)
|
54
|
+
if block_given?
|
55
|
+
if multiline
|
56
|
+
info(m1)
|
57
|
+
else
|
58
|
+
print _word_wrap(m1, '# ').blue
|
59
|
+
end
|
60
|
+
|
61
|
+
yield
|
62
|
+
|
63
|
+
if multiline
|
64
|
+
info(m2)
|
65
|
+
else
|
66
|
+
puts _word_wrap(m2, '# ').blue
|
67
|
+
end
|
68
|
+
else
|
69
|
+
fail 'Did not specify a valid block'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Empty method so that Messaging doesn't freak
|
74
|
+
# out when passed a log message.
|
75
|
+
# @return [void]
|
76
|
+
def log(m); end
|
77
|
+
|
28
78
|
# Singleton method to return (or initialize, if needed)
|
29
79
|
# a LoggerDelegator.
|
30
80
|
# @return [LoggerDelegator]
|
31
81
|
def messenger
|
32
82
|
@@messenger ||= default_instance
|
33
83
|
end
|
84
|
+
|
85
|
+
# Outputs a prompt, collects the user's response, and
|
86
|
+
# returns it.
|
87
|
+
# @param [String] prompt The prompt to output
|
88
|
+
# @param [String] default The default option
|
89
|
+
# @param [String] start_dir The directory to start from for autocompletion
|
90
|
+
# @return [String]
|
91
|
+
def prompt(prompt, default = nil, start_dir = '')
|
92
|
+
Readline.completion_append_character = nil
|
93
|
+
Readline.completion_proc = lambda do |prefix|
|
94
|
+
files = Dir["#{start_dir}#{prefix}*"]
|
95
|
+
files.map { |f| File.expand_path(f) }
|
96
|
+
.map { |f| File.directory?(f) ? "#{ f }/" : f }
|
97
|
+
end
|
98
|
+
p = "# #{ prompt }#{ default.nil? ? ':' : " [default: #{ default }]:" } "
|
99
|
+
choice = Readline.readline(p.cyan)
|
100
|
+
if choice.empty?
|
101
|
+
default
|
102
|
+
else
|
103
|
+
choice
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Outputs a formatted-purple section message.
|
108
|
+
# @param [String] m The message to output
|
109
|
+
# @return [void]
|
110
|
+
def section(m)
|
111
|
+
puts _word_wrap(m, '---> ').purple
|
112
|
+
end
|
113
|
+
|
114
|
+
# Wraps a block in an opening and closing section message.
|
115
|
+
# @param [String] m The opening message to output
|
116
|
+
# @param [<True, False>] multiline Whether the message should be multiline
|
117
|
+
# @yield
|
118
|
+
# @return [void]
|
119
|
+
def section_block(m, multiline = true)
|
120
|
+
if block_given?
|
121
|
+
if multiline
|
122
|
+
section(m)
|
123
|
+
else
|
124
|
+
print _word_wrap(m, '---> ').purple
|
125
|
+
end
|
126
|
+
|
127
|
+
yield
|
128
|
+
else
|
129
|
+
fail 'Did not specify a valid block'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Outputs a formatted-green success message.
|
134
|
+
# @param [String] m The message to output
|
135
|
+
# @return [void]
|
136
|
+
def success(m)
|
137
|
+
puts _word_wrap(m, '# ').green
|
138
|
+
end
|
139
|
+
|
140
|
+
# Outputs a formatted-yellow warning message.
|
141
|
+
# @param [String] m The message to output
|
142
|
+
# @return [void]
|
143
|
+
def warn(m)
|
144
|
+
puts _word_wrap(m, '# ').yellow
|
145
|
+
end
|
34
146
|
end
|
35
147
|
end
|
data/lib/cliutils/prefs/pref.rb
CHANGED
@@ -1,17 +1,35 @@
|
|
1
|
-
require 'cliutils/messaging'
|
2
|
-
require 'cliutils/prefs/pref_behavior'
|
3
|
-
require 'cliutils/prefs/pref_validation'
|
4
|
-
|
5
1
|
module CLIUtils
|
6
2
|
# Pref Class
|
7
3
|
# An individual preference
|
8
4
|
class Pref
|
9
5
|
include Messaging
|
10
6
|
|
7
|
+
# Constant defining an Action
|
8
|
+
ASSET_TYPE_ACTION = 0
|
9
|
+
|
10
|
+
# Constant defining a Behavior
|
11
|
+
ASSET_TYPE_BEHAVIOR = 1
|
12
|
+
|
13
|
+
# Constant defining a Validator
|
14
|
+
ASSET_TYPE_VALIDATOR = 2
|
15
|
+
|
16
|
+
# Contains a listing of asset names for classes and
|
17
|
+
# file suffixes.
|
18
|
+
# @return [Array]
|
19
|
+
@@asset_labels = [
|
20
|
+
{ class_suffix: 'Action', file_suffix: 'action' },
|
21
|
+
{ class_suffix: 'Behavior', file_suffix: 'behavior' },
|
22
|
+
{ class_suffix: 'Validator', file_suffix: 'validator' }
|
23
|
+
]
|
24
|
+
|
11
25
|
# Stores the answer to this Pref.
|
12
26
|
# @return [String, Symbol]
|
13
27
|
attr_accessor :answer
|
14
28
|
|
29
|
+
# Stores instantiated Behavior objects.
|
30
|
+
# @return [Array]
|
31
|
+
attr_accessor :behavior_objects
|
32
|
+
|
15
33
|
# Stores the behaviors that this Pref conforms to.
|
16
34
|
# @return [Array]
|
17
35
|
attr_accessor :behaviors
|
@@ -54,17 +72,29 @@ module CLIUtils
|
|
54
72
|
# @return [String]
|
55
73
|
attr_accessor :prompt_text
|
56
74
|
|
75
|
+
# Stores instantiated Validators
|
76
|
+
# @return [Array]
|
77
|
+
attr_accessor :validator_objects
|
78
|
+
|
57
79
|
# Stores key/value combinations required to show this Pref.
|
58
80
|
# @return [Hash]
|
59
81
|
attr_accessor :validators
|
60
82
|
|
61
|
-
# Initializes a new Pref via passed-in parameters.
|
83
|
+
# Initializes a new Pref via passed-in parameters. Also
|
84
|
+
# initializes objects for each Validator and Behavior on
|
85
|
+
# this Pref.
|
62
86
|
# @param [Hash] params Parameters to initialize
|
63
87
|
# @return [void]
|
64
88
|
def initialize(params = {})
|
89
|
+
@behavior_objects = []
|
90
|
+
@validator_objects = []
|
91
|
+
|
92
|
+
# Assign all of the passed params as instance variables.
|
65
93
|
params.each { |key, value| send("#{ key }=", value) }
|
66
|
-
|
67
|
-
#
|
94
|
+
|
95
|
+
# Instantiate any listed Behaviors or Validators.
|
96
|
+
@behaviors.each { |b| _init_and_add_behavior(b) } if @behaviors
|
97
|
+
@validators.each { |v| _init_and_add_validator(v) } if @validators
|
68
98
|
end
|
69
99
|
|
70
100
|
# Custom equality operator for this class.
|
@@ -105,25 +135,13 @@ module CLIUtils
|
|
105
135
|
# @param [String] text The text to evaluate
|
106
136
|
# @return [String]
|
107
137
|
def evaluate_behaviors(text)
|
108
|
-
|
109
|
-
|
110
|
-
@
|
111
|
-
|
112
|
-
parameter = method.values[0]
|
113
|
-
method = method.keys[0]
|
114
|
-
end
|
115
|
-
|
116
|
-
args = [modified_text, parameter]
|
117
|
-
if PrefBehavior.respond_to?(method)
|
118
|
-
modified_text = PrefBehavior.send(method, *args)
|
119
|
-
else
|
120
|
-
messenger.warn("Skipping undefined Pref Behavior: #{ b }")
|
121
|
-
end
|
138
|
+
modified_text = text
|
139
|
+
if @behavior_objects
|
140
|
+
@behavior_objects.each do |b|
|
141
|
+
modified_text = b.evaluate(modified_text)
|
122
142
|
end
|
123
|
-
modified_text
|
124
|
-
else
|
125
|
-
text
|
126
143
|
end
|
144
|
+
modified_text
|
127
145
|
end
|
128
146
|
|
129
147
|
# Validates a text against this pref's options and
|
@@ -131,8 +149,8 @@ module CLIUtils
|
|
131
149
|
# @param [String] text The text to validate
|
132
150
|
# @return [Boolean]
|
133
151
|
def validate(text)
|
134
|
-
|
135
|
-
|
152
|
+
_check_options(text) &&
|
153
|
+
_check_validators(text)
|
136
154
|
end
|
137
155
|
|
138
156
|
private
|
@@ -140,7 +158,7 @@ module CLIUtils
|
|
140
158
|
# Validates a text against the options for this Pref
|
141
159
|
# @param [String] text The text to validate
|
142
160
|
# @return [Boolean]
|
143
|
-
def
|
161
|
+
def _check_options(text)
|
144
162
|
ret = true
|
145
163
|
if @options
|
146
164
|
unless @options.include?(text)
|
@@ -155,18 +173,14 @@ module CLIUtils
|
|
155
173
|
# Validates a text against the validators for this Pref
|
156
174
|
# @param [String] text The text to validate
|
157
175
|
# @return [Boolean]
|
158
|
-
def
|
176
|
+
def _check_validators(text)
|
159
177
|
ret = true
|
160
|
-
if @
|
161
|
-
@
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
ret = false
|
167
|
-
end
|
168
|
-
else
|
169
|
-
messenger.warn("Skipping undefined Pref Validator: #{ v }")
|
178
|
+
if @validator_objects
|
179
|
+
@validator_objects.each do |v|
|
180
|
+
v.validate(text)
|
181
|
+
unless v.is_valid
|
182
|
+
@last_error_message = v.message
|
183
|
+
ret = false
|
170
184
|
end
|
171
185
|
end
|
172
186
|
end
|
@@ -178,11 +192,10 @@ module CLIUtils
|
|
178
192
|
def _eval_pre
|
179
193
|
info(@pre[:message])
|
180
194
|
prompt('Press enter to continue')
|
181
|
-
|
195
|
+
|
182
196
|
if (@pre[:action])
|
183
|
-
action_obj =
|
184
|
-
action_obj.
|
185
|
-
action_obj.run(@pre[:action_parameters][0])
|
197
|
+
action_obj = _init_action(@pre[:action][:name])
|
198
|
+
action_obj.run
|
186
199
|
end
|
187
200
|
end
|
188
201
|
|
@@ -192,45 +205,79 @@ module CLIUtils
|
|
192
205
|
info(@post[:message])
|
193
206
|
|
194
207
|
if (@post[:action])
|
195
|
-
action_obj =
|
196
|
-
action_obj.
|
197
|
-
|
208
|
+
action_obj = _init_action(@post[:action][:name])
|
209
|
+
action_obj.run
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Attempts to instantiate a Pre or Post Action based on name; if
|
214
|
+
# successful, the new object gets placed in @validator_objects
|
215
|
+
# @param [String] path_or_name The path to or name of the Action
|
216
|
+
# @return [void]
|
217
|
+
def _init_action(path_or_name)
|
218
|
+
obj = _load_asset(ASSET_TYPE_ACTION, path_or_name)
|
219
|
+
unless obj.nil?
|
220
|
+
obj.pref = self
|
221
|
+
obj.parameters = @pre[:action][:parameters]
|
198
222
|
end
|
223
|
+
obj
|
199
224
|
end
|
200
225
|
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
#
|
205
|
-
|
206
|
-
|
207
|
-
|
226
|
+
# Attempts to instantiate a Behavior based on name; if
|
227
|
+
# successful, the new object gets placed in @behavior_objects
|
228
|
+
# @param [Hash] behavior_hash The Behavior attributes
|
229
|
+
# @return [void]
|
230
|
+
def _init_and_add_behavior(behavior_hash)
|
231
|
+
obj = _load_asset(ASSET_TYPE_BEHAVIOR, behavior_hash[:name])
|
232
|
+
unless obj.nil?
|
233
|
+
obj.pref = self
|
234
|
+
obj.parameters = behavior_hash[:parameters]
|
235
|
+
@behavior_objects << obj
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Attempts to instantiate a Validator based on name; if
|
240
|
+
# successful, the new object gets placed in @validator_objects
|
241
|
+
# @param [String] path_or_name The path to or name of the Validator
|
242
|
+
# @return [void]
|
243
|
+
def _init_and_add_validator(path_or_name)
|
244
|
+
obj = _load_asset(ASSET_TYPE_VALIDATOR, path_or_name)
|
245
|
+
unless obj.nil?
|
246
|
+
obj.pref = self
|
247
|
+
@validator_objects << obj
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# General function to load an asset (a Validator or Behavior).
|
252
|
+
# Note that if an asset isn't found, the user is warned, but
|
253
|
+
# execution continues.
|
254
|
+
# @param [Integer] type ASSET_TYPE_BEHAVIOR or ASSET_TYPE_VALIDATOR
|
255
|
+
# @param [String] path_or_name The path to or name of the asset
|
256
|
+
# @return [Object]
|
257
|
+
def _load_asset(type, path_or_name)
|
208
258
|
if File.exist?(path_or_name)
|
209
259
|
# If the file exists, we're assuming that the user
|
210
260
|
# passed a filepath.
|
211
|
-
|
212
|
-
|
213
|
-
|
261
|
+
asset_path = File.expand_path(path_or_name) if path_or_name.start_with?('~')
|
262
|
+
asset_path = "#{ path_or_name }_#{ @@asset_labels[type][:file_suffix] }"
|
263
|
+
asset_name = File.basename(path_or_name, '.*').camelize
|
214
264
|
else
|
215
265
|
# If it doesn't, we're assuming that the user
|
216
266
|
# passed a class name.
|
217
|
-
_default = File.join(File.dirname(__FILE__),
|
218
|
-
|
219
|
-
|
267
|
+
_default = File.join(File.dirname(__FILE__), "pref_#{ @@asset_labels[type][:file_suffix] }s")
|
268
|
+
asset_path = File.join(_default, "#{ path_or_name }_#{ @@asset_labels[type][:file_suffix] }")
|
269
|
+
asset_name = path_or_name.camelize
|
220
270
|
end
|
221
271
|
|
222
272
|
# Try to load and instantiate the Action. If that fails, warn
|
223
273
|
# the user with a message and skip over it.
|
224
274
|
begin
|
225
|
-
require
|
226
|
-
Object.const_get("CLIUtils::#{
|
227
|
-
rescue
|
228
|
-
messenger.warn("Skipping undefined Pref
|
275
|
+
require asset_path
|
276
|
+
Object.const_get("CLIUtils::#{ asset_name }#{ @@asset_labels[type][:class_suffix] }").new
|
277
|
+
rescue LoadError
|
278
|
+
messenger.warn("Skipping undefined Pref #{ @@asset_labels[type][:class_suffix] }: #{ path_or_name }")
|
279
|
+
nil
|
229
280
|
end
|
230
281
|
end
|
231
|
-
|
232
|
-
def _load_validators
|
233
|
-
|
234
|
-
end
|
235
282
|
end
|
236
283
|
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
module CLIUtils
|
2
|
+
# Pref Action to open a URL in the default
|
3
|
+
# browser.
|
2
4
|
class OpenUrlAction < PrefAction
|
3
|
-
|
4
|
-
|
5
|
+
# Runs the action.
|
6
|
+
# @return [void]
|
7
|
+
def run
|
8
|
+
`open #{ @parameters[:url] }`
|
5
9
|
end
|
6
10
|
end
|
7
11
|
end
|
@@ -1,23 +1,32 @@
|
|
1
1
|
module CLIUtils
|
2
2
|
# The generic base class for a Pref
|
3
|
-
#
|
3
|
+
# Action.
|
4
4
|
class PrefAction
|
5
5
|
include Messaging
|
6
6
|
|
7
|
+
# Holds the parameters that apply to
|
8
|
+
# this Action.
|
9
|
+
# @!attribute parameters
|
10
|
+
# @return [Hash]
|
11
|
+
attr_accessor :parameters
|
12
|
+
|
7
13
|
# Holds a reference to the pref that
|
8
|
-
# is implementing this
|
14
|
+
# is implementing this Action.
|
15
|
+
# @!attribute pref
|
9
16
|
# @return [Pref]
|
10
17
|
attr_accessor :pref
|
11
18
|
|
12
|
-
# Runs the
|
13
|
-
# method implemented here
|
14
|
-
# an
|
15
|
-
#
|
16
|
-
#
|
19
|
+
# Runs the Action. Note that the
|
20
|
+
# method implemented here will throw
|
21
|
+
# an exception by default, meaning that
|
22
|
+
# the user's subclass *needs* to
|
23
|
+
# implement it.
|
17
24
|
# @parameter [Hash] parameters
|
25
|
+
# @raise [StandardError] if the subclass
|
26
|
+
# doesn't implement this method.
|
18
27
|
# @return [void]
|
19
|
-
def run
|
20
|
-
|
28
|
+
def run
|
29
|
+
fail "`run` method not implemented on caller: #{ self.class }"
|
21
30
|
end
|
22
31
|
end
|
23
32
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Behavior to capitalize a Pref answer
|
3
|
+
class CapitalizeBehavior < PrefBehavior
|
4
|
+
# Evaluates the behavior against the text.
|
5
|
+
# @param [Object] text The "text" to evaluate
|
6
|
+
# @return [String]
|
7
|
+
def evaluate(text)
|
8
|
+
text.to_s.capitalize
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Behavior to run File.expand_path on a
|
3
|
+
# Pref answer
|
4
|
+
class ExpandFilepathBehavior < PrefBehavior
|
5
|
+
# Evaluates the behavior against the text.
|
6
|
+
# @param [Object] text The "text" to evaluate
|
7
|
+
# @return [String]
|
8
|
+
def evaluate(text)
|
9
|
+
File.expand_path(text.to_s)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Behavior to lowecase a Pref answer
|
3
|
+
class LowercaseBehavior < PrefBehavior
|
4
|
+
# Evaluates the behavior against the text.
|
5
|
+
# @param [Object] text The "text" to evaluate
|
6
|
+
# @return [String]
|
7
|
+
def evaluate(text)
|
8
|
+
text.to_s.downcase
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# The generic base class for a Pref
|
3
|
+
# Behavior.
|
4
|
+
class PrefBehavior
|
5
|
+
include Messaging
|
6
|
+
|
7
|
+
# Holds the parameters associated with
|
8
|
+
# this behavior.
|
9
|
+
# @return [Hash]
|
10
|
+
attr_accessor :parameters
|
11
|
+
|
12
|
+
# Holds a reference to the Pref that
|
13
|
+
# is applying this Behavior.
|
14
|
+
# @return [Pref]
|
15
|
+
attr_accessor :pref
|
16
|
+
|
17
|
+
# Evaluate the Behavior!
|
18
|
+
# @parameter [Hash] parameters
|
19
|
+
# @raise [StandardError] if the subclass
|
20
|
+
# doesn't implement this method.
|
21
|
+
# @return [void]
|
22
|
+
def evaluate(text = '')
|
23
|
+
fail "`evaluate` method not implemented on caller: #{ self.class }"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Behavior to prefix a Pref answer with a string
|
3
|
+
class PrefixBehavior < PrefBehavior
|
4
|
+
# Evaluates the behavior against the text.
|
5
|
+
# @param [Object] text The "text" to evaluate
|
6
|
+
# @return [String]
|
7
|
+
def evaluate(text)
|
8
|
+
@parameters[:prefix] + text.to_s
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Behavior to suffix a Pref answer with a string
|
3
|
+
class SuffixBehavior < PrefBehavior
|
4
|
+
# Evaluates the behavior against the text.
|
5
|
+
# @param [Object] text The "text" to evaluate
|
6
|
+
# @return [String]
|
7
|
+
def evaluate(text)
|
8
|
+
text.to_s + @parameters[:suffix]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Behavior to titlecase a Pref answer
|
3
|
+
class TitlecaseBehavior < PrefBehavior
|
4
|
+
# Evaluates the behavior against the text.
|
5
|
+
# @param [Object] text The "text" to evaluate
|
6
|
+
# @return [String]
|
7
|
+
def evaluate(text)
|
8
|
+
text.to_s.split.map(&:capitalize).join(' ')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Behavior to uppercase a Pref answer
|
3
|
+
class UppercaseBehavior < PrefBehavior
|
4
|
+
# Evaluates the behavior against the text.
|
5
|
+
# @param [Object] text The "text" to evaluate
|
6
|
+
# @return [String]
|
7
|
+
def evaluate(text)
|
8
|
+
text.to_s.upcase
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Validator to verify whether a Pref answer
|
3
|
+
# is alphabetic (made up of letters and spaces).
|
4
|
+
class AlphabeticValidator < PrefValidator
|
5
|
+
# Runs the Validator against the answer.
|
6
|
+
# @param [Object] text The "text" to evaluate
|
7
|
+
# @return [String]
|
8
|
+
def validate(text)
|
9
|
+
@is_valid = text.to_s =~ /\A[A-Za-z\s]+\z/
|
10
|
+
@message = "Response is not alphabetic: #{ text }"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Validator to verify whether a Pref answer
|
3
|
+
# is alphanumeric (made up of letters, numbers
|
4
|
+
# and spaces).
|
5
|
+
class AlphanumericValidator < PrefValidator
|
6
|
+
# Runs the Validator against the answer.
|
7
|
+
# @param [Object] text The "text" to evaluate
|
8
|
+
# @return [String]
|
9
|
+
def validate(text)
|
10
|
+
@is_valid = text.to_s =~ /\A[A-Za-z0-9\s]+\z/
|
11
|
+
@message = "Response is not alphanumeric: #{ text }"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Validator to verify whether a Pref answer
|
3
|
+
# is a date.
|
4
|
+
class DateValidator < PrefValidator
|
5
|
+
# Runs the Validator against the answer.
|
6
|
+
# @param [Object] text The "text" to evaluate
|
7
|
+
# @return [String]
|
8
|
+
def validate(text)
|
9
|
+
@is_valid = !(Date.parse(text) rescue nil).nil?
|
10
|
+
@message = "Response is not a date: #{ text }"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Validator to verify whether a Pref answer
|
3
|
+
# is a datetime.
|
4
|
+
class DatetimeValidator < PrefValidator
|
5
|
+
# Runs the Validator against the answer.
|
6
|
+
# @param [Object] text The "text" to evaluate
|
7
|
+
# @return [String]
|
8
|
+
def validate(text)
|
9
|
+
@is_valid = !(DateTime.parse(text) rescue nil).nil?
|
10
|
+
@message = "Response is not a datetime: #{ text }"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Validator to verify whether a Pref answer
|
3
|
+
# is a local filepath that exists.
|
4
|
+
class FilepathExistsValidator < PrefValidator
|
5
|
+
# Runs the Validator against the answer.
|
6
|
+
# @param [Object] text The "text" to evaluate
|
7
|
+
# @return [String]
|
8
|
+
def validate(text)
|
9
|
+
@is_valid = Pathname.new(text.to_s).exist?
|
10
|
+
@message = "Path does not exist locally: #{ text }"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Validator to verify whether a Pref answer
|
3
|
+
# is not empty or nil.
|
4
|
+
class NonNilValidator < PrefValidator
|
5
|
+
# Runs the Validator against the answer.
|
6
|
+
# @param [Object] text The "text" to evaluate
|
7
|
+
# @return [String]
|
8
|
+
def validate(text)
|
9
|
+
@is_valid = !text.nil? && !text.empty?
|
10
|
+
@message = 'Nil text not allowed'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CLIUtils
|
2
|
+
# A Validator to verify whether a Pref answer
|
3
|
+
# is not a number.
|
4
|
+
class NumberValidator < PrefValidator
|
5
|
+
# Runs the Validator against the answer.
|
6
|
+
# @param [Object] text The "text" to evaluate
|
7
|
+
# @return [String]
|
8
|
+
def validate(text)
|
9
|
+
@is_valid = text.to_s =~ /\A[-+]?\d*\.?\d+\z/
|
10
|
+
@message = "Response is not a number: #{ text }"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|