eric-adhearsion 0.7.999 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/CHANGELOG +8 -2
  2. data/EVENTS +11 -0
  3. data/Rakefile +96 -24
  4. data/adhearsion.gemspec +148 -0
  5. data/app_generators/ahn/ahn_generator.rb +24 -9
  6. data/app_generators/ahn/templates/.ahnrc +25 -3
  7. data/app_generators/ahn/templates/Rakefile +22 -2
  8. data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
  9. data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
  10. data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
  11. data/app_generators/ahn/templates/components/disabled/stomp_gateway/config.yml +12 -0
  12. data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
  13. data/app_generators/ahn/templates/components/simon_game/{lib/simon_game.rb → simon_game.rb} +14 -19
  14. data/app_generators/ahn/templates/config/startup.rb +3 -6
  15. data/app_generators/ahn/templates/dialplan.rb +2 -3
  16. data/app_generators/ahn/templates/events.rb +32 -0
  17. data/bin/jahn +10 -0
  18. data/examples/asterisk_manager_interface/standalone.rb +51 -0
  19. data/lib/adhearsion.rb +17 -11
  20. data/lib/adhearsion/cli.rb +141 -24
  21. data/lib/adhearsion/component_manager.rb +169 -238
  22. data/lib/adhearsion/component_manager/component_tester.rb +55 -0
  23. data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
  24. data/lib/adhearsion/events_support.rb +84 -0
  25. data/lib/adhearsion/{core_extensions → foundation}/all.rb +0 -0
  26. data/lib/adhearsion/{blank_slate.rb → foundation/blank_slate.rb} +0 -0
  27. data/lib/adhearsion/{core_extensions → foundation}/custom_daemonizer.rb +0 -0
  28. data/lib/adhearsion/foundation/event_socket.rb +203 -0
  29. data/lib/adhearsion/foundation/future_resource.rb +36 -0
  30. data/lib/adhearsion/{core_extensions → foundation}/global.rb +0 -0
  31. data/lib/adhearsion/{core_extensions → foundation}/metaprogramming.rb +0 -0
  32. data/lib/adhearsion/foundation/numeric.rb +13 -0
  33. data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
  34. data/lib/adhearsion/{core_extensions → foundation}/relationship_properties.rb +2 -0
  35. data/lib/adhearsion/foundation/string.rb +26 -0
  36. data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
  37. data/lib/adhearsion/{core_extensions → foundation}/thread_safety.rb +0 -0
  38. data/lib/adhearsion/host_definitions.rb +5 -1
  39. data/lib/adhearsion/initializer.rb +229 -73
  40. data/lib/adhearsion/initializer/asterisk.rb +33 -11
  41. data/lib/adhearsion/initializer/configuration.rb +58 -6
  42. data/lib/adhearsion/initializer/database.rb +3 -46
  43. data/lib/adhearsion/initializer/drb.rb +9 -3
  44. data/lib/adhearsion/initializer/freeswitch.rb +3 -3
  45. data/lib/adhearsion/initializer/rails.rb +1 -1
  46. data/lib/adhearsion/tasks.rb +2 -1
  47. data/lib/adhearsion/tasks/deprecations.rb +59 -0
  48. data/lib/adhearsion/version.rb +3 -3
  49. data/lib/adhearsion/voip/asterisk.rb +2 -2
  50. data/lib/adhearsion/voip/asterisk/agi_server.rb +9 -6
  51. data/lib/adhearsion/voip/asterisk/commands.rb +106 -4
  52. data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
  53. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
  54. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
  55. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
  56. data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
  57. data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
  58. data/lib/adhearsion/voip/call.rb +51 -2
  59. data/lib/adhearsion/voip/dial_plan.rb +74 -61
  60. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
  61. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +2 -6
  62. data/lib/adhearsion/voip/dsl/numerical_string.rb +2 -2
  63. data/lib/adhearsion/voip/freeswitch/oes_server.rb +2 -2
  64. data/lib/theatre.rb +151 -0
  65. data/lib/theatre/README.markdown +64 -0
  66. data/lib/theatre/callback_definition_loader.rb +84 -0
  67. data/lib/theatre/guid.rb +23 -0
  68. data/lib/theatre/invocation.rb +121 -0
  69. data/lib/theatre/namespace_manager.rb +153 -0
  70. data/lib/theatre/version.rb +2 -0
  71. metadata +63 -138
  72. data/Manifest.txt +0 -149
  73. data/README.txt +0 -6
  74. data/ahn_generators/component/USAGE +0 -5
  75. data/ahn_generators/component/component_generator.rb +0 -57
  76. data/ahn_generators/component/templates/configuration.rb +0 -0
  77. data/ahn_generators/component/templates/lib/lib.rb.erb +0 -3
  78. data/ahn_generators/component/templates/test/test.rb.erb +0 -12
  79. data/ahn_generators/component/templates/test/test_helper.rb +0 -14
  80. data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
  81. data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +0 -14
  82. data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +0 -31
  83. data/lib/adhearsion/core_extensions/array.rb +0 -0
  84. data/lib/adhearsion/core_extensions/guid.rb +0 -5
  85. data/lib/adhearsion/core_extensions/hash.rb +0 -0
  86. data/lib/adhearsion/core_extensions/numeric.rb +0 -4
  87. data/lib/adhearsion/core_extensions/proc.rb +0 -0
  88. data/lib/adhearsion/core_extensions/pseudo_uuid.rb +0 -11
  89. data/lib/adhearsion/core_extensions/publishable.rb +0 -73
  90. data/lib/adhearsion/core_extensions/string.rb +0 -26
  91. data/lib/adhearsion/core_extensions/thread.rb +0 -13
  92. data/lib/adhearsion/core_extensions/time.rb +0 -0
  93. data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
  94. data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
  95. data/lib/adhearsion/distributed/gateways/rest_gateway.rb +0 -9
  96. data/lib/adhearsion/distributed/gateways/soap_gateway.rb +0 -9
  97. data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +0 -9
  98. data/lib/adhearsion/distributed/peer_finder.rb +0 -0
  99. data/lib/adhearsion/distributed/remote_cli.rb +0 -0
  100. data/lib/adhearsion/hooks.rb +0 -57
  101. data/lib/adhearsion/initializer/paths.rb +0 -55
  102. data/lib/adhearsion/services/scheduler.rb +0 -5
  103. data/lib/adhearsion/voip/asterisk/ami.rb +0 -147
  104. data/lib/adhearsion/voip/asterisk/ami/actions.rb +0 -238
  105. data/lib/adhearsion/voip/asterisk/ami/machine.rb +0 -871
  106. data/lib/adhearsion/voip/asterisk/ami/machine.rl +0 -109
  107. data/lib/adhearsion/voip/asterisk/ami/parser.rb +0 -262
  108. data/script/destroy +0 -14
  109. data/script/generate +0 -14
  110. data/spec/fixtures/dialplan.rb +0 -3
  111. data/spec/initializer/test_configuration.rb +0 -267
  112. data/spec/initializer/test_loading.rb +0 -162
  113. data/spec/initializer/test_paths.rb +0 -43
  114. data/spec/silence.rb +0 -10
  115. data/spec/test_ahn_command.rb +0 -149
  116. data/spec/test_code_quality.rb +0 -87
  117. data/spec/test_component_manager.rb +0 -97
  118. data/spec/test_constants.rb +0 -8
  119. data/spec/test_drb.rb +0 -104
  120. data/spec/test_helper.rb +0 -94
  121. data/spec/test_hooks.rb +0 -37
  122. data/spec/test_host_definitions.rb +0 -79
  123. data/spec/test_initialization.rb +0 -105
  124. data/spec/test_logging.rb +0 -80
  125. data/spec/test_relationship_properties.rb +0 -54
  126. data/spec/voip/asterisk/ami_response_definitions.rb +0 -23
  127. data/spec/voip/asterisk/config_file_generators/test_agents.rb +0 -253
  128. data/spec/voip/asterisk/config_file_generators/test_queues.rb +0 -325
  129. data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +0 -306
  130. data/spec/voip/asterisk/menu_command/test_calculated_match.rb +0 -111
  131. data/spec/voip/asterisk/menu_command/test_matchers.rb +0 -98
  132. data/spec/voip/asterisk/mock_ami_server.rb +0 -176
  133. data/spec/voip/asterisk/test_agi_server.rb +0 -451
  134. data/spec/voip/asterisk/test_ami.rb +0 -227
  135. data/spec/voip/asterisk/test_commands.rb +0 -2006
  136. data/spec/voip/asterisk/test_config_manager.rb +0 -129
  137. data/spec/voip/dsl/dispatcher_spec_helper.rb +0 -45
  138. data/spec/voip/dsl/test_dialing_dsl.rb +0 -268
  139. data/spec/voip/dsl/test_dispatcher.rb +0 -82
  140. data/spec/voip/dsl/test_parser.rb +0 -87
  141. data/spec/voip/freeswitch/test_basic_connection_manager.rb +0 -39
  142. data/spec/voip/freeswitch/test_inbound_connection_manager.rb +0 -39
  143. data/spec/voip/freeswitch/test_oes_server.rb +0 -9
  144. data/spec/voip/test_call_routing.rb +0 -127
  145. data/spec/voip/test_dialplan_manager.rb +0 -372
  146. data/spec/voip/test_numerical_string.rb +0 -48
  147. data/spec/voip/test_phone_number.rb +0 -36
  148. data/test/test_ahn_generator.rb +0 -59
  149. data/test/test_component_generator.rb +0 -52
  150. data/test/test_generator_helper.rb +0 -20
