adhearsion 1.2.6 → 2.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
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