lib/adhearsion/menu_dsl/menu.rb in adhearsion-2.0.0.beta1 vs lib/adhearsion/menu_dsl/menu.rb in adhearsion-2.0.0.rc1

- old
+ new

@@ -1,55 +1,82 @@ +# encoding: utf-8 + module Adhearsion module MenuDSL class Menu DEFAULT_MAX_NUMBER_OF_TRIES = 1 DEFAULT_TIMEOUT = 5 - attr_reader :builder, :timeout, :tries_count, :max_number_of_tries + InvalidStructureError = Class.new StandardError + attr_reader :builder, :timeout, :tries_count, :max_number_of_tries, :terminator, :limit, :interruptible, :status + def initialize(options = {}, &block) @tries_count = 0 # Counts the number of tries the menu's been executed @timeout = options[:timeout] || DEFAULT_TIMEOUT @max_number_of_tries = options[:tries] || DEFAULT_MAX_NUMBER_OF_TRIES + @terminator = options[:terminator].to_s + @limit = options[:limit] + @interruptible = options.has_key?(:interruptible) ? options[:interruptible] : true @builder = MenuDSL::MenuBuilder.new + @terminated = false - @builder.build &block + @builder.build(&block) if block initialize_digit_buffer end + def validate(mode = nil) + case mode + when :basic + @terminator.present? || !!@limit || raise(InvalidStructureError, "You must specify at least one of limit or terminator") + else + @builder.has_matchers? || raise(InvalidStructureError, "You must specify one or more matchers") + end + end + def <<(other) - digit_buffer << other + if other == terminator + @terminated = true + else + digit_buffer << other + end end def digit_buffer @digit_buffer end def digit_buffer_string digit_buffer.to_s end + alias :result :digit_buffer_string def digit_buffer_empty? digit_buffer.empty? end def continue return get_another_digit_or_timeout! if digit_buffer_empty? + return menu_terminated! if @terminated + return menu_limit_reached! if limit && digit_buffer.size >= limit + + return menu_validator_terminated! if execute_validator_hook + calculated_matches = builder.calculate_matches_for digit_buffer_string if calculated_matches.exact_match_count >= 1 first_exact_match = calculated_matches.exact_matches.first if calculated_matches.potential_match_count.zero? menu_result_found! first_exact_match, digit_buffer_string else get_another_digit_or_finish! first_exact_match.match_payload, first_exact_match.query end - elsif calculated_matches.potential_match_count >= 1 + elsif calculated_matches.potential_match_count >= 1 || !@builder.has_matchers? get_another_digit_or_timeout! else invalid! end end @@ -73,31 +100,54 @@ def execute_failure_hook builder.execute_hook_for :failure, digit_buffer_string end + def execute_validator_hook + builder.execute_hook_for :validator, digit_buffer_string + end + protected # If you're using a more complex class in subclasses, you may want to override this method in addition to the # digit buffer, digit_buffer_empty, and digit_buffer_string methods def initialize_digit_buffer @digit_buffer = ClearableStringBuffer.new end def invalid! + @status = :invalid MenuResultInvalid.new end def menu_result_found!(match_object, new_extension) + @status = :matched MenuResultFound.new(match_object, new_extension) end + def menu_terminated! + @status = :terminated + MenuTerminated.new + end + + def menu_validator_terminated! + @status = :validator_terminated + MenuValidatorTerminated.new + end + + def menu_limit_reached! + @status = :limited + MenuLimitReached.new + end + def get_another_digit_or_finish!(match_payload, new_extension) + @status = :multi_matched MenuGetAnotherDigitOrFinish.new(match_payload, new_extension) end def get_another_digit_or_timeout! + @status = :potential MenuGetAnotherDigitOrTimeout.new end # The superclass from which all message-like exceptions descend. It should never # be instantiated directly. @@ -125,9 +175,13 @@ class MenuGetAnotherDigitOrTimeout < MenuResult include MenuGetAnotherDigit end MenuResultInvalid = Class.new MenuResult + + MenuTerminated = Class.new MenuResultDone + MenuValidatorTerminated = Class.new MenuResultDone + MenuLimitReached = Class.new MenuResultDone # For our default purpose, we need the digit_buffer to behave much like a normal String except that it should # handle its own resetting (clearing) class ClearableStringBuffer < String def clear!