adhearsion 1.2.6 → 2.0.0.alpha1

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 (236) hide show
  1. data/.gitignore +17 -10
  2. data/CHANGELOG.md +273 -0
  3. data/Gemfile +1 -1
  4. data/Guardfile +17 -0
  5. data/README.markdown +61 -9
  6. data/Rakefile +16 -48
  7. data/adhearsion.gemspec +21 -7
  8. data/bin/ahn +3 -1
  9. data/cucumber.yml +4 -0
  10. data/features/app_generator.feature +42 -0
  11. data/features/cli.feature +108 -0
  12. data/features/step_definitions/app_generator_steps.rb +6 -0
  13. data/features/step_definitions/cli_steps.rb +74 -0
  14. data/features/support/aruba_helper.rb +22 -0
  15. data/features/support/env.rb +37 -0
  16. data/features/support/utils.rb +8 -0
  17. data/lib/adhearsion.rb +85 -41
  18. data/lib/adhearsion/call.rb +176 -0
  19. data/lib/adhearsion/call_controller.rb +134 -0
  20. data/lib/adhearsion/call_controller/dial.rb +70 -0
  21. data/lib/adhearsion/call_controller/input.rb +173 -0
  22. data/lib/adhearsion/call_controller/menu.rb +124 -0
  23. data/lib/adhearsion/call_controller/output.rb +267 -0
  24. data/lib/adhearsion/call_controller/record.rb +42 -0
  25. data/lib/adhearsion/call_controller/utility.rb +60 -0
  26. data/lib/adhearsion/calls.rb +81 -0
  27. data/lib/adhearsion/cli.rb +1 -3
  28. data/lib/adhearsion/cli_commands.rb +142 -0
  29. data/lib/adhearsion/configuration.rb +149 -0
  30. data/lib/adhearsion/console.rb +19 -8
  31. data/lib/adhearsion/dialplan_controller.rb +9 -0
  32. data/lib/adhearsion/events.rb +84 -0
  33. data/lib/adhearsion/foundation/all.rb +0 -7
  34. data/lib/adhearsion/foundation/custom_daemonizer.rb +4 -6
  35. data/lib/adhearsion/foundation/exception_handler.rb +9 -0
  36. data/lib/adhearsion/foundation/object.rb +26 -8
  37. data/lib/adhearsion/foundation/synchronized_hash.rb +3 -6
  38. data/lib/adhearsion/foundation/thread_safety.rb +17 -1
  39. data/lib/adhearsion/generators/app/app_generator.rb +4 -13
  40. data/lib/adhearsion/generators/app/templates/Gemfile +10 -5
  41. data/lib/adhearsion/generators/app/templates/Procfile +1 -0
  42. data/lib/adhearsion/generators/app/templates/README.md +28 -0
  43. data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +41 -0
  44. data/lib/adhearsion/generators/app/templates/{components/simon_game → lib}/simon_game.rb +6 -18
  45. data/lib/adhearsion/generators/app/templates/script/ahn +2 -2
  46. data/lib/adhearsion/initializer.rb +151 -293
  47. data/lib/adhearsion/initializer/logging.rb +33 -0
  48. data/lib/adhearsion/logging.rb +65 -69
  49. data/lib/adhearsion/menu_dsl.rb +15 -0
  50. data/lib/adhearsion/menu_dsl/calculated_match.rb +39 -0
  51. data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +41 -0
  52. data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +18 -0
  53. data/lib/adhearsion/menu_dsl/match_calculator.rb +36 -0
  54. data/lib/adhearsion/{voip/menu_state_machine/menu_class.rb → menu_dsl/menu.rb} +38 -40
  55. data/lib/adhearsion/menu_dsl/menu_builder.rb +69 -0
  56. data/lib/adhearsion/menu_dsl/range_match_calculator.rb +55 -0
  57. data/lib/adhearsion/menu_dsl/string_match_calculator.rb +21 -0
  58. data/lib/adhearsion/outbound_call.rb +64 -0
  59. data/lib/adhearsion/plugin.rb +319 -0
  60. data/lib/adhearsion/plugin/collection.rb +19 -0
  61. data/lib/adhearsion/plugin/initializer.rb +37 -0
  62. data/lib/adhearsion/plugin/methods_container.rb +6 -0
  63. data/lib/adhearsion/process.rb +94 -0
  64. data/lib/adhearsion/punchblock_plugin.rb +29 -0
  65. data/lib/adhearsion/punchblock_plugin/initializer.rb +137 -0
  66. data/lib/adhearsion/router.rb +30 -0
  67. data/lib/adhearsion/router/route.rb +42 -0
  68. data/lib/adhearsion/script_ahn_loader.rb +2 -2
  69. data/lib/adhearsion/tasks.rb +14 -9
  70. data/lib/adhearsion/tasks/configuration.rb +26 -0
  71. data/lib/adhearsion/tasks/plugins.rb +17 -0
  72. data/lib/adhearsion/version.rb +8 -14
  73. data/spec/adhearsion/call_controller/dial_spec.rb +138 -0
  74. data/spec/adhearsion/call_controller/input_spec.rb +278 -0
  75. data/spec/adhearsion/call_controller/menu_spec.rb +120 -0
  76. data/spec/adhearsion/call_controller/output_spec.rb +466 -0
  77. data/spec/adhearsion/call_controller/record_spec.rb +125 -0
  78. data/spec/adhearsion/call_controller_spec.rb +395 -0
  79. data/spec/adhearsion/call_spec.rb +438 -0
  80. data/spec/adhearsion/calls_spec.rb +47 -0
  81. data/spec/adhearsion/configuration_spec.rb +308 -0
  82. data/spec/adhearsion/dialplan_controller_spec.rb +26 -0
  83. data/spec/adhearsion/events_spec.rb +112 -0
  84. data/spec/adhearsion/initializer/logging_spec.rb +58 -0
  85. data/spec/adhearsion/initializer_spec.rb +209 -122
  86. data/spec/adhearsion/logging_spec.rb +58 -47
  87. data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +56 -0
  88. data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +57 -0
  89. data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +33 -0
  90. data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +13 -0
  91. data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +118 -0
  92. data/spec/adhearsion/menu_dsl/menu_spec.rb +210 -0
  93. data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +28 -0
  94. data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +36 -0
  95. data/spec/adhearsion/menu_dsl_spec.rb +12 -0
  96. data/spec/adhearsion/outbound_call_spec.rb +174 -0
  97. data/spec/adhearsion/plugin_spec.rb +489 -0
  98. data/spec/adhearsion/process_spec.rb +34 -0
  99. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +294 -0
  100. data/spec/adhearsion/router/route_spec.rb +99 -0
  101. data/spec/adhearsion/router_spec.rb +106 -0
  102. data/spec/adhearsion_spec.rb +46 -0
  103. data/spec/spec_helper.rb +14 -14
  104. data/spec/support/call_controller_test_helpers.rb +48 -0
  105. data/spec/support/initializer_stubs.rb +8 -13
  106. data/spec/support/punchblock_mocks.rb +6 -0
  107. metadata +255 -253
  108. data/CHANGELOG +0 -174
  109. data/bin/ahnctl +0 -68
  110. data/bin/jahn +0 -43
  111. data/examples/asterisk_manager_interface/standalone.rb +0 -51
  112. data/lib/adhearsion/commands.rb +0 -302
  113. data/lib/adhearsion/component_manager.rb +0 -278
  114. data/lib/adhearsion/component_manager/component_tester.rb +0 -54
  115. data/lib/adhearsion/component_manager/spec_framework.rb +0 -18
  116. data/lib/adhearsion/events_support.rb +0 -65
  117. data/lib/adhearsion/foundation/blank_slate.rb +0 -3
  118. data/lib/adhearsion/foundation/event_socket.rb +0 -205
  119. data/lib/adhearsion/foundation/future_resource.rb +0 -36
  120. data/lib/adhearsion/foundation/metaprogramming.rb +0 -17
  121. data/lib/adhearsion/foundation/numeric.rb +0 -13
  122. data/lib/adhearsion/foundation/pseudo_guid.rb +0 -10
  123. data/lib/adhearsion/foundation/relationship_properties.rb +0 -42
  124. data/lib/adhearsion/foundation/string.rb +0 -26
  125. data/lib/adhearsion/generators/app/templates/.ahnrc +0 -34
  126. data/lib/adhearsion/generators/app/templates/README +0 -8
  127. data/lib/adhearsion/generators/app/templates/components/ami_remote/ami_remote.rb +0 -15
  128. data/lib/adhearsion/generators/app/templates/components/disabled/HOW_TO_ENABLE +0 -7
  129. data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/README.markdown +0 -47
  130. data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.rb +0 -34
  131. data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.yml +0 -12
  132. data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/README.markdown +0 -3
  133. data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb +0 -11
  134. data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml +0 -0
  135. data/lib/adhearsion/generators/app/templates/config/startup.rb +0 -81
  136. data/lib/adhearsion/generators/app/templates/dialplan.rb +0 -3
  137. data/lib/adhearsion/generators/app/templates/events.rb +0 -33
  138. data/lib/adhearsion/host_definitions.rb +0 -67
  139. data/lib/adhearsion/initializer/asterisk.rb +0 -86
  140. data/lib/adhearsion/initializer/configuration.rb +0 -324
  141. data/lib/adhearsion/initializer/database.rb +0 -60
  142. data/lib/adhearsion/initializer/drb.rb +0 -31
  143. data/lib/adhearsion/initializer/freeswitch.rb +0 -22
  144. data/lib/adhearsion/initializer/ldap.rb +0 -57
  145. data/lib/adhearsion/initializer/rails.rb +0 -41
  146. data/lib/adhearsion/initializer/xmpp.rb +0 -42
  147. data/lib/adhearsion/tasks/components.rb +0 -32
  148. data/lib/adhearsion/tasks/database.rb +0 -5
  149. data/lib/adhearsion/tasks/deprecations.rb +0 -59
  150. data/lib/adhearsion/tasks/generating.rb +0 -20
  151. data/lib/adhearsion/tasks/lint.rb +0 -4
  152. data/lib/adhearsion/voip/asterisk.rb +0 -4
  153. data/lib/adhearsion/voip/asterisk/agi_server.rb +0 -121
  154. data/lib/adhearsion/voip/asterisk/commands.rb +0 -1966
  155. data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +0 -140
  156. data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +0 -102
  157. data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +0 -250
  158. data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +0 -240
  159. data/lib/adhearsion/voip/asterisk/config_manager.rb +0 -64
  160. data/lib/adhearsion/voip/asterisk/manager_interface.rb +0 -697
  161. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +0 -1681
  162. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +0 -341
  163. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +0 -78
  164. data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +0 -87
  165. data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +0 -80
  166. data/lib/adhearsion/voip/call.rb +0 -521
  167. data/lib/adhearsion/voip/call_routing.rb +0 -64
  168. data/lib/adhearsion/voip/commands.rb +0 -17
  169. data/lib/adhearsion/voip/constants.rb +0 -39
  170. data/lib/adhearsion/voip/conveniences.rb +0 -18
  171. data/lib/adhearsion/voip/dial_plan.rb +0 -252
  172. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +0 -151
  173. data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +0 -37
  174. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +0 -27
  175. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +0 -124
  176. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +0 -69
  177. data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +0 -16
  178. data/lib/adhearsion/voip/dsl/numerical_string.rb +0 -128
  179. data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +0 -48
  180. data/lib/adhearsion/voip/freeswitch/event_handler.rb +0 -58
  181. data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +0 -129
  182. data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +0 -38
  183. data/lib/adhearsion/voip/freeswitch/oes_server.rb +0 -195
  184. data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +0 -80
  185. data/lib/adhearsion/voip/menu_state_machine/matchers.rb +0 -123
  186. data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +0 -57
  187. data/lib/adhearsion/xmpp/connection.rb +0 -61
  188. data/lib/theatre.rb +0 -147
  189. data/lib/theatre/README.markdown +0 -64
  190. data/lib/theatre/callback_definition_loader.rb +0 -86
  191. data/lib/theatre/guid.rb +0 -23
  192. data/lib/theatre/invocation.rb +0 -131
  193. data/lib/theatre/namespace_manager.rb +0 -153
  194. data/lib/theatre/version.rb +0 -2
  195. data/spec/adhearsion/cli_spec.rb +0 -306
  196. data/spec/adhearsion/component_manager_spec.rb +0 -292
  197. data/spec/adhearsion/constants_spec.rb +0 -8
  198. data/spec/adhearsion/drb_spec.rb +0 -65
  199. data/spec/adhearsion/fixtures/dialplan.rb +0 -3
  200. data/spec/adhearsion/foundation/event_socket_spec.rb +0 -168
  201. data/spec/adhearsion/host_definitions_spec.rb +0 -79
  202. data/spec/adhearsion/initializer/configuration_spec.rb +0 -291
  203. data/spec/adhearsion/initializer/loading_spec.rb +0 -154
  204. data/spec/adhearsion/initializer/paths_spec.rb +0 -74
  205. data/spec/adhearsion/relationship_properties_spec.rb +0 -54
  206. data/spec/adhearsion/voip/asterisk/agi_server_spec.rb +0 -473
  207. data/spec/adhearsion/voip/asterisk/ami/ami_spec.rb +0 -550
  208. data/spec/adhearsion/voip/asterisk/ami/lexer/ami_fixtures.yml +0 -30
  209. data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story +0 -291
  210. data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story.rb +0 -241
  211. data/spec/adhearsion/voip/asterisk/ami/lexer/story_helper.rb +0 -124
  212. data/spec/adhearsion/voip/asterisk/commands_spec.rb +0 -3241
  213. data/spec/adhearsion/voip/asterisk/config_file_generators/agents_spec.rb +0 -251
  214. data/spec/adhearsion/voip/asterisk/config_file_generators/queues_spec.rb +0 -323
  215. data/spec/adhearsion/voip/asterisk/config_file_generators/voicemail_spec.rb +0 -306
  216. data/spec/adhearsion/voip/asterisk/config_manager_spec.rb +0 -127
  217. data/spec/adhearsion/voip/asterisk/menu_command/calculated_match_spec.rb +0 -109
  218. data/spec/adhearsion/voip/asterisk/menu_command/matchers_spec.rb +0 -97
  219. data/spec/adhearsion/voip/call_routing_spec.rb +0 -125
  220. data/spec/adhearsion/voip/dialplan_manager_spec.rb +0 -468
  221. data/spec/adhearsion/voip/dsl/dialing_dsl_spec.rb +0 -270
  222. data/spec/adhearsion/voip/dsl/dispatcher_spec.rb +0 -82
  223. data/spec/adhearsion/voip/dsl/dispatcher_spec_helper.rb +0 -45
  224. data/spec/adhearsion/voip/dsl/parser_spec.rb +0 -69
  225. data/spec/adhearsion/voip/freeswitch/basic_connection_manager_spec.rb +0 -39
  226. data/spec/adhearsion/voip/freeswitch/inbound_connection_manager_spec.rb +0 -39
  227. data/spec/adhearsion/voip/freeswitch/oes_server_spec.rb +0 -9
  228. data/spec/adhearsion/voip/numerical_string_spec.rb +0 -61
  229. data/spec/adhearsion/voip/phone_number_spec.rb +0 -45
  230. data/spec/support/the_following_code.rb +0 -3
  231. data/spec/theatre/dsl_examples/simple_before_call.rb +0 -7
  232. data/spec/theatre/dsl_spec.rb +0 -69
  233. data/spec/theatre/invocation_spec.rb +0 -182
  234. data/spec/theatre/namespace_spec.rb +0 -125
  235. data/spec/theatre/spec_helper_spec.rb +0 -28
  236. data/spec/theatre/theatre_class_spec.rb +0 -148
