adhearsion 2.0.0.rc4 → 2.0.0.rc5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/adhearsion.gemspec +1 -1
- data/bin/ahn +0 -3
- data/lib/adhearsion.rb +7 -4
- data/lib/adhearsion/call.rb +1 -1
- data/lib/adhearsion/call_controller.rb +1 -0
- data/lib/adhearsion/call_controller/menu_dsl.rb +19 -0
- data/lib/adhearsion/call_controller/menu_dsl/calculated_match.rb +43 -0
- data/lib/adhearsion/call_controller/menu_dsl/calculated_match_collection.rb +45 -0
- data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +22 -0
- data/lib/adhearsion/call_controller/menu_dsl/match_calculator.rb +40 -0
- data/lib/adhearsion/call_controller/menu_dsl/menu.rb +203 -0
- data/lib/adhearsion/call_controller/menu_dsl/menu_builder.rb +84 -0
- data/lib/adhearsion/call_controller/menu_dsl/range_match_calculator.rb +60 -0
- data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +25 -0
- data/lib/adhearsion/cli.rb +0 -1
- data/lib/adhearsion/router/route.rb +2 -2
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/input_spec.rb +1 -1
- data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +60 -0
- data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +61 -0
- data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +37 -0
- data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +17 -0
- data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +151 -0
- data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +373 -0
- data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +32 -0
- data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +40 -0
- metadata +91 -91
- data/lib/adhearsion/menu_dsl.rb +0 -17
- data/lib/adhearsion/menu_dsl/calculated_match.rb +0 -41
- data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +0 -43
- data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +0 -20
- data/lib/adhearsion/menu_dsl/match_calculator.rb +0 -38
- data/lib/adhearsion/menu_dsl/menu.rb +0 -201
- data/lib/adhearsion/menu_dsl/menu_builder.rb +0 -82
- data/lib/adhearsion/menu_dsl/range_match_calculator.rb +0 -58
- data/lib/adhearsion/menu_dsl/string_match_calculator.rb +0 -23
- data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +0 -58
- data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +0 -59
- data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +0 -35
- data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +0 -15
- data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +0 -149
- data/spec/adhearsion/menu_dsl/menu_spec.rb +0 -371
- data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +0 -30
- data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +0 -38
data/lib/adhearsion/menu_dsl.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Adhearsion
|
4
|
-
module MenuDSL
|
5
|
-
extend ActiveSupport::Autoload
|
6
|
-
|
7
|
-
autoload :Exceptions
|
8
|
-
autoload :CalculatedMatch
|
9
|
-
autoload :CalculatedMatchCollection
|
10
|
-
autoload :MatchCalculator
|
11
|
-
autoload :FixnumMatchCalculator
|
12
|
-
autoload :RangeMatchCalculator
|
13
|
-
autoload :StringMatchCalculator
|
14
|
-
autoload :MenuBuilder
|
15
|
-
autoload :Menu
|
16
|
-
end
|
17
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Adhearsion
|
4
|
-
module MenuDSL
|
5
|
-
class CalculatedMatch
|
6
|
-
|
7
|
-
def self.failed_match!(pattern, query, match_payload)
|
8
|
-
new :pattern => pattern, :query => query, :match_payload => match_payload
|
9
|
-
end
|
10
|
-
|
11
|
-
attr_reader :match_payload, :potential_matches, :exact_matches, :pattern, :query, :block
|
12
|
-
|
13
|
-
def initialize(options = {})
|
14
|
-
@pattern, @query, @match_payload, @block = options.values_at :pattern, :query, :match_payload, :block
|
15
|
-
@potential_matches = options[:potential_matches] ? Array(options[:potential_matches]) : []
|
16
|
-
@exact_matches = options[:exact_matches] ? Array(options[:exact_matches]) : []
|
17
|
-
end
|
18
|
-
|
19
|
-
def exact_match?
|
20
|
-
exact_matches.any?
|
21
|
-
end
|
22
|
-
|
23
|
-
def potential_match?
|
24
|
-
potential_matches.any?
|
25
|
-
end
|
26
|
-
|
27
|
-
def failed_match?
|
28
|
-
!(potential_match? || exact_match?)
|
29
|
-
end
|
30
|
-
|
31
|
-
def type_of_match
|
32
|
-
if exact_match?
|
33
|
-
:exact
|
34
|
-
elsif potential_match?
|
35
|
-
:potential
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Adhearsion
|
4
|
-
module MenuDSL
|
5
|
-
class CalculatedMatchCollection
|
6
|
-
attr_reader :calculated_matches, :potential_matches, :exact_matches,
|
7
|
-
:actual_potential_matches, :actual_exact_matches
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@calculated_matches = []
|
11
|
-
@potential_matches = []
|
12
|
-
@exact_matches = []
|
13
|
-
@actual_potential_matches = []
|
14
|
-
@actual_exact_matches = []
|
15
|
-
end
|
16
|
-
|
17
|
-
def <<(calculated_match)
|
18
|
-
calculated_matches << calculated_match
|
19
|
-
actual_potential_matches.concat calculated_match.potential_matches
|
20
|
-
actual_exact_matches.concat calculated_match.exact_matches
|
21
|
-
|
22
|
-
potential_matches << calculated_match if calculated_match.potential_match?
|
23
|
-
exact_matches << calculated_match if calculated_match.exact_match?
|
24
|
-
end
|
25
|
-
|
26
|
-
def potential_match_count
|
27
|
-
actual_potential_matches.size
|
28
|
-
end
|
29
|
-
|
30
|
-
def exact_match_count
|
31
|
-
actual_exact_matches.size
|
32
|
-
end
|
33
|
-
|
34
|
-
def potential_match?
|
35
|
-
potential_match_count > 0
|
36
|
-
end
|
37
|
-
|
38
|
-
def exact_match?
|
39
|
-
exact_match_count > 0
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Adhearsion
|
4
|
-
module MenuDSL
|
5
|
-
class FixnumMatchCalculator < MatchCalculator
|
6
|
-
|
7
|
-
def match(query)
|
8
|
-
numeric_query = coerce_to_numeric query
|
9
|
-
exact_match, potential_match = nil
|
10
|
-
if pattern == numeric_query
|
11
|
-
exact_match = pattern
|
12
|
-
elsif pattern.to_s.starts_with? query.to_s
|
13
|
-
potential_match = pattern
|
14
|
-
end
|
15
|
-
new_calculated_match :query => query, :exact_matches => exact_match, :potential_matches => potential_match
|
16
|
-
end
|
17
|
-
|
18
|
-
end # class FixnumMatchCalculator
|
19
|
-
end
|
20
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Adhearsion
|
4
|
-
module MenuDSL
|
5
|
-
class MatchCalculator
|
6
|
-
|
7
|
-
class << self
|
8
|
-
|
9
|
-
def build_with_pattern(pattern, match_payload, &block)
|
10
|
-
class_for_pattern(pattern).new pattern, match_payload, &block
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def class_for_pattern(pattern)
|
16
|
-
MenuDSL.const_get "#{pattern.class.name.camelize}MatchCalculator"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
attr_reader :pattern, :match_payload, :block
|
21
|
-
|
22
|
-
def initialize(pattern, match_payload, &block)
|
23
|
-
@pattern, @match_payload, @block = pattern, match_payload, block
|
24
|
-
end
|
25
|
-
|
26
|
-
protected
|
27
|
-
|
28
|
-
def new_calculated_match(options)
|
29
|
-
CalculatedMatch.new({:pattern => pattern, :match_payload => match_payload, :block => block}.merge(options))
|
30
|
-
end
|
31
|
-
|
32
|
-
def coerce_to_numeric(victim)
|
33
|
-
victim.kind_of?(Numeric) ? victim : (victim.to_s =~ /^\d+$/ ? victim.to_s.to_i : nil )
|
34
|
-
end
|
35
|
-
|
36
|
-
end # class MatchCalculator
|
37
|
-
end
|
38
|
-
end
|
@@ -1,201 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Adhearsion
|
4
|
-
module MenuDSL
|
5
|
-
|
6
|
-
class Menu
|
7
|
-
|
8
|
-
DEFAULT_MAX_NUMBER_OF_TRIES = 1
|
9
|
-
DEFAULT_TIMEOUT = 5
|
10
|
-
|
11
|
-
InvalidStructureError = Class.new Adhearsion::Error
|
12
|
-
|
13
|
-
attr_reader :builder, :timeout, :tries_count, :max_number_of_tries, :terminator, :limit, :interruptible, :status
|
14
|
-
|
15
|
-
def initialize(options = {}, &block)
|
16
|
-
@tries_count = 0 # Counts the number of tries the menu's been executed
|
17
|
-
@timeout = options[:timeout] || DEFAULT_TIMEOUT
|
18
|
-
@max_number_of_tries = options[:tries] || DEFAULT_MAX_NUMBER_OF_TRIES
|
19
|
-
@terminator = options[:terminator].to_s
|
20
|
-
@limit = options[:limit]
|
21
|
-
@interruptible = options.has_key?(:interruptible) ? options[:interruptible] : true
|
22
|
-
@builder = MenuDSL::MenuBuilder.new
|
23
|
-
@terminated = false
|
24
|
-
|
25
|
-
@builder.build(&block) if block
|
26
|
-
|
27
|
-
initialize_digit_buffer
|
28
|
-
end
|
29
|
-
|
30
|
-
def validate(mode = nil)
|
31
|
-
case mode
|
32
|
-
when :basic
|
33
|
-
@terminator.present? || !!@limit || raise(InvalidStructureError, "You must specify at least one of limit or terminator")
|
34
|
-
else
|
35
|
-
@builder.has_matchers? || raise(InvalidStructureError, "You must specify one or more matchers")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def <<(other)
|
40
|
-
if other == terminator
|
41
|
-
@terminated = true
|
42
|
-
else
|
43
|
-
digit_buffer << other
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def digit_buffer
|
48
|
-
@digit_buffer
|
49
|
-
end
|
50
|
-
|
51
|
-
def digit_buffer_string
|
52
|
-
digit_buffer.to_s
|
53
|
-
end
|
54
|
-
alias :result :digit_buffer_string
|
55
|
-
|
56
|
-
def digit_buffer_empty?
|
57
|
-
digit_buffer.empty?
|
58
|
-
end
|
59
|
-
|
60
|
-
def continue
|
61
|
-
return get_another_digit_or_timeout! if digit_buffer_empty?
|
62
|
-
|
63
|
-
return menu_terminated! if @terminated
|
64
|
-
return menu_limit_reached! if limit && digit_buffer.size >= limit
|
65
|
-
|
66
|
-
return menu_validator_terminated! if execute_validator_hook
|
67
|
-
|
68
|
-
calculated_matches = builder.calculate_matches_for digit_buffer_string
|
69
|
-
|
70
|
-
if calculated_matches.exact_match_count >= 1
|
71
|
-
first_exact_match = calculated_matches.exact_matches.first
|
72
|
-
if calculated_matches.potential_match_count.zero?
|
73
|
-
menu_result_found! first_exact_match, digit_buffer_string
|
74
|
-
else
|
75
|
-
get_another_digit_or_finish! first_exact_match.match_payload, first_exact_match.query
|
76
|
-
end
|
77
|
-
elsif calculated_matches.potential_match_count >= 1 || !@builder.has_matchers?
|
78
|
-
get_another_digit_or_timeout!
|
79
|
-
else
|
80
|
-
invalid!
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def should_continue?
|
85
|
-
tries_count < max_number_of_tries
|
86
|
-
end
|
87
|
-
|
88
|
-
def restart!
|
89
|
-
@tries_count += 1
|
90
|
-
digit_buffer.clear!
|
91
|
-
end
|
92
|
-
|
93
|
-
def execute_invalid_hook
|
94
|
-
builder.execute_hook_for :invalid, digit_buffer_string
|
95
|
-
end
|
96
|
-
|
97
|
-
def execute_timeout_hook
|
98
|
-
builder.execute_hook_for :timeout, digit_buffer_string
|
99
|
-
end
|
100
|
-
|
101
|
-
def execute_failure_hook
|
102
|
-
builder.execute_hook_for :failure, digit_buffer_string
|
103
|
-
end
|
104
|
-
|
105
|
-
def execute_validator_hook
|
106
|
-
builder.execute_hook_for :validator, digit_buffer_string
|
107
|
-
end
|
108
|
-
|
109
|
-
protected
|
110
|
-
|
111
|
-
# If you're using a more complex class in subclasses, you may want to override this method in addition to the
|
112
|
-
# digit buffer, digit_buffer_empty, and digit_buffer_string methods
|
113
|
-
def initialize_digit_buffer
|
114
|
-
@digit_buffer = ClearableStringBuffer.new
|
115
|
-
end
|
116
|
-
|
117
|
-
def invalid!
|
118
|
-
@status = :invalid
|
119
|
-
MenuResultInvalid.new
|
120
|
-
end
|
121
|
-
|
122
|
-
def menu_result_found!(match_object, new_extension)
|
123
|
-
@status = :matched
|
124
|
-
MenuResultFound.new(match_object, new_extension)
|
125
|
-
end
|
126
|
-
|
127
|
-
def menu_terminated!
|
128
|
-
@status = :terminated
|
129
|
-
MenuTerminated.new
|
130
|
-
end
|
131
|
-
|
132
|
-
def menu_validator_terminated!
|
133
|
-
@status = :validator_terminated
|
134
|
-
MenuValidatorTerminated.new
|
135
|
-
end
|
136
|
-
|
137
|
-
def menu_limit_reached!
|
138
|
-
@status = :limited
|
139
|
-
MenuLimitReached.new
|
140
|
-
end
|
141
|
-
|
142
|
-
def get_another_digit_or_finish!(match_payload, new_extension)
|
143
|
-
@status = :multi_matched
|
144
|
-
MenuGetAnotherDigitOrFinish.new(match_payload, new_extension)
|
145
|
-
end
|
146
|
-
|
147
|
-
def get_another_digit_or_timeout!
|
148
|
-
@status = :potential
|
149
|
-
MenuGetAnotherDigitOrTimeout.new
|
150
|
-
end
|
151
|
-
|
152
|
-
# The superclass from which all message-like exceptions descend. It should never
|
153
|
-
# be instantiated directly.
|
154
|
-
MenuResult = Class.new
|
155
|
-
MenuResultDone = Class.new MenuResult
|
156
|
-
|
157
|
-
class MenuResultFound < MenuResult
|
158
|
-
|
159
|
-
attr_reader :match_object, :new_extension
|
160
|
-
|
161
|
-
def initialize(match_object, new_extension)
|
162
|
-
super()
|
163
|
-
@match_object = match_object
|
164
|
-
@new_extension = new_extension
|
165
|
-
end
|
166
|
-
|
167
|
-
end #class MenuResultFound < MenuResult
|
168
|
-
|
169
|
-
MenuGetAnotherDigit = Module.new
|
170
|
-
|
171
|
-
class MenuGetAnotherDigitOrFinish < MenuResultFound
|
172
|
-
include MenuGetAnotherDigit
|
173
|
-
end
|
174
|
-
|
175
|
-
class MenuGetAnotherDigitOrTimeout < MenuResult
|
176
|
-
include MenuGetAnotherDigit
|
177
|
-
end
|
178
|
-
|
179
|
-
MenuResultInvalid = Class.new MenuResult
|
180
|
-
|
181
|
-
MenuTerminated = Class.new MenuResultDone
|
182
|
-
MenuValidatorTerminated = Class.new MenuResultDone
|
183
|
-
MenuLimitReached = Class.new MenuResultDone
|
184
|
-
|
185
|
-
# For our default purpose, we need the digit_buffer to behave much like a normal String except that it should
|
186
|
-
# handle its own resetting (clearing)
|
187
|
-
class ClearableStringBuffer < String
|
188
|
-
def clear!
|
189
|
-
replace ""
|
190
|
-
end
|
191
|
-
|
192
|
-
def <<(other)
|
193
|
-
super other.to_s
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
|
198
|
-
end # class Menu
|
199
|
-
|
200
|
-
end
|
201
|
-
end
|
@@ -1,82 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Adhearsion
|
4
|
-
module MenuDSL
|
5
|
-
|
6
|
-
class MenuBuilder
|
7
|
-
|
8
|
-
attr_accessor :patterns, :menu_callbacks
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@patterns = []
|
12
|
-
@menu_callbacks = {}
|
13
|
-
@context = nil
|
14
|
-
end
|
15
|
-
|
16
|
-
def build(&block)
|
17
|
-
@context = eval "self", block.binding
|
18
|
-
instance_eval(&block)
|
19
|
-
end
|
20
|
-
|
21
|
-
def match(*args, &block)
|
22
|
-
payload = if block_given?
|
23
|
-
raise ArgumentError, "You cannot specify both a block and a controller name." if args.last.is_a? Class
|
24
|
-
nil
|
25
|
-
else
|
26
|
-
raise ArgumentError, "You need to provide a block or a controller name." unless args.last.is_a? Class
|
27
|
-
args.pop
|
28
|
-
end
|
29
|
-
|
30
|
-
raise ArgumentError, "You cannot call this method without patterns." if args.empty?
|
31
|
-
|
32
|
-
args.each do |pattern|
|
33
|
-
@patterns << MatchCalculator.build_with_pattern(pattern, payload, &block)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def weighted_match_calculators
|
38
|
-
@patterns
|
39
|
-
end
|
40
|
-
|
41
|
-
def has_matchers?
|
42
|
-
@patterns.size > 0
|
43
|
-
end
|
44
|
-
|
45
|
-
def execute_hook_for(symbol, input)
|
46
|
-
callback = @menu_callbacks[symbol]
|
47
|
-
return unless callback
|
48
|
-
@context.instance_exec input, &callback
|
49
|
-
end
|
50
|
-
|
51
|
-
def invalid(&block)
|
52
|
-
raise LocalJumpError, "Must supply a block!" unless block_given?
|
53
|
-
@menu_callbacks[:invalid] = block
|
54
|
-
end
|
55
|
-
|
56
|
-
def timeout(&block)
|
57
|
-
raise LocalJumpError, "Must supply a block!" unless block_given?
|
58
|
-
@menu_callbacks[:timeout] = block
|
59
|
-
end
|
60
|
-
|
61
|
-
def failure(&block)
|
62
|
-
raise LocalJumpError, "Must supply a block!" unless block_given?
|
63
|
-
@menu_callbacks[:failure] = block
|
64
|
-
end
|
65
|
-
|
66
|
-
def validator(&block)
|
67
|
-
raise LocalJumpError, "Must supply a block!" unless block_given?
|
68
|
-
@menu_callbacks[:validator] = block
|
69
|
-
end
|
70
|
-
|
71
|
-
def calculate_matches_for(result)
|
72
|
-
CalculatedMatchCollection.new.tap do |collection|
|
73
|
-
weighted_match_calculators.each do |pattern|
|
74
|
-
collection << pattern.match(result)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
end # class MenuBuilder
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|