@@ -1,277 +1,208 @@
1
1
  module Adhearsion
2
-
3
2
  module Components
4
- class Manager
5
- attr_reader :active_components, :host_information, :started_components, :components_with_call_context
6
- def initialize
7
- @active_components = {}
8
- @started_components = []
9
- @components_with_call_context = {}
10
- end
11
-
12
- def [](component_name)
13
- active_components[component_name].component_class.instance
14
- end
15
3
 
16
- def component(component_name)
17
- active_components[component_name]
18
- end
19
-
20
- def has_component?(component_name)
21
- active_components.has_key?(component_name)
22
- end
23
-
24
- def component_gems
25
- @repository ||= RubygemsRepository.new
26
- @repository.adhearsion_gems
27
- end
4
+ mattr_accessor :component_manager
28
5
 
29
- def load
30
- return unless File.exist?(AHN_ROOT.component_path)
31
- component_directories = Dir.glob(File.join(AHN_ROOT.component_path, "*"))
32
- component_directories.each do |component_directory|
33
- component_name = File.basename(component_directory).to_sym
34
- @active_components[component_name] = Component.new(self, component_name, component_directory)
35
- end
36
- end
6
+ class ConfigurationError < Exception; end
37
7
 
38
- def start
39
- @active_components.keys.each do |name|
40
- @active_components[name].start
41
- end
42
- end
43
-
44
- def stop
45
- @started_components.reverse.each do |name|
46
- @active_components[name].stop
8
+ class ComponentManager
9
+
10
+ class << self
11
+
12
+ def scopes_valid?(*scopes)
13
+ unrecognized_scopes = (scopes.flatten - SCOPE_NAMES).map(&:inspect)
14
+ raise ArgumentError, "Unrecognized scopes #{unrecognized_scopes.to_sentence}" if unrecognized_scopes.any?
15
+ true
47
16
  end
