sevenscale-adhearsion 0.7.1003 → 0.8.0

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 (149) hide show
  1. data/CHANGELOG +8 -2
  2. data/EVENTS +11 -0
  3. data/Rakefile +92 -26
  4. data/adhearsion.gemspec +131 -23
  5. data/app_generators/ahn/ahn_generator.rb +21 -7
  6. data/app_generators/ahn/templates/.ahnrc +10 -4
  7. data/app_generators/ahn/templates/Rakefile +7 -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 -6
  17. data/bin/jahn +10 -0
  18. data/examples/asterisk_manager_interface/standalone.rb +51 -0
  19. data/lib/adhearsion/cli.rb +140 -23
  20. data/lib/adhearsion/component_manager/component_tester.rb +55 -0
  21. data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
  22. data/lib/adhearsion/component_manager.rb +169 -238
  23. data/lib/adhearsion/events_support.rb +59 -237
  24. data/lib/adhearsion/{core_extensions → foundation}/all.rb +0 -0
  25. data/lib/adhearsion/{blank_slate.rb → foundation/blank_slate.rb} +0 -0
  26. data/lib/adhearsion/{core_extensions → foundation}/custom_daemonizer.rb +0 -0
  27. data/lib/adhearsion/foundation/event_socket.rb +203 -0
  28. data/lib/adhearsion/foundation/future_resource.rb +36 -0
  29. data/lib/adhearsion/{core_extensions → foundation}/global.rb +0 -0
  30. data/lib/adhearsion/{core_extensions → foundation}/metaprogramming.rb +0 -0
  31. data/lib/adhearsion/foundation/numeric.rb +13 -0
  32. data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
  33. data/lib/adhearsion/{core_extensions → foundation}/relationship_properties.rb +2 -0
  34. data/lib/adhearsion/foundation/string.rb +26 -0
  35. data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
  36. data/lib/adhearsion/{core_extensions → foundation}/thread_safety.rb +0 -0
  37. data/lib/adhearsion/host_definitions.rb +5 -1
  38. data/lib/adhearsion/initializer/asterisk.rb +33 -11
  39. data/lib/adhearsion/initializer/configuration.rb +58 -6
  40. data/lib/adhearsion/initializer/database.rb +3 -46
  41. data/lib/adhearsion/initializer/drb.rb +9 -3
  42. data/lib/adhearsion/initializer/freeswitch.rb +3 -3
  43. data/lib/adhearsion/initializer/rails.rb +1 -1
  44. data/lib/adhearsion/initializer.rb +213 -87
  45. data/lib/adhearsion/tasks/deprecations.rb +59 -0
  46. data/lib/adhearsion/tasks.rb +2 -1
  47. data/lib/adhearsion/version.rb +3 -3
  48. data/lib/adhearsion/voip/asterisk/agi_server.rb +6 -6
  49. data/lib/adhearsion/voip/asterisk/commands.rb +100 -2
  50. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
  51. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
  52. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
  53. data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
  54. data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
  55. data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
  56. data/lib/adhearsion/voip/asterisk.rb +1 -8
  57. data/lib/adhearsion/voip/call.rb +5 -1
  58. data/lib/adhearsion/voip/dial_plan.rb +74 -61
  59. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
  60. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +2 -6
  61. data/lib/adhearsion/voip/dsl/numerical_string.rb +2 -2
  62. data/lib/adhearsion/voip/freeswitch/oes_server.rb +2 -2
  63. data/lib/adhearsion.rb +16 -11
  64. data/lib/theatre/README.markdown +64 -0
  65. data/lib/theatre/callback_definition_loader.rb +84 -0
  66. data/lib/theatre/guid.rb +23 -0
  67. data/lib/theatre/invocation.rb +121 -0
  68. data/lib/theatre/namespace_manager.rb +153 -0
  69. data/lib/theatre/version.rb +2 -0
  70. data/lib/theatre.rb +151 -0
  71. metadata +60 -147
  72. data/Manifest.txt +0 -151
  73. data/README.txt +0 -5
  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/voip/asterisk/ami/actions.rb +0 -238
  103. data/lib/adhearsion/voip/asterisk/ami/machine.rb +0 -871
  104. data/lib/adhearsion/voip/asterisk/ami/machine.rl +0 -109
  105. data/lib/adhearsion/voip/asterisk/ami/parser.rb +0 -262
  106. data/lib/adhearsion/voip/asterisk/ami.rb +0 -147
  107. data/spec/fixtures/dialplan.rb +0 -3
  108. data/spec/initializer/test_configuration.rb +0 -267
  109. data/spec/initializer/test_loading.rb +0 -162
  110. data/spec/initializer/test_paths.rb +0 -43
  111. data/spec/sample.rb +0 -9
  112. data/spec/silence.rb +0 -10
  113. data/spec/test_ahn_command.rb +0 -149
  114. data/spec/test_code_quality.rb +0 -87
  115. data/spec/test_component_manager.rb +0 -97
  116. data/spec/test_constants.rb +0 -8
  117. data/spec/test_drb.rb +0 -104
  118. data/spec/test_events.rb +0 -136
  119. data/spec/test_helper.rb +0 -106
  120. data/spec/test_hooks.rb +0 -15
  121. data/spec/test_host_definitions.rb +0 -79
  122. data/spec/test_initialization.rb +0 -124
  123. data/spec/test_logging.rb +0 -80
  124. data/spec/test_relationship_properties.rb +0 -54
  125. data/spec/voip/asterisk/ami_response_definitions.rb +0 -23
  126. data/spec/voip/asterisk/config_file_generators/test_agents.rb +0 -253
  127. data/spec/voip/asterisk/config_file_generators/test_queues.rb +0 -325
  128. data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +0 -306
  129. data/spec/voip/asterisk/menu_command/test_calculated_match.rb +0 -111
  130. data/spec/voip/asterisk/menu_command/test_matchers.rb +0 -98
  131. data/spec/voip/asterisk/mock_ami_server.rb +0 -176
  132. data/spec/voip/asterisk/test_agi_server.rb +0 -453
  133. data/spec/voip/asterisk/test_ami.rb +0 -227
  134. data/spec/voip/asterisk/test_commands.rb +0 -2006
  135. data/spec/voip/asterisk/test_config_manager.rb +0 -129
  136. data/spec/voip/dsl/dispatcher_spec_helper.rb +0 -45
  137. data/spec/voip/dsl/test_dialing_dsl.rb +0 -268
  138. data/spec/voip/dsl/test_dispatcher.rb +0 -82
  139. data/spec/voip/dsl/test_parser.rb +0 -87
  140. data/spec/voip/freeswitch/test_basic_connection_manager.rb +0 -39
  141. data/spec/voip/freeswitch/test_inbound_connection_manager.rb +0 -39
  142. data/spec/voip/freeswitch/test_oes_server.rb +0 -9
  143. data/spec/voip/test_call_routing.rb +0 -127
  144. data/spec/voip/test_dialplan_manager.rb +0 -442
  145. data/spec/voip/test_numerical_string.rb +0 -48
  146. data/spec/voip/test_phone_number.rb +0 -36
  147. data/test/test_ahn_generator.rb +0 -59
  148. data/test/test_component_generator.rb +0 -52
  149. 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