adhearsion 2.0.0.beta1 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/.travis.yml +2 -4
  2. data/CHANGELOG.md +34 -4
  3. data/README.markdown +2 -1
  4. data/Rakefile +22 -1
  5. data/adhearsion.gemspec +1 -0
  6. data/bin/ahn +0 -2
  7. data/features/cli_daemon.feature +2 -0
  8. data/features/cli_restart.feature +19 -0
  9. data/features/cli_start.feature +4 -6
  10. data/features/cli_stop.feature +3 -0
  11. data/features/step_definitions/app_generator_steps.rb +2 -0
  12. data/features/step_definitions/cli_steps.rb +2 -0
  13. data/features/support/aruba_helper.rb +2 -0
  14. data/features/support/env.rb +8 -46
  15. data/features/support/utils.rb +2 -0
  16. data/lib/adhearsion.rb +4 -6
  17. data/lib/adhearsion/call.rb +71 -17
  18. data/lib/adhearsion/call_controller.rb +25 -14
  19. data/lib/adhearsion/call_controller/dial.rb +34 -15
  20. data/lib/adhearsion/call_controller/input.rb +186 -144
  21. data/lib/adhearsion/call_controller/output.rb +10 -6
  22. data/lib/adhearsion/call_controller/record.rb +11 -13
  23. data/lib/adhearsion/call_controller/utility.rb +2 -0
  24. data/lib/adhearsion/calls.rb +4 -2
  25. data/lib/adhearsion/cli.rb +4 -0
  26. data/lib/adhearsion/cli_commands.rb +8 -2
  27. data/lib/adhearsion/configuration.rb +7 -3
  28. data/lib/adhearsion/console.rb +17 -17
  29. data/lib/adhearsion/events.rb +10 -4
  30. data/lib/adhearsion/foundation.rb +9 -0
  31. data/lib/adhearsion/foundation/custom_daemonizer.rb +3 -1
  32. data/lib/adhearsion/foundation/exception_handler.rb +2 -0
  33. data/lib/adhearsion/foundation/libc.rb +2 -0
  34. data/lib/adhearsion/foundation/object.rb +3 -0
  35. data/lib/adhearsion/foundation/thread_safety.rb +5 -11
  36. data/lib/adhearsion/generators.rb +2 -0
  37. data/lib/adhearsion/generators/app/app_generator.rb +2 -0
  38. data/lib/adhearsion/generators/app/templates/README.md +9 -0
  39. data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +38 -16
  40. data/lib/adhearsion/generators/app/templates/config/environment.rb +2 -0
  41. data/lib/adhearsion/generators/app/templates/lib/simon_game.rb +5 -3
  42. data/lib/adhearsion/generators/controller/controller_generator.rb +2 -0
  43. data/lib/adhearsion/generators/controller/templates/lib/controller.rb +2 -0
  44. data/lib/adhearsion/generators/controller/templates/spec/controller_spec.rb +2 -0
  45. data/lib/adhearsion/generators/generator.rb +3 -1
  46. data/lib/adhearsion/generators/plugin/plugin_generator.rb +2 -0
  47. data/lib/adhearsion/initializer.rb +31 -17
  48. data/lib/adhearsion/linux_proc_name.rb +2 -0
  49. data/lib/adhearsion/logging.rb +5 -3
  50. data/lib/adhearsion/menu_dsl.rb +2 -0
  51. data/lib/adhearsion/menu_dsl/calculated_match.rb +2 -0
  52. data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +2 -0
  53. data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +2 -0
  54. data/lib/adhearsion/menu_dsl/match_calculator.rb +2 -0
  55. data/lib/adhearsion/menu_dsl/menu.rb +58 -4
  56. data/lib/adhearsion/menu_dsl/menu_builder.rb +14 -1
  57. data/lib/adhearsion/menu_dsl/range_match_calculator.rb +4 -1
  58. data/lib/adhearsion/menu_dsl/string_match_calculator.rb +2 -0
  59. data/lib/adhearsion/outbound_call.rb +2 -0
  60. data/lib/adhearsion/plugin.rb +9 -7
  61. data/lib/adhearsion/plugin/collection.rb +3 -1
  62. data/lib/adhearsion/plugin/initializer.rb +3 -1
  63. data/lib/adhearsion/process.rb +8 -2
  64. data/lib/adhearsion/punchblock_plugin.rb +3 -1
  65. data/lib/adhearsion/punchblock_plugin/initializer.rb +34 -11
  66. data/lib/adhearsion/router.rb +4 -2
  67. data/lib/adhearsion/router/route.rb +2 -0
  68. data/lib/adhearsion/script_ahn_loader.rb +2 -0
  69. data/lib/adhearsion/tasks.rb +2 -0
  70. data/lib/adhearsion/tasks/configuration.rb +2 -0
  71. data/lib/adhearsion/tasks/debugging.rb +8 -0
  72. data/lib/adhearsion/tasks/environment.rb +2 -0
  73. data/lib/adhearsion/tasks/plugins.rb +2 -0
  74. data/lib/adhearsion/tasks/testing.rb +2 -0
  75. data/lib/adhearsion/version.rb +3 -1
  76. data/pre-commit +2 -0
  77. data/spec/adhearsion/call_controller/dial_spec.rb +114 -25
  78. data/spec/adhearsion/call_controller/input_spec.rb +192 -169
  79. data/spec/adhearsion/call_controller/output_spec.rb +26 -12
  80. data/spec/adhearsion/call_controller/record_spec.rb +29 -77
  81. data/spec/adhearsion/call_controller/utility_spec.rb +69 -0
  82. data/spec/adhearsion/call_controller_spec.rb +90 -15
  83. data/spec/adhearsion/call_spec.rb +92 -24
  84. data/spec/adhearsion/calls_spec.rb +9 -7
  85. data/spec/adhearsion/configuration_spec.rb +58 -56
  86. data/spec/adhearsion/console_spec.rb +4 -2
  87. data/spec/adhearsion/events_spec.rb +9 -7
  88. data/spec/adhearsion/generators_spec.rb +3 -1
  89. data/spec/adhearsion/initializer_spec.rb +16 -14
  90. data/spec/adhearsion/logging_spec.rb +11 -9
  91. data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +6 -4
  92. data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +6 -4
  93. data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +3 -1
  94. data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +2 -0
  95. data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +42 -11
  96. data/spec/adhearsion/menu_dsl/menu_spec.rb +197 -36
  97. data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +4 -2
  98. data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +5 -3
  99. data/spec/adhearsion/outbound_call_spec.rb +7 -5
  100. data/spec/adhearsion/plugin_spec.rb +19 -15
  101. data/spec/adhearsion/process_spec.rb +12 -7
  102. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +35 -15
  103. data/spec/adhearsion/punchblock_plugin_spec.rb +4 -1
  104. data/spec/adhearsion/router/route_spec.rb +8 -6
  105. data/spec/adhearsion/router_spec.rb +12 -10
  106. data/spec/adhearsion_spec.rb +13 -2
  107. data/spec/capture_warnings.rb +33 -0
  108. data/spec/spec_helper.rb +4 -0
  109. data/spec/support/call_controller_test_helpers.rb +2 -4
  110. data/spec/support/initializer_stubs.rb +8 -5
  111. data/spec/support/logging_helpers.rb +2 -0
  112. data/spec/support/punchblock_mocks.rb +2 -0
  113. metadata +84 -71
  114. data/EVENTS +0 -11
  115. data/lib/adhearsion/call_controller/menu.rb +0 -124
  116. data/lib/adhearsion/foundation/all.rb +0 -8
  117. data/spec/adhearsion/call_controller/menu_spec.rb +0 -120
  118. data/spec/adhearsion/menu_dsl_spec.rb +0 -12