17
+
48
18
  end
49
-
50
- class RubygemsRepository
51
- def initialize
52
- require 'rubygems'
53
- Gem.manage_gems
54
- end
55
-
56
- def adhearsion_gems
57
- gems = {}
58
- Gem.source_index.each {|name, spec| gems[spec.name] = spec.full_gem_path if spec.requirements.include?("adhearsion")}
59
- gems
19
+
20
+ SCOPE_NAMES = [:dialplan, :events, :generators, :rpc, :global]
21
+ DEFAULT_CONFIG_NAME = "config.yml"
22
+
23
+ attr_reader :scopes, :lazy_config_loader
24
+ def initialize(path_to_container_directory)
25
+ @path_to_container_directory = path_to_container_directory
26
+ @scopes = SCOPE_NAMES.inject({}) do |scopes, name|
27
+ scopes[name] = Module.new
28
+ scopes
60
29
  end
61
- end
62
- end
63
-
64
- ClassToGetCallContext = Struct.new(:component_class, :instance_variable)
65
- class ClassToGetCallContext
66
- def instantiate_with_call_context(call_context, *args, &block)
67
- component = component_class.allocate
68
- component.instance_variable_set(("@"+instance_variable.to_s).to_sym, call_context)
69
- component.send(:initialize, *args, &block)
70
- component
71
- end
72
- end
73
-
74
-
75
- #component behavior is shared across components
76
- module Behavior
77
- def self.included(component_class)
78
- component_class.extend(ClassMethods)
30
+ @lazy_config_loader = LazyConfigLoader.new(self)
79
31
  end
80
32
 
81
- def component_name
82
- Component.name
83
- end
84
-
85
- def component_description
86
- Configuration.description || Component.name
33
+ ##
34
+ # Includes the anonymous Module created for the :global scope in Object, making its methods globally accessible.
35
+ #
36
+ def globalize_global_scope!
37
+ Object.send :include, @scopes[:global]
87
38
  end
