lib/cliutils/prefs/pref.rb in cliutils-1.3.1 vs lib/cliutils/prefs/pref.rb in cliutils-1.4.0

- old
+ new

@@ -34,17 +34,27 @@ # Stores the valid options the user can pick from. # @return [Array] attr_accessor :options + # Stores the message and behavior that should be + # executed after the prompt is delivered. + # @return [Hash] + attr_accessor :post + + # Stores the message and behavior that should be + # executed before the prompt is delivered. + # @return [Hash] + attr_accessor :pre + # Stores the prereqs information. # @return [Array] attr_accessor :prereqs # Stores the prompt text. # @return [String] - attr_accessor :prompt + attr_accessor :prompt_text # Stores key/value combinations required to show this Pref. # @return [Hash] attr_accessor :validators @@ -59,13 +69,38 @@ # @param [Pref] other # @return [Boolean] def ==(other) @config_key == other.config_key && @config_section == other.config_section && - @prompt == other.prompt + @prompt_text == other.prompt_text end + # Delivers the prompt the user. Handles retries + # after incorrect answers, validation, behavior + # evaluation, and pre-/post-behaviors. + # @param [String] default The default option + # @return [void] + def deliver(default = nil) + # Design decision: the pre-prompt behavior + # gets evaluated *once*, not every time the + # user gets prompted. This prevents multiple + # evaluations when bad options are provided. + _eval_pre + + valid_option_chosen = false + until valid_option_chosen + response = prompt(@prompt_text, default) + if validate(response) + valid_option_chosen = true + @answer = evaluate_behaviors(response) + _eval_post + else + messenger.error(@last_error_message) + end + end + end + # Runs the passed text through this Pref's behaviors. # @param [String] text The text to evaluate # @return [String] def evaluate_behaviors(text) if @behaviors @@ -78,11 +113,11 @@ args = [modified_text, parameter] if PrefBehavior.respond_to?(method) modified_text = PrefBehavior.send(method, *args) else - messenger.warn("Skipping undefined Pref behavior: #{ b }") + messenger.warn("Skipping undefined Pref Behavior: #{ b }") end end modified_text else text @@ -127,13 +162,66 @@ unless validator.code @last_error_message = validator.message ret = false end else - messenger.warn("Skipping undefined Pref validator: #{ v }") + messenger.warn("Skipping undefined Pref Validator: #{ v }") end end end ret + end + + # Evaluates the pre-prompt Hash and does the right thing. :) + # @return [void] + def _eval_pre + info(@pre[:message]) + prompt('Press enter to continue') + + if (@pre[:action]) + action_obj = _load_action(@pre[:action]) + action_obj.run(@pre[:action_parameters][0]) + end + end + + # Evaluates the post-prompt Hash and does the right thing. :) + # @return [void] + def _eval_post + info(@post[:message]) + + if (@post[:action]) + action_obj = _load_action(@post[:action]) + action_obj.run(@post[:action_parameters][0]) + end + end + + # Loads a Pref Action, instantiates it (if it exists), + # and returns that instance. Note that the passed + # String can be a name (thus translating to an included + # Action) or a filepath to a user-defined Action. + # @param [String] path_or_name The name of or path to an Action + # @return [Object] + def _load_action(path_or_name) + if File.exist?(path_or_name) + # If the file exists, we're assuming that the user + # passed a filepath. + action_path = "#{ path_or_name }_action" + action_name = File.basename(path_or_name, '.*').camelize + else + # If it doesn't, we're assuming that the user + # passed a class name. + _default = File.join(File.dirname(__FILE__), 'pref_actions') + action_path = File.join(_default, "#{ path_or_name }_action") + action_name = path_or_name.camelize + end + + # Try to load and instantiate the Action. If that fails, warn + # the user with a message and skip over it. + begin + require action_path + Object.const_get("CLIUtils::#{ action_name }Action").new + rescue + messenger.warn("Skipping undefined Pref Action: #{ path_or_name }") + end end end end