@@ -1,27 +1,28 @@
1
- # Centralized way to overwrite any Adhearsion platform or plugin configuration
2
- # - Execute rake adhearsion:config:desc to get the configuration options
3
- # - Execute rake adhearsion:config:show to get the configuration values
4
- #
5
- # To update a plugin configuration you can write either:
6
- #
7
- # * Option 1
8
- # Adhearsion.config.<plugin-name> do |config|
9
- # config.<key> = <value>
10
- # end
11
- #
12
- # * Option 2
13
- # Adhearsion.config do |config|
14
- # config.<plugin-name>.<key> = <value>
15
- # end
1
+ # encoding: utf-8
16
2
 
17
3
  Adhearsion.config do |config|
18
4
 
5
+ # Centralized way to specify any Adhearsion platform or plugin configuration
6
+ # - Execute rake config:show to view the active configuration values
7
+ #
8
+ # To update a plugin configuration you can write either:
9
+ #
10
+ # * Option 1
11
+ # Adhearsion.config.<plugin-name> do |config|
12
+ # config.<key> = <value>
13
+ # end
14
+ #
15
+ # * Option 2
16
+ # Adhearsion.config do |config|
17
+ # config.<plugin-name>.<key> = <value>
18
+ # end
19
+
19
20
  config.development do |dev|
