adhearsion 2.0.0.rc4 → 2.0.0.rc5

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.
Files changed (45) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/adhearsion.gemspec +1 -1
  3. data/bin/ahn +0 -3
  4. data/lib/adhearsion.rb +7 -4
  5. data/lib/adhearsion/call.rb +1 -1
  6. data/lib/adhearsion/call_controller.rb +1 -0
  7. data/lib/adhearsion/call_controller/menu_dsl.rb +19 -0
  8. data/lib/adhearsion/call_controller/menu_dsl/calculated_match.rb +43 -0
  9. data/lib/adhearsion/call_controller/menu_dsl/calculated_match_collection.rb +45 -0
  10. data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +22 -0
  11. data/lib/adhearsion/call_controller/menu_dsl/match_calculator.rb +40 -0
  12. data/lib/adhearsion/call_controller/menu_dsl/menu.rb +203 -0
  13. data/lib/adhearsion/call_controller/menu_dsl/menu_builder.rb +84 -0
  14. data/lib/adhearsion/call_controller/menu_dsl/range_match_calculator.rb +60 -0
  15. data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +25 -0
  16. data/lib/adhearsion/cli.rb +0 -1
  17. data/lib/adhearsion/router/route.rb +2 -2
  18. data/lib/adhearsion/version.rb +1 -1
  19. data/spec/adhearsion/call_controller/input_spec.rb +1 -1
  20. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +60 -0
  21. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +61 -0
  22. data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +37 -0
  23. data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +17 -0
  24. data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +151 -0
  25. data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +373 -0
  26. data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +32 -0
  27. data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +40 -0
  28. metadata +91 -91
  29. data/lib/adhearsion/menu_dsl.rb +0 -17
  30. data/lib/adhearsion/menu_dsl/calculated_match.rb +0 -41
  31. data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +0 -43
  32. data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +0 -20
  33. data/lib/adhearsion/menu_dsl/match_calculator.rb +0 -38
  34. data/lib/adhearsion/menu_dsl/menu.rb +0 -201
  35. data/lib/adhearsion/menu_dsl/menu_builder.rb +0 -82
  36. data/lib/adhearsion/menu_dsl/range_match_calculator.rb +0 -58
  37. data/lib/adhearsion/menu_dsl/string_match_calculator.rb +0 -23
  38. data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +0 -58
  39. data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +0 -59
  40. data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +0 -35
  41. data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +0 -15
  42. data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +0 -149
  43. data/spec/adhearsion/menu_dsl/menu_spec.rb +0 -371
  44. data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +0 -30
  45. data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +0 -38
@@ -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