88
39
 
89
- module ClassMethods
90
- def add_call_context(params = {:as => :call_context})
91
- attr_reader params[:as]
92
- ComponentManager.components_with_call_context[name] = ClassToGetCallContext.new(self, params[:as])
40
+ def load_components
41
+ components = Dir.glob(File.join(@path_to_container_directory + "/*")).select do |path|
42
+ File.directory?(path)
93
43
  end
94
- end
95
- end
96
-
97
- class Component
98
- class << self
99
- def prepare_component_class(component_module, name)
100
- component_class_name = name.to_s.camelize
101
- component_module.module_eval(<<-EVAL, __FILE__, __LINE__)
102
- class #{component_class_name}
103
- def self.name
104
- '#{component_class_name}'
105
- end
106
- include Adhearsion::Components::Behavior
107
- end
108
- EVAL
44
+ components.map! { |path| File.basename path }
45
+ components.each do |component|
46
+ next if component == "disabled"
47
+ component_file = File.join(@path_to_container_directory, component, component + ".rb")
48
+ if File.exists? component_file
49
+ load_file component_file
50
+ else
51
+ ahn_log.warn "Component directory does not contain a matching .rb file! Was expecting #{component_file.inspect}"
52
+ end
109
53
  end
110
- end
111
54
 
112
- attr_reader :manager, :name, :path, :component_module, :component_class
113
- def initialize(manager, name, path)
114
- @manager = manager
115
- @name = name
116
- @path = path
117
- unless File.exist?(main_file_name)
118
- gem_path = @manager.component_gems[@name.to_s]
119
- raise "The component '#{@name}' does not have the main file: #{main_file_name}" unless gem_path
120
- @path = gem_path
121
- end
122
- @started = false
123
55
  end
124
56
 
125
- def start
126
- return if @started
127
- manager.started_components << @name
128
- @started = true
129
- @component_module = ComponentModule.new(self) do |component_module|
130
- Component.prepare_component_class(component_module, @name)
131
- component_module.load_configuration_file
57
+ ##
58
+ # Loads the configuration file for a given component name.
59
+ #
60
+ # @return [Hash] The loaded YAML for the given component name. An empty Hash if no YAML file exists.
61
+ #
62
+ def configuration_for_component_named(component_name)
63
+ component_dir = File.join(@path_to_container_directory, component_name)
64
+ config_file = File.join component_dir, DEFAULT_CONFIG_NAME
65
+ if File.exists?(config_file)
66
+ YAML.load_file config_file
67
+ else
68
+ return {}
132
69
  end
133
- @component_module.require(File.join("lib", @name.to_s))
134
70
  end
135
71
 
136
- def configuration
137
- @component_module.const_get(:Configuration)
72
+ def extend_object_with(object, *scopes)
73
+ raise ArgumentError, "Must supply at least one scope!" if scopes.empty?
74
+
75
+ self.class.scopes_valid? scopes
76
+
77
+ scopes.each do |scope|
78
+ methods = @scopes[scope]
79
+ if object.kind_of?(Module)
80
+ object.send :include, methods
81
+ else
82
+ object.extend methods
83
+ end
84
+ end
85
+ object
138
86
  end
139
-
140
- def stop
141
- #@component_class.unload if @component_class && @component_class.respond_to?(:unload)
87
+
88
+ def load_code(code)
89
+ load_container ComponentDefinitionContainer.load_code(code)
142
90
  end
143
-
144
- def configuration_file
145
- File.join(path, configuration_file_name)
91
+
92
+ def load_file(filename)
93
+ load_container ComponentDefinitionContainer.load_file(filename)
146
94
  end
147
95
 
148
- private
96
+ protected
149
97
 
150
- def main_file_name
151
- File.join(@path, "lib", @name.to_s+".rb")
98
+ def load_container(container)
99
+ container.constants.each do |constant_name|
100
+ constant_value = container.const_get(constant_name)
101
+ Object.const_set(constant_name, constant_value)
152
102
  end
153
-
154
- def configuration_file_name
155
- "configuration.rb"
103
+ metadata = container.metaclass.send(:instance_variable_get, :@metadata)
104
+ metadata[:initialization_block].call if metadata[:initialization_block]
105
+
106
+ self.class.scopes_valid? metadata[:scopes].keys
107
+
108
+ metadata[:scopes].each_pair do |scope, method_definition_blocks|
109
+ method_definition_blocks.each do |method_definition_block|
110
+ @scopes[scope].module_eval(&method_definition_block)
111
+ end
156
112
  end