20
21
  dev.platform.logging.level = :debug
21
22
  end
22
23
 
23
24
  ##
24
- # Use with Voxeo PRISM or other Rayo installation
25
+ # Use with Rayo (eg Voxeo PRISM)
25
26
  #
26
27
  # config.punchblock.username = "" # Your XMPP JID for use with Rayo
27
28
  # config.punchblock.password = "" # Your XMPP password
@@ -36,6 +37,27 @@ Adhearsion.config do |config|
36
37
  # config.punchblock.port = 5038 # Your AMI port
37
38
  end
38
39
 
40
+ Adhearsion::Events.draw do
41
+
42
+ # Register global handlers for events
43
+ #
44
+ # eg. Handling Punchblock events
45
+ # punchblock do |event|
46
+ # ...
47
+ # end
48
+ #
49
+ # eg Handling PeerStatus AMI events
50
+ # ami :name => 'PeerStatus' do |event|
51
+ # ...
52
+ # end
53
+ #
54
+ end
55
+
39
56
  Adhearsion.router do
57
+
58
+ #
59
+ # Specify your call routes, directing calls with particular attributes to a controller
60
+ #
61
+
40
62
  route 'default', SimonGame
41
63
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'rubygems'
2
4
  require 'bundler'
3
5
  Bundler.setup
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  class SimonGame < Adhearsion::CallController
2
4
  def run
3
5
  answer
@@ -19,7 +21,7 @@ class SimonGame < Adhearsion::CallController
19
21
 
20
22
  def say_number
21
23
  update_number
22
- speak @number
24
+ say @number
23
25
  end
24
26
 
25
27
  def collect_attempt
@@ -28,9 +30,9 @@ class SimonGame < Adhearsion::CallController
28
30
 
29
31
  def verify_attempt
30
32
  if attempt_correct?
31
- speak 'good'
33
+ say 'good'
32
34
  else
33
- speak "#{@number.length - 1} times wrong, try again smarty"
35
+ say "#{@number.length - 1} times wrong, try again smarty"
34
36
  reset
35
37
  end
36
38
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Adhearsion
2
4
  module Generators
3
5
  class ControllerGenerator < Generator
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  class <%= @controller_name %> < Adhearsion::CallController
2
4
  def run
3
5
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  describe <%= @controller_name %> do
2
4
 
3
5
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  begin
2
4
  require 'thor/group'
3
5
  rescue LoadError
@@ -66,7 +68,7 @@ module Adhearsion
66
68
  def self.generator_name
67
69
  @generator_name ||= begin
68
70
  if generator = name.to_s.split('::').last
69
- generator.sub! /Generator$/, ''
71
+ generator.sub!(/Generator$/, '')
70
72
  generator.underscore
71
73
  end
72
74
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Adhearsion
2
4
  module Generators
3
5
  class PluginGenerator < Generator
@@ -1,5 +1,8 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'adhearsion/punchblock_plugin'
2
4
  require 'adhearsion/linux_proc_name'
5
+ require 'rbconfig'
3
6
 
4
7
  module Adhearsion
5
8
  class Initializer
@@ -41,6 +44,7 @@ module Adhearsion
41
44
  initialize_log_paths
42
45
  daemonize! if should_daemonize?
43
46
  start_logging
47
+ debugging_log
44
48
  launch_console if need_console?
45
49
  catch_termination_signal
46
50
  create_pid_file
@@ -52,10 +56,9 @@ module Adhearsion
52
56
  run_plugins
53
57
  trigger_after_initialized_hooks
54
58
 
55
- if Adhearsion.status == :booting
56
- Adhearsion::Process.booted
57
- logger.info "Adhearsion v#{Adhearsion::VERSION} initialized with environment <#{Adhearsion.config.platform.environment}>!"
58
- end
59
+ Adhearsion::Process.booted if Adhearsion.status == :booting
60
+
61
+ logger.info "Adhearsion v#{Adhearsion::VERSION} initialized in \"#{Adhearsion.config.platform.environment}\"!" if Adhearsion.status == :running
59
62
 