@@ -1,86 +0,0 @@
1
- module Theatre
2
-
3
- ##
4
- # This class provides the a wrapper aroung which an events.rb file can be instance_eval'd.
5
- #
6
- class CallbackDefinitionLoader
7
-
8
- attr_reader :theatre, :root_name
9
- def initialize(theatre, root_name=:events)
10
- @theatre = theatre
11
- @root_name = root_name
12
-
13
- create_recorder_method root_name
14
- end
15
-
16
- def anonymous_recorder
17
- BlankSlateMessageRecorder.new(&method(:callback_registered))
18
- end
19
-
20
- ##
21
- # Parses the given Ruby source code file and returns this object.
22
- #
23
- # @param [String, File] file The filename or File object for the Ruby source code file to parse.
24
- #
25
- def load_events_file(file)
26
- file = File.open(file) if file.kind_of? String
27
- instance_eval file.read, file.path
28
- self
29
- ensure
30
- file.close
31
- end
32
-
33
- ##
34
- # Parses the given Ruby source code and returns this object.
35
- #
36
- # NOTE: Only use this if you're generating the code yourself! If you're loading a file from the filesystem, you should
37
- # use load_events_file() since load_events_file() will properly attribute errors in the code to the file from which the
38
- # code was loaded.
39
- #
40
- # @param [String] code The Ruby source code to parse
41
- #
42
- def load_events_code(code)
43
- instance_eval code
44
- self
45
- end
46
-
47
- protected
48
-
49
- ##
50
- # Immediately register the namespace and callback with the Theatre instance given to the constructor. This method is only
51
- # called when a new BlankSlateMessageRecorder is instantiated and receives #each().
52
- #
53
- def callback_registered(namespaces, callback)
54
- # Get rid of all arguments passed to the namespaces. Will support arguments in the future.
55
- namespaces = namespaces.map { |namespace| namespace.first }
56
-
57
- theatre.namespace_manager.register_callback_at_namespace namespaces, callback
58
- end
59
-
60
- def create_recorder_method(record_method_name)
61
- (class << self; self; end).send(:alias_method, record_method_name, :anonymous_recorder)
62
- end
63
-
64
- class BlankSlateMessageRecorder
65
-
66
- (instance_methods.map{|m| m.to_sym} - [:instance_eval, :object_id]).each { |method| undef_method method unless method.to_s =~ /^__/ }
67
-
68
- def initialize(&notify_on_completion)
69
- @notify_on_completion = notify_on_completion
70
- @namespaces = []
71
- end
72
-
73
- def method_missing(*method_name_and_args)
74
- raise ArgumentError, "Supplying a block is not supported" if block_given?
75
- @namespaces << method_name_and_args
76
- self
77
- end
78
-
79
- def each(&callback)
80
- @notify_on_completion.call(@namespaces, callback)
81
- end
82
-
83
- end
84
-
85
- end
86
- end
@@ -1,23 +0,0 @@
1
- # Right now Adhearsion also defines this method. The eventual solution will be to extract the Adhearsion features on which
2
- # Theatre depends and make that a dependent library.
3
-
4
- unless respond_to? :new_guid
5
-
6
- def random_character
7
- case random_digit = rand(62)
8
- when 0...10 then random_digit.to_s
9
- when 10...36 then (random_digit + 55).chr
10
- when 36...62 then (random_digit + 61).chr
11
- end
12
- end
13
-
14
- def random_string(length_of_string=8)
15
- Array.new(length_of_string) { random_character }.join
16
- end
17
-
18
- # This GUID implementation doesn't adhere to the RFC which wants to make certain segments based on the MAC address of a
19
- # network interface card and other wackiness. It's sufficiently random for our needs.
20
- def new_guid
21
- [8,4,4,4,12].map { |segment_length| random_string(segment_length) }.join('-')
22
- end
23
- end
@@ -1,131 +0,0 @@
1
- require 'theatre/guid'
2
- require 'thread'
3
- require 'monitor'
4
-
5
- module Theatre
6
-
7
- ##
8
- # An Invocation is an object which Theatre generates and returns from Theatre#trigger.
9
- #
10
- class Invocation
11
-
12
- attr_reader :queued_time, :started_time, :finished_time, :unique_id, :callback, :namespace, :error, :returned_value
13
-
14
- class InvalidStateError < StandardError; end
15
-
16
- ##
17
- # Create a new Invocation.
18
- #
19
- # @param [String] namespace The "/foo/bar/qaz" path to the namespace to which this Invocation belongs.
20
- # @param [Proc] callback The block which should be executed by an Actor scheduler.
21
- # @param [Object] payload The message that will be sent to the callback for processing.
22
- #
23
- def initialize(namespace, callback, payload=:theatre_no_payload)
24
- raise ArgumentError, "Callback must be a Proc" unless callback.kind_of? Proc
25
- @namespace = namespace
26
- @callback = callback
27
- @payload = payload
28
- @unique_id = new_guid.freeze
29
- @current_state = :new
30
- @state_lock = Mutex.new
31
-
32
- # Used just to protect access to the @returned_value instance variable
33
- @returned_value_lock = Monitor.new
34
-
35
- # Used when wait() is called to notify all waiting threads by using a ConditionVariable
36
- @returned_value_blocker = @returned_value_lock.new_cond#Monitor::ConditionVariable.new @returned_value_lock
37
- end
38
-
39
- def queued
40
- with_state_lock do
41
- raise InvalidStateError unless @current_state == :new
42
- @current_state = :queued
43
- @queued_time = Time.now.freeze
44
- end
45
- true
46
- end
47
-
48
- def current_state
49
- with_state_lock { @current_state }
50
- end
51
-
52
- def start
53
- with_state_lock do
54
- raise InvalidStateError unless @current_state == :queued
55
- @current_state = :running
56
- end
57
- @started_time = Time.now.freeze
58
-
59
- begin
60
- self.returned_value = if @payload.equal? :theatre_no_payload
61
- @callback.call
62
- else
63
- @callback.call @payload
64
- end
65
- with_state_lock { @current_state = :success }
66
- rescue => e
67
- if Array(@namespace).first =~ /exception/
68
- # Exception encountered in exception handler. Do not perpetuate the loop.
69
- ahn_log.error "Exception encountered in exception handler!"
70
- ahn_log.error e.message
71
- ahn_log.error e.backtrace.join("\n")
72
- else
73
- Adhearsion::Events.trigger('/exception', e)
74
- end
75
- @error = e
76
- with_state_lock { @current_state = :error }
77
- ensure
78
- @finished_time = Time.now.freeze
79
- end
80
- end
81
-
82
- def execution_duration
83
- return nil unless @finished_time
84
- @finished_time - @started_time
85
- end
86
-
87
- def error?
88
- current_state.equal? :error
89
- end
90
-
91
- def success?
92
- current_state.equal? :success
93
- end
94
-
95
- ##
96
- # When this Invocation has been queued, started, and entered either the :success or :error state, this method will
97
- # finally return. Until then, it blocks the Thread.
98
- #
99
- # @return [Object] The result of invoking this Invocation's callback
100
- #
101
- def wait
102
- with_returned_value_lock { return @returned_value if defined? @returned_value }
103
- @returned_value_blocker.wait
104
- # Return the returned_value
105
- with_returned_value_lock { @returned_value }
106
- end
107
-
108
- protected
109
-
110
- ##
111
- # Protected setter which does some other housework when the returned value is found (such as notifying wait()ers)
112
- #
113
- # @param [returned_value] The value to set this returned value to.
114
- #
115
- def returned_value=(returned_value)
116
- with_returned_value_lock do
117
- @returned_value = returned_value
118
- @returned_value_blocker.broadcast
119
- end
120
- end
121
-
122
- def with_returned_value_lock(&block)
123
- @returned_value_lock.synchronize(&block)
124
- end
125
-
126
- def with_state_lock(&block)
127
- @state_lock.synchronize(&block)
128
- end
129
-
130
- end
131
- end
@@ -1,153 +0,0 @@
1
- module Theatre
2
-
3
- ##
4
- # Manages the hierarchial namespaces of a Theatre. This class is Thread-safe.
5
- #
6
- class ActorNamespaceManager
7
-
8
- VALID_NAMESPACE = %r{^(/[\w_]+)+$}
9
-
10
- class << self
11
- def valid_namespace_path?(namespace_path)
12
- namespace_path =~ VALID_NAMESPACE
13
- end
14
-
15
- ##
16
- # Since there are a couple ways to represent namespaces, this is a helper method which will normalize
17
- # them into the most practical: an Array of Symbols
18
- # @param [String, Array] paths The namespace to register. Can be in "/foo/bar" or *[foo,bar] format
19
- def normalize_path_to_array(paths)
20
- paths = paths.is_a?(Array) ? paths.flatten : Array(paths)
21
- paths.map! { |path_segment| path_segment.kind_of?(String) ? path_segment.split('/') : path_segment }
22
- paths.flatten!
23
- paths.reject! { |path| path.nil? || (path.kind_of?(String) && path.empty?) }
24
- paths.map { |path| path.to_sym }
25
- end
26
-
27
- end
28
-
29
- def initialize
30
- @registry_lock = Mutex.new
31
- @root = RootNamespaceNode.new
32
- end
33
-
34
- ##
35
- # Have this registry recognize a new path and prepare it for callback registrations. All path segements will be created
36
- # in order. For example, when registering "/foo/bar/qaz" when no namespaces at all have been registered, this method will
37
- # first register "foo", then "bar", then "qaz". If the namespace was already registered, it will not be affected.
38
- #
39
- # @param [String, Array] paths The namespace to register. Can be in "/foo/bar" or *[foo,bar] format
40
- # @return [NamespaceNode] The NamespaceNode representing the path given.
41
- # @raise NamespaceNotFound if a segment has not been registered yet
42
- #
43
- def register_namespace_name(*paths)
44
- paths = self.class.normalize_path_to_array paths
45
-
46
- paths.inject(@root) do |node, name|
47
- node.register_namespace_name name
48
- end
49
- end
50
-
51
- ##
52
- # Returns a Proc found after searching with the namespace you provide
53
- #
54
- # @raise NamespaceNotFound if a segment has not been registered yet
55
- #
56
- def callbacks_for_namespaces(*paths)
57
- search_for_namespace(paths).callbacks
58
- end
59
-
60
- ##
61
- # Find a namespace in the tree.
62
- #
63
- # @param [Array, String] paths Must be an Array of segments or a name like "/foo/bar/qaz"
64
- # @raise NamespaceNotFound if a segment has not been registered yet
65
- #
66
- def search_for_namespace(paths)
67
- paths = self.class.normalize_path_to_array paths
68
- path_string = "/"
69
-
70
- found_namespace = paths.inject(@root) do |last_node,this_node_name|
71
- raise NamespaceNotFound.new(path_string) if last_node.nil?
72
- path_string << this_node_name.to_s
73
- last_node.child_named this_node_name
74
- end
75
- raise NamespaceNotFound.new("/#{paths.join('/')}") unless found_namespace
76
- found_namespace
77
- end
78
-
79
- ##
80
- # Registers the given callback at a namespace, assuming the namespace was already registered.
81
- #
82
- # @param [Array] paths Must be an Array of segments
83
- # @param [Proc] callback
84
- # @raise NamespaceNotFound if a segment has not been registered yet
85
- #
86
- def register_callback_at_namespace(paths, callback)
87
- raise ArgumentError, "callback must be a Proc" unless callback.kind_of? Proc
88
- search_for_namespace(paths).register_callback callback
89
- end
90
-
91
- protected
92
-
93
- ##
94
- # Used by NamespaceManager to build a tree of namespaces. Has a Hash of children which is not
95
- # Thread-safe. For Thread-safety, all access should semaphore through the NamespaceManager.
96
- class NamespaceNode
97
-
98
- attr_reader :name
99
- def initialize(name)
100
- @name = name.freeze
101
- @children = {}
102
- @callbacks = []
103
- end
104
-
105
- def register_namespace_name(name)
106
- @children[name] ||= NamespaceNode.new(name)
107
- end
108
-
109
- def register_callback(callback)
110
- @callbacks << callback
111
- callback
112
- end
113
-
114
- def callbacks
115
- @callbacks.clone
116
- end
117
-
118
- def delete_callback(callback)
119
- @callbacks.delete callback
120
- end
121
-
122
- def child_named(name)
123
- @children[name]
124
- end
125
-
126
- def destroy_namespace(name)
127
- @children.delete name
128
- end
129
-
130
- def root?
131
- false
132
- end
133
-
134
- end
135
-
136
- class RootNamespaceNode < NamespaceNode
137
- def initialize
138
- super :ROOT
139
- end
140
- def root?
141
- true
142
- end
143
- end
144
-
145
- end
146
-
147
- class NamespaceNotFound < StandardError
148
- def initialize(full_path)
149
- super "Could not find #{full_path.inspect} in the namespace registry. Did you register it yet?"
150
- end
151
- end
152
-
153
- end
@@ -1,2 +0,0 @@
1
- THEATRE_VERSION_MAJOR, THEATRE_VERSION_MINOR, THEATRE_VERSION_REVISION = THEATRE_VERSION = [0,8,1]
2
- THEATRE_VERSION_STRING = THEATRE_VERSION.join '.'
@@ -1,306 +0,0 @@
1
- require 'spec_helper'
2
- require 'adhearsion/cli'
3
-
4
- module AhnCommandSpecHelper
5
-
6
- def simulate_args(*args)
7
- ARGV.clear
8
- ARGV.concat args
9
- end
10
-
11
- def capture_stdout(&block)
12
- old = $stdout
13
- $stdout = io = StringIO.new
14
- yield
15
- ensure
16
- $stdout = old
17
- return io.string
18
- end
19
-
20
- def new_tmp_dir(filename=new_guid)
21
- File.join Dir.tmpdir, filename
22
- end
23
-
24
- def create_component_sandbox
25
- new_tmp_dir.tap do |dir|
26
- Dir.mkdir dir
27
- FileUtils.touch dir + "/.ahnrc"
28
- Dir.mkdir dir + "/components"
29
- end
30
- end
31
-
32
- def execute_ahn_command
33
- Adhearsion::CLI::AhnCommand.execute!
34
- end
35
-
36
- def executing_ahn_command_should_fail_with(exception)
37
- flexmock(Adhearsion::CLI::AhnCommand).should_receive(:fail_and_print_usage).with(exception).once
38
- execute_ahn_command
39
- end
40
-
41
- end
42
-
43
- describe 'The Ahn Command helper' do
44
-
45
- include AhnCommandSpecHelper
46
-
47
- it "args are simulated properly" do
48
- before = ARGV.clone
49
- simulate_args "create", "/tmp/blah"
50
- ARGV.should_not be before
51
- end
52
-
53
- it "STDOUT should be captured" do
54
- capture_stdout do
55
- puts "wee"
56
- end.should == "wee\n"
57
- end
58
-
59
- end
60
-
61
- describe "A simulated use of the 'ahn' command" do
62
-
63
- include AhnCommandSpecHelper
64
-
65
- it "USAGE is defined" do
66
- Adhearsion::CLI::AhnCommand.const_defined?('USAGE').should be true
67
- end
68
-
69
- before do
70
- flexmock Adhearsion::ScriptAhnLoader, :in_ahn_application? => true
71
- end
72
-
73
- it "arguments to 'create' are executed properly" do
74
- some_path = "/path/somewhere"
75
- simulate_args "create", some_path
76
- flexmock(Adhearsion::CLI::AhnCommand::CommandHandler).should_receive(:create).once.with(some_path)
77
- capture_stdout { Adhearsion::CLI::AhnCommand.execute! }
78
- end
79
-
80
- it "arguments to 'start' are executed properly properly" do
81
- some_path = "/tmp/blargh"
82
- simulate_args "start", some_path
83
- flexmock(Adhearsion::CLI::AhnCommand::CommandHandler).should_receive(:start).once.with(some_path, :foreground, nil)
84
- Adhearsion::CLI::AhnCommand.execute!
85
- end
86
-
87
- it "should execute arguments to 'start' for daemonizing properly" do
88
- somewhere = "/tmp/blarghh"
89
- simulate_args "start", 'daemon', somewhere
90
- flexmock(Adhearsion::CLI::AhnCommand::CommandHandler).should_receive(:start).once.with(somewhere, :daemon, nil)
91
- Adhearsion::CLI::AhnCommand.execute!
92
- end
93
-
94
- it "should execute arguments to 'start' for using a console properly" do
95
- somewhere = "/tmp/blarghh"
96
- simulate_args "start", 'console', somewhere
97
- flexmock(Adhearsion::CLI::AhnCommand::CommandHandler).should_receive(:start).once.with(somewhere, :console, nil)
98
- Adhearsion::CLI::AhnCommand.execute!
99
- end
100
-
101
- it 'parse_arguments should recognize start with daemon properly' do
102
- path = '/path/to/somesuch'
103
- arguments = ['start', 'daemon', path]
104
- Adhearsion::CLI::AhnCommand.parse_arguments(arguments).should == [:start, path, :daemon, nil]
105
- end
106
-
107
- it 'should not allow both daemon and console to be specified' do
108
- path = '/path/to/somesuch'
109
- arguments = ['start', 'daemon', 'console', path]
110
- lambda { Adhearsion::CLI::AhnCommand.parse_arguments(arguments) }.should raise_error Adhearsion::CLI::AhnCommand::CommandHandler::CLIException
111
- end
112
-
113
- it 'should recognize start with daemon and pid file properly' do
114
- project_path = '/second/star/on/the/right'
115
- pid_file_path = '/straight/on/til/morning'
116
- arguments = ["start", "daemon", project_path, "--pid-file=#{pid_file_path}"]
117
- Adhearsion::CLI::AhnCommand.parse_arguments(arguments).should == [:start, project_path, :daemon, pid_file_path]
118
- end
119
-
120
- it 'should recognize start without daemon and with pid file properly' do
121
- project_path = '/second/star/on/the/right'
122
- pid_file_path = '/straight/on/til/morning'
123
- arguments = ["start", project_path, "--pid-file=#{pid_file_path}"]
124
- Adhearsion::CLI::AhnCommand.parse_arguments(arguments).should == [:start, project_path, :foreground, pid_file_path]
125
- end
126
-
127
- it 'parse_arguments should recognize start without daemon properly' do
128
- path = '/path/to/somewhere'
129
- arguments = ['start', path]
130
- Adhearsion::CLI::AhnCommand.parse_arguments(arguments).should == [:start, path, :foreground, nil]
131
- end
132
-
133
- it "if no path is provided, running Ahn command blows up" do
134
- lambda { Adhearsion::CLI::AhnCommand.parse_arguments(['start']) }.should raise_error Adhearsion::CLI::AhnCommand::CommandHandler::CLIException
135
- end
136
-
137
- it "printing the version" do
138
- capture_stdout do
139
- simulate_args 'version'
140
- Adhearsion::CLI::AhnCommand.execute!
141
- end.should =~ Regexp.new(Regexp.escape(Adhearsion::VERSION::STRING))
142
- end
143
-
144
- it "printing the help" do
145
- capture_stdout do
146
- simulate_args 'help'
147
- Adhearsion::CLI::AhnCommand.execute!
148
- end.should =~ Regexp.new(Regexp.escape(Adhearsion::CLI::AhnCommand::USAGE))
149
- end
150
-
151
- it "reacting to unrecognized commands" do
152
- simulate_args "alpha", "beta"
153
- flexmock(Adhearsion::CLI::AhnCommand).should_receive(:fail_and_print_usage).once.and_return
154
- Adhearsion::CLI::AhnCommand.execute!
155
- end
156
-
157
- it "giving a path that doesn't contain a project raises an exception" do
158
- simulate_args "start", "/asjdfas/sndjfabsdfbqwb/qnjwejqbwh"
159
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::PathInvalid
160
- end
161
-
162
- end
163
-
164
- describe "Component-related commands" do
165
-
166
- include AhnCommandSpecHelper
167
-
168
-
169
- it "should move a folder from the components/disabled/ folder of an app to the components/ directory if it exists" do
170
- sandbox = create_component_sandbox
171
- disabled_dir = "#{sandbox}/components/disabled/foobar"
172
- enabled_dir = "#{sandbox}/components/foobar"
173
-
174
- FileUtils.mkdir_p disabled_dir
175
- FileUtils.touch disabled_dir + "/foobar.rb"
176
-
177
- flexmock(Dir).should_receive(:pwd).once.and_return disabled_dir
178
-
179
- simulate_args "enable", "component", "foobar"
180
- capture_stdout { execute_ahn_command }
181
-
182
- File.directory?(disabled_dir).should_not be true
183
- File.exists?(enabled_dir + "/foobar.rb").should be true
184
- end
185
-
186
- it "should raise a ComponentError exception if there is no disabled folder" do
187
- sandbox = create_component_sandbox
188
-
189
- flexmock(Dir).should_receive(:pwd).once.and_return sandbox
190
-
191
- simulate_args "enable", "component", "foo"
192
-
193
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::ComponentError
194
- end
195
-
196
- it "should raise an exception if the disabled component exists and there's an enabled component of the same name" do
197
- sandbox = create_component_sandbox
198
-
199
- flexmock(Dir).should_receive(:pwd).once.and_return sandbox
200
-
201
- FileUtils.mkdir_p sandbox + "/disabled/lolcats"
202
- FileUtils.mkdir_p sandbox + "/lolcats"
203
-
204
- simulate_args "enable", "component", "foo"
205
-
206
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::ComponentError
207
- end
208
-
209
- it "should raise a PathInvalid error if the current directory does not belong to an Adhearsion app" do
210
- flexmock(Dir).should_receive("pwd").and_return "/"
211
- simulate_args "enable", "component", "foo"
212
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::PathInvalid
213
- end
214
-
215
- it "should properly create the disabled folder if it doesn't exist when disabling a component" do
216
- sandbox = create_component_sandbox
217
- flexmock(Dir).should_receive(:pwd).once.and_return sandbox
218
-
219
- FileUtils.mkdir_p sandbox + "/components/rickroller"
220
-
221
- simulate_args 'disable', 'component', 'rickroller'
222
- capture_stdout { execute_ahn_command }
223
- File.directory?(sandbox + "/components/disabled/rickroller").should be true
224
- File.directory?(sandbox + "/components/rickroller").should be false
225
- end
226
-
227
- it "should raise an UnknownCommand error when trying to enable a kind of feature which doesn't exist" do
228
- simulate_args "enable", "bonobo"
229
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::UnknownCommand
230
- end
231
-
232
- it "should raise an UnknownCommand error when trying to disable a kind of feature which doesn't exist" do
233
- simulate_args "disable", "thanksgiving_dinner"
234
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::UnknownCommand
235
- end
236
-
237
- it "should raise a ComponentError when the component to disable doesn't exist" do
238
- sandbox = create_component_sandbox
239
- flexmock(Dir).should_receive(:pwd).once.and_return sandbox
240
-
241
- simulate_args "disable", "component", "monkeybars"
242
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::ComponentError
243
- end
244
-
245
- it "should raise an exception when disabling a component and the component's disabled directory already exists" do
246
- sandbox = create_component_sandbox
247
-
248
- flexmock(Dir).should_receive(:pwd).once.and_return sandbox
249
-
250
- FileUtils.mkdir_p sandbox + "/disabled/lolcats"
251
- FileUtils.mkdir_p sandbox + "/lolcats"
252
-
253
- simulate_args "disable", "component", "foo"
254
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::ComponentError
255
- end
256
-
257
- end
258
-
259
- describe 'The "create" command' do
260
-
261
- include AhnCommandSpecHelper
262
-
263
- it "creating a project" do
264
- the_following_code {
265
- tmp_path = new_tmp_dir
266
- simulate_args "create", tmp_path
267
- # capture_stdout { Adhearsion::CLI::AhnCommand.execute! }
268
- execute_ahn_command
269
- File.exists?(File.join(tmp_path, ".ahnrc")).should be true
270
- }.should_not raise_error
271
- end
272
-
273
- it "should raise an UnknownCommand if running create with no arguments" do
274
- simulate_args "create"
275
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::UnknownCommand
276
- end
277
-
278
- it "should raise a ComponentError if the name of the component is not a valid Ruby symbol name" do
279
- bad_names = ["!))", "37signals", "foo bar", "*"]
280
- bad_names.each do |bad_name|
281
- simulate_args "create", "component", bad_name
282
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::ComponentError
283
- end
284
- end
285
-
286
- it "should raise a ComponentError if the component name already exists in the folder" do
287
- sandbox = create_component_sandbox
288
- Dir.mkdir sandbox + "/components/blehhh"
289
- flexmock(Dir).should_receive(:pwd).once.and_return sandbox
290
- simulate_args "create", "component", "blehhh"
291
-
292
- executing_ahn_command_should_fail_with Adhearsion::CLI::AhnCommand::CommandHandler::ComponentError
293
- end
294
-
295
- it "should create a folder with matching .rb file and .yml file when all guards pass" do
296
- sandbox = create_component_sandbox
297
- flexmock(Dir).should_receive(:pwd).once.and_return sandbox
298
-
299
- simulate_args "create", "component", "ohai"
300
- capture_stdout { execute_ahn_command }
301
-
302
- File.exists?(sandbox + "/components/ohai/lib/ohai.rb").should be true
303
- File.exists?(sandbox + "/components/ohai/config/ohai.yml").should be true
304
- end
305
-
306
- end