157
- end
158
-
159
- class ComponentModule < Module
160
- # The file with which the Script was instantiated.
161
- attr_reader :main_file
162
-
163
- # The directory in which main_file is located, and relative to which
164
- # #load searches for files before falling back to Kernel#load.
165
- attr_reader :dir
166
-
167
- # A hash that maps <tt>filename=>true</tt> for each file that has been
168
- # required locally by the script. This has the same semantics as <tt>$"</tt>,
169
- # alias <tt>$LOADED_FEATURES</tt>, except that it is local to this script.
170
- attr_reader :loaded_features
171
-
172
- class << self
173
- alias load new
174
- end
175
-
176
- # Creates new Script, and loads _main_file_ in the scope of the Script. If a
177
- # block is given, the script is passed to it before loading from the file, and
178
- # constants can be defined as inputs to the script.
179
- attr_reader :component
180
- def initialize(component) # :yields: self
181
- extend ComponentModuleMethods
182
- @component = component
183
- @loaded_features = {}
184
-
185
- const_set :Component, component
186
- const_set :Configuration, OpenStruct.new(:description => nil)
187
-
188
- yield self if block_given?
189
- end
190
-
191
- def load_configuration_file
192
- load_in_module(component.configuration_file)
193
- end
194
-
195
- # Loads _file_ into this Script. Searches relative to the local dir, that is,
196
- # the dir of the file given in the original call to
197
- # <tt>Script.load(file)</tt>, loads the file, if found, into this Script's
198
- # scope, and returns true. If the file is not found, falls back to
199
- # <tt>Kernel.load</tt>, which searches on <tt>$LOAD_PATH</tt>, loads the file,
200
- # if found, into global scope, and returns true. Otherwise, raises
201
- # <tt>LoadError</tt>.
202
- #
203
- # The _wrap_ argument is passed to <tt>Kernel.load</tt> in the fallback case,
204
- # when the file is not found locally.
205
- #
206
- # Typically called from within the main file to load additional sub files, or
207
- # from those sub files.
208
-
209
- def load(file, wrap = false)
210
- load_in_module(File.join(component.path, file))
211
- true
212
- rescue MissingFile
213
- super
113
+ container
214
114
  end
215
115
 
216
- # Analogous to <tt>Kernel#require</tt>. First tries the local dir, then falls
217
- # back to <tt>Kernel#require</tt>. Will load a given _feature_ only once.
218
- #
219
- # Note that extensions (*.so, *.dll) can be required in the global scope, as
220
- # usual, but not in the local scope. (This is not much of a limitation in
221
- # practice--you wouldn't want to load an extension more than once.) This
222
- # implementation falls back to <tt>Kernel#require</tt> when the argument is an
223
- # extension or is not found locally.
224
-
225
- def require(feature)
226
- unless @loaded_features[feature]
227
- @loaded_features[feature] = true
228
- file = feature
229
- file += ".rb" unless /\.rb$/ =~ file
230
- load_in_module(File.join(component.path, file))
116
+ class ComponentDefinitionContainer < Module
117
+
118
+ class << self
119
+ def load_code(code)
120
+ returning(new) do |instance|
121
+ instance.module_eval code
122
+ end
123
+ end
124
+
125
+ def load_file(filename)
126
+ returning(new) do |instance|
127
+ instance.module_eval File.read(filename), filename
128
+ end
129
+ end
231
130
  end
232
- rescue MissingFile
233
- @loaded_features[feature] = false
234
- super
235
- end
236
-
237
- # Raised by #load_in_module, caught by #load and #require.
238
- class MissingFile < LoadError; end
239
-
240
- # Loads _file_ in this module's context. Note that <tt>\_\_FILE\_\_</tt> and
241
- # <tt>\_\_LINE\_\_</tt> work correctly in _file_.
242
- # Called by #load and #require; not normally called directly.
243
-
244
- def load_in_module(file)
245
- module_eval(File.read(file), File.expand_path(file))
246
- rescue Errno::ENOENT => e
247
- if /#{file}$/ =~ e.message
248
- raise MissingFile, e.message
249
- else
250
- raise
131
+
132
+ def initialize(&block)
133
+ # Hide our instance variables in the singleton class
134
+ metadata = {}
135
+ metaclass.send(:instance_variable_set, :@metadata, metadata)
136
+
137
+ metadata[:scopes] = ComponentManager::SCOPE_NAMES.inject({}) do |scopes, name|
138
+ scopes[name] = []
139
+ scopes
140
+ end
141
+
142
+ super
143
+
144
+ meta_def(:initialize) { raise "This object has already been instantiated. Are you sure you didn't mean initialization()?" }
145
+ end
146
+
147
+ def methods_for(*scopes, &block)
148
+ raise ArgumentError if scopes.empty?
149
+
150
+ ComponentManager.scopes_valid? scopes
151
+
152
+ metadata = metaclass.send(:instance_variable_get, :@metadata)
153
+ scopes.each { |scope| metadata[:scopes][scope] << block }
154
+ end
155
+
156
+ def initialization(&block)
157
+ # Raise an exception if the initialization block has already been set
158
+ metadata = metaclass.send(:instance_variable_get, :@metadata)
159
+ if metadata[:initialization_block]
160
+ raise "You should only have one initialization() block!"
161
+ else
162
+ metadata[:initialization_block] = block
163
+ end
251
164
  end