60
63
  # This method will block until all important threads have finished.
61
64
  # When it does, the process will exit.
@@ -63,25 +66,37 @@ module Adhearsion
63
66
  self
64
67
  end
65
68
 
69
+ def debugging_items
70
+ [
71
+ "OS: #{RbConfig::CONFIG['host_os']} - RUBY: #{RUBY_ENGINE} #{RUBY_VERSION}",
72
+ "Environment: #{ENV.inspect}",
73
+ Adhearsion.config.description(:all),
74
+ "Gem versions: #{Gem.loaded_specs.inject([]) { |c,g| c << "#{g[0]} #{g[1].version}" }}"
75
+ ]
76
+ end
77
+
78
+ def debugging_log
79
+ debugging_items.each do |item|
80
+ logger.trace item
81
+ end
82
+ end
83
+
66
84
  def update_rails_env_var
67
85
  env = ENV['AHN_ENV']
68
86
  if env && Adhearsion.config.valid_environment?(env.to_sym)
69
- if ENV['RAILS_ENV']
70
- logger.info "Using provided RAILS_ENV value of <#{ENV['RAILS_ENV']}>"
71
- else
72
- logger.warn "Setting RAILS_ENV variable to <#{env}>"
87
+ unless ENV['RAILS_ENV']
88
+ logger.info "Copying AHN_ENV (#{env}) to RAILS_ENV"
73
89
  ENV['RAILS_ENV'] = env
74
90
  end
75
91
  else
76
- env = ENV['RAILS_ENV']
77
- if env
78
- logger.info "Using the configured value for RAILS_ENV : <#{env}>"
79
- else
92
+ unless ENV['RAILS_ENV']
80
93
  env = Adhearsion.config.platform.environment.to_s
81
- logger.info "Defining RAILS_ENV variable to <#{env}>"
94
+ ENV['AHN_ENV'] = env
95
+ logger.info "Setting RAILS_ENV to \"#{env}\""
82
96
  ENV['RAILS_ENV'] = env
83
97
  end
84
98
  end
99
+ logger.warn "AHN_ENV(#{ENV['AHN_ENV']}) does not match RAILS_ENV(#{ENV['RAILS_ENV']})!" unless ENV['RAILS_ENV'] == ENV['AHN_ENV']
85
100
  env
86
101
  end
87
102
 
@@ -202,7 +217,7 @@ module Adhearsion
202
217
 
203
218
  def daemonize!
204
219
  logger.info "Daemonizing now!"
205
- logger.info "Creating PID file #{pid_file}"
220
+ logger.debug "Creating PID file #{pid_file}"
206
221
  extend Adhearsion::CustomDaemonizer
207
222
  daemonize resolve_log_file_path
208
223
  end
@@ -211,7 +226,6 @@ module Adhearsion
211
226
  Adhearsion::Process.important_threads << Thread.new do
212
227
  catching_standard_errors do
213
228
  Adhearsion::Console.run
214
- Adhearsion::Process.shutdown
215
229
  end
216
230
  end
217
231
  end
@@ -241,8 +255,8 @@ module Adhearsion
241
255
  end
242
256
 
243
257
  def initialize_exception_logger
244
- Events.register_handler :exception do |e|
245
- logger.error e
258
+ Events.register_handler :exception do |e, l|
259
+ (l || logger).error e
246
260
  end
247
261
  end
248
262
 
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Adhearsion
2
4
 
3
5
  # https://gist.github.com/1350729
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'logging'
2
4
 
3
5
  module Adhearsion
@@ -11,14 +13,14 @@ module Adhearsion
11
13
 
12
14
  ::Logging.color_scheme 'bright',
13
15
  :levels => {
16
+ :debug => :magenta,
14
17
  :info => :green,
15
18
  :warn => :yellow,
16
19
  :error => :red,
17
20
  :fatal => [:white, :on_red]
18
21
  },
19
- :date => :blue,
20
- :logger => :cyan,
21
- :message => :magenta
22
+ :date => [:bold, :blue],
23
+ :logger => :cyan
22
24
 
23
25
  def adhearsion_pattern
24
26
  '[%d] %-5l %c: %m\n'
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Adhearsion
2
4
  module MenuDSL
3
5
  extend ActiveSupport::Autoload
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Adhearsion
2
4
  module MenuDSL
3
5
  class CalculatedMatch
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Adhearsion
2
4
  module MenuDSL