165
+ alias initialisation initialization
166
+
167
+ protected
168
+
169
+ class << self
170
+ def self.method_added(method_name)
171
+ @methods ||= []
172
+ @methods << method_name
173
+ end
174
+ end
175
+
252
176
  end
253
-
254
- def to_s
255
- "#<#{self.class}:#{File.basename(component.path)}>"
177
+
178
+ class ComponentMethodDefinitionContainer < Module
179
+ class << self
180
+ def method_added(method_name)
181
+ @methods ||= []
182
+ @methods << method_name
183
+ end
184
+ end
185
+
186
+ attr_reader :scopes
187
+ def initialize(*scopes, &block)
188
+ @scopes = []
189
+ super(&block)
190
+ end
191
+
256
192
  end
257
-
258
- module ComponentModuleMethods
259
- # This is so that <tt>def meth...</tt> behaves like in Ruby's top-level
260
- # context. The implementation simply calls
261
- # <tt>Module#module_function(name)</tt>.
262
- def method_added(name) # :nodoc:
263
- module_function(name)
193
+
194
+ class LazyConfigLoader
195
+ def initialize(component_manager)
196
+ @component_manager = component_manager
264
197
  end
265
-
266
- def start_component_after(*others)
267
- others.each do |component_name|
268
- component.manager.active_components[component_name].start
269
- end
198
+
199
+ def method_missing(component_name)
200
+ config = @component_manager.configuration_for_component_named(component_name.to_s)
201
+ (class << self; self; end).send(:define_method, component_name) { config }
202
+ config
270
203
  end
271
-
272
204
  end
205
+
273
206
  end
274
207
  end
275
-
276
- ComponentManager = Components::Manager.new unless defined? ComponentManager
277
208
  end
@@ -0,0 +1,55 @@
1
+ module ComponentTester
2
+
3
+ class << self
4
+
5
+ ##
6
+ #
7
+ #
8
+ # @return [Module] an anonymous module which includes the ComponentTester module.
9
+ #
10
+ def new(component_name, component_directory)
11
+ component_directory = File.expand_path component_directory
12
+ main_file = component_directory + "/#{component_name}/#{component_name}.rb"
13
+
14
+ component_manager = Adhearsion::Components::ComponentManager.new(component_directory)
15
+ component_module = Adhearsion::Components::ComponentManager::ComponentDefinitionContainer.load_file main_file
16
+
17
+ Module.new do
18
+
19
+ extend ComponentTester
20
+
21
+ (class << self; self; end).send(:define_method, :component_manager) { component_manager }
22
+ (class << self; self; end).send(:define_method, :component_name) { component_name }
23
+ (class << self; self; end).send(:define_method, :component_module) { component_module }
24
+ (class << self; self; end).send(:define_method, :component_directory) { component_directory }
25
+
26
+
27
+ define_method(:component_manager) { component_manager }
28
+ define_method(:component_name) { component_name }
29
+ define_method(:component_module) { component_module }
30
+ define_method(:component_directory) { component_directory }
31
+
32
+ def self.const_missing(name)
33
+ component_module.const_get name
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+
40
+ def helper_method(name)
41
+ Object.new.extend(component_module).method(name)
42
+ end
43
+
44
+ def config
45
+ component_manager.configuration_for_component_named component_name
46
+ end
47
+
48
+ def initialize!
49
+ metadata = component_module.metaclass.send(:instance_variable_get, :@metadata)
50
+ if metadata && metadata[:initialization_block].kind_of?(Proc)
51
+ metadata[:initialization_block].call
52
+ end
53
+ end
54
+
55
+ end