3
5
  class CalculatedMatchCollection
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Adhearsion
2
4
  module MenuDSL
3
5
  class FixnumMatchCalculator < MatchCalculator
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Adhearsion
2
4
  module MenuDSL
3
5
  class MatchCalculator
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Adhearsion
2
4
  module MenuDSL
3
5
 
@@ -6,21 +8,40 @@ module Adhearsion
6
8
  DEFAULT_MAX_NUMBER_OF_TRIES = 1
7
9
  DEFAULT_TIMEOUT = 5
8
10
 
9
- attr_reader :builder, :timeout, :tries_count, :max_number_of_tries
11
+ InvalidStructureError = Class.new StandardError
12
+
13
+ attr_reader :builder, :timeout, :tries_count, :max_number_of_tries, :terminator, :limit, :interruptible, :status
10
14
 
11
15
  def initialize(options = {}, &block)
12
16
  @tries_count = 0 # Counts the number of tries the menu's been executed
13
17
  @timeout = options[:timeout] || DEFAULT_TIMEOUT
14
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
15
22
  @builder = MenuDSL::MenuBuilder.new
23
+ @terminated = false
16
24
 
17
- @builder.build &block
25
+ @builder.build(&block) if block
18
26
 
19
27
  initialize_digit_buffer
20
28
  end
21
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
+
22
39
  def <<(other)
23
- digit_buffer << other
40
+ if other == terminator
41
+ @terminated = true
42
+ else
43
+ digit_buffer << other
44
+ end
24
45
  end
25
46
 
26
47
  def digit_buffer
@@ -30,6 +51,7 @@ module Adhearsion
30
51
  def digit_buffer_string
31
52
  digit_buffer.to_s
32
53
  end
54
+ alias :result :digit_buffer_string
33
55
 
34
56
  def digit_buffer_empty?
35
57
  digit_buffer.empty?
@@ -38,6 +60,11 @@ module Adhearsion
38
60
  def continue
39
61
  return get_another_digit_or_timeout! if digit_buffer_empty?
40
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
+
41
68
  calculated_matches = builder.calculate_matches_for digit_buffer_string
42
69
 
43
70
  if calculated_matches.exact_match_count >= 1
@@ -47,7 +74,7 @@ module Adhearsion
47
74
  else
48
75
  get_another_digit_or_finish! first_exact_match.match_payload, first_exact_match.query
49
76
  end
50
- elsif calculated_matches.potential_match_count >= 1
77
+ elsif calculated_matches.potential_match_count >= 1 || !@builder.has_matchers?
51
78
  get_another_digit_or_timeout!
52
79
  else
53
80
  invalid!
@@ -75,6 +102,10 @@ module Adhearsion
75
102
  builder.execute_hook_for :failure, digit_buffer_string
76
103
  end
77
104
 
105
+ def execute_validator_hook
106
+ builder.execute_hook_for :validator, digit_buffer_string
107
+ end
108
+
78
109
  protected
79
110
 
80
111
  # If you're using a more complex class in subclasses, you may want to override this method in addition to the
@@ -84,18 +115,37 @@ module Adhearsion
84
115
  end
85
116
 
86
117
  def invalid!
118
+ @status = :invalid
87
119
  MenuResultInvalid.new
88
120
  end
89
121
 
90
122
  def menu_result_found!(match_object, new_extension)
123
+ @status = :matched
91
124
  MenuResultFound.new(match_object, new_extension)
92
125
  end
93
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
+
94
142
  def get_another_digit_or_finish!(match_payload, new_extension)
143
+ @status = :multi_matched
95
144
  MenuGetAnotherDigitOrFinish.new(match_payload, new_extension)
96
145
  end
97
146
 
98
147
  def get_another_digit_or_timeout!
148
+ @status = :potential
99
149
  MenuGetAnotherDigitOrTimeout.new
100
150
  end
101
151
 
@@ -128,6 +178,10 @@ module Adhearsion
128
178
 
129
179
  MenuResultInvalid = Class.new MenuResult
130
180
 
181
+ MenuTerminated = Class.new MenuResultDone
182
+ MenuValidatorTerminated = Class.new MenuResultDone
183
+ MenuLimitReached = Class.new MenuResultDone
184
+
131
185
  # For our default purpose, we need the digit_buffer to behave much like a normal String except that it should
132
186
  # handle its own resetting (clearing)
133
187
  class ClearableStringBuffer < String