eric-adhearsion 0.7.999

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 +3 -0
  2. data/LICENSE +456 -0
  3. data/Manifest.txt +149 -0
  4. data/README.txt +6 -0
  5. data/Rakefile +48 -0
  6. data/ahn_generators/component/USAGE +5 -0
  7. data/ahn_generators/component/component_generator.rb +57 -0
  8. data/ahn_generators/component/templates/configuration.rb +0 -0
  9. data/ahn_generators/component/templates/lib/lib.rb.erb +3 -0
  10. data/ahn_generators/component/templates/test/test.rb.erb +12 -0
  11. data/ahn_generators/component/templates/test/test_helper.rb +14 -0
  12. data/app_generators/ahn/USAGE +5 -0
  13. data/app_generators/ahn/ahn_generator.rb +76 -0
  14. data/app_generators/ahn/templates/.ahnrc +12 -0
  15. data/app_generators/ahn/templates/README +8 -0
  16. data/app_generators/ahn/templates/Rakefile +3 -0
  17. data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
  18. data/app_generators/ahn/templates/components/simon_game/lib/simon_game.rb +61 -0
  19. data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +14 -0
  20. data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +31 -0
  21. data/app_generators/ahn/templates/config/startup.rb +53 -0
  22. data/app_generators/ahn/templates/dialplan.rb +4 -0
  23. data/bin/ahn +28 -0
  24. data/bin/ahnctl +68 -0
  25. data/bin/jahn +32 -0
  26. data/lib/adhearsion/blank_slate.rb +5 -0
  27. data/lib/adhearsion/cli.rb +106 -0
  28. data/lib/adhearsion/component_manager.rb +277 -0
  29. data/lib/adhearsion/core_extensions/all.rb +9 -0
  30. data/lib/adhearsion/core_extensions/array.rb +0 -0
  31. data/lib/adhearsion/core_extensions/custom_daemonizer.rb +45 -0
  32. data/lib/adhearsion/core_extensions/global.rb +1 -0
  33. data/lib/adhearsion/core_extensions/guid.rb +5 -0
  34. data/lib/adhearsion/core_extensions/hash.rb +0 -0
  35. data/lib/adhearsion/core_extensions/metaprogramming.rb +17 -0
  36. data/lib/adhearsion/core_extensions/numeric.rb +4 -0
  37. data/lib/adhearsion/core_extensions/proc.rb +0 -0
  38. data/lib/adhearsion/core_extensions/pseudo_uuid.rb +11 -0
  39. data/lib/adhearsion/core_extensions/publishable.rb +73 -0
  40. data/lib/adhearsion/core_extensions/relationship_properties.rb +40 -0
  41. data/lib/adhearsion/core_extensions/string.rb +26 -0
  42. data/lib/adhearsion/core_extensions/thread.rb +13 -0
  43. data/lib/adhearsion/core_extensions/thread_safety.rb +7 -0
  44. data/lib/adhearsion/core_extensions/time.rb +0 -0
  45. data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
  46. data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
  47. data/lib/adhearsion/distributed/gateways/rest_gateway.rb +9 -0
  48. data/lib/adhearsion/distributed/gateways/soap_gateway.rb +9 -0
  49. data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +9 -0
  50. data/lib/adhearsion/distributed/peer_finder.rb +0 -0
  51. data/lib/adhearsion/distributed/remote_cli.rb +0 -0
  52. data/lib/adhearsion/hooks.rb +57 -0
  53. data/lib/adhearsion/host_definitions.rb +63 -0
  54. data/lib/adhearsion/initializer/asterisk.rb +59 -0
  55. data/lib/adhearsion/initializer/configuration.rb +202 -0
  56. data/lib/adhearsion/initializer/database.rb +92 -0
  57. data/lib/adhearsion/initializer/drb.rb +25 -0
  58. data/lib/adhearsion/initializer/freeswitch.rb +22 -0
  59. data/lib/adhearsion/initializer/paths.rb +55 -0
  60. data/lib/adhearsion/initializer/rails.rb +40 -0
  61. data/lib/adhearsion/initializer.rb +217 -0
  62. data/lib/adhearsion/logging.rb +92 -0
  63. data/lib/adhearsion/services/scheduler.rb +5 -0
  64. data/lib/adhearsion/tasks/database.rb +5 -0
  65. data/lib/adhearsion/tasks/generating.rb +20 -0
  66. data/lib/adhearsion/tasks/lint.rb +4 -0
  67. data/lib/adhearsion/tasks/testing.rb +37 -0
  68. data/lib/adhearsion/tasks.rb +15 -0
  69. data/lib/adhearsion/version.rb +9 -0
  70. data/lib/adhearsion/voip/asterisk/agi_server.rb +78 -0
  71. data/lib/adhearsion/voip/asterisk/ami/actions.rb +238 -0
  72. data/lib/adhearsion/voip/asterisk/ami/machine.rb +871 -0
  73. data/lib/adhearsion/voip/asterisk/ami/machine.rl +109 -0
  74. data/lib/adhearsion/voip/asterisk/ami/parser.rb +262 -0
  75. data/lib/adhearsion/voip/asterisk/ami.rb +147 -0
  76. data/lib/adhearsion/voip/asterisk/commands.rb +1182 -0
  77. data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
  78. data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
  79. data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
  80. data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
  81. data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
  82. data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
  83. data/lib/adhearsion/voip/asterisk.rb +4 -0
  84. data/lib/adhearsion/voip/call.rb +391 -0
  85. data/lib/adhearsion/voip/call_routing.rb +64 -0
  86. data/lib/adhearsion/voip/commands.rb +9 -0
  87. data/lib/adhearsion/voip/constants.rb +39 -0
  88. data/lib/adhearsion/voip/conveniences.rb +18 -0
  89. data/lib/adhearsion/voip/dial_plan.rb +205 -0
  90. data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
  91. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
  92. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
  93. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
  94. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +75 -0
  95. data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
  96. data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
  97. data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
  98. data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
  99. data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
  100. data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
  101. data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
  102. data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
  103. data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
  104. data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
  105. data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
  106. data/lib/adhearsion.rb +31 -0
  107. data/script/destroy +14 -0
  108. data/script/generate +14 -0
  109. data/spec/fixtures/dialplan.rb +3 -0
  110. data/spec/initializer/test_configuration.rb +267 -0
  111. data/spec/initializer/test_loading.rb +162 -0
  112. data/spec/initializer/test_paths.rb +43 -0
  113. data/spec/silence.rb +10 -0
  114. data/spec/test_ahn_command.rb +149 -0
  115. data/spec/test_code_quality.rb +87 -0
  116. data/spec/test_component_manager.rb +97 -0
  117. data/spec/test_constants.rb +8 -0
  118. data/spec/test_drb.rb +104 -0
  119. data/spec/test_helper.rb +94 -0
  120. data/spec/test_hooks.rb +37 -0
  121. data/spec/test_host_definitions.rb +79 -0
  122. data/spec/test_initialization.rb +105 -0
  123. data/spec/test_logging.rb +80 -0
  124. data/spec/test_relationship_properties.rb +54 -0
  125. data/spec/voip/asterisk/ami_response_definitions.rb +23 -0
  126. data/spec/voip/asterisk/config_file_generators/test_agents.rb +253 -0
  127. data/spec/voip/asterisk/config_file_generators/test_queues.rb +325 -0
  128. data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +306 -0
  129. data/spec/voip/asterisk/menu_command/test_calculated_match.rb +111 -0
  130. data/spec/voip/asterisk/menu_command/test_matchers.rb +98 -0
  131. data/spec/voip/asterisk/mock_ami_server.rb +176 -0
  132. data/spec/voip/asterisk/test_agi_server.rb +451 -0
  133. data/spec/voip/asterisk/test_ami.rb +227 -0
  134. data/spec/voip/asterisk/test_commands.rb +2006 -0
  135. data/spec/voip/asterisk/test_config_manager.rb +129 -0
  136. data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
  137. data/spec/voip/dsl/test_dialing_dsl.rb +268 -0
  138. data/spec/voip/dsl/test_dispatcher.rb +82 -0
  139. data/spec/voip/dsl/test_parser.rb +87 -0
  140. data/spec/voip/freeswitch/test_basic_connection_manager.rb +39 -0
  141. data/spec/voip/freeswitch/test_inbound_connection_manager.rb +39 -0
  142. data/spec/voip/freeswitch/test_oes_server.rb +9 -0
  143. data/spec/voip/test_call_routing.rb +127 -0
  144. data/spec/voip/test_dialplan_manager.rb +372 -0
  145. data/spec/voip/test_numerical_string.rb +48 -0
  146. data/spec/voip/test_phone_number.rb +36 -0
  147. data/test/test_ahn_generator.rb +59 -0
  148. data/test/test_component_generator.rb +52 -0
  149. data/test/test_generator_helper.rb +20 -0
  150. metadata +254 -0
@@ -0,0 +1,277 @@
1
+ module Adhearsion
2
+
3
+ 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
+
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
28
+
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
37
+
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
47
+ end
48
+ 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
60
+ 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)
79
+ end
80
+
81
+ def component_name
82
+ Component.name
83
+ end
84
+
85
+ def component_description
86
+ Configuration.description || Component.name
87
+ end
88
+
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])
93
+ 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
109
+ end
110
+ end
111
+
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
+ end
124
+
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
132
+ end
133
+ @component_module.require(File.join("lib", @name.to_s))
134
+ end
135
+
136
+ def configuration
137
+ @component_module.const_get(:Configuration)
138
+ end
139
+
140
+ def stop
141
+ #@component_class.unload if @component_class && @component_class.respond_to?(:unload)
142
+ end
143
+
144
+ def configuration_file
145
+ File.join(path, configuration_file_name)
146
+ end
147
+
148
+ private
149
+
150
+ def main_file_name
151
+ File.join(@path, "lib", @name.to_s+".rb")
152
+ end
153
+
154
+ def configuration_file_name
155
+ "configuration.rb"
156
+ 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
214
+ end
215
+
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))
231
+ 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
251
+ end
252
+ end
253
+
254
+ def to_s
255
+ "#<#{self.class}:#{File.basename(component.path)}>"
256
+ 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)
264
+ end
265
+
266
+ def start_component_after(*others)
267
+ others.each do |component_name|
268
+ component.manager.active_components[component_name].start
269
+ end
270
+ end
271
+
272
+ end
273
+ end
274
+ end
275
+
276
+ ComponentManager = Components::Manager.new unless defined? ComponentManager
277
+ end
@@ -0,0 +1,9 @@
1
+ require 'English'
2
+ require 'tmpdir'
3
+ require 'tempfile'
4
+ require 'active_support'
5
+
6
+ # Require all other files here.
7
+ Dir.glob File.join(File.dirname(__FILE__), "*rb") do |file|
8
+ require file
9
+ end
File without changes
@@ -0,0 +1,45 @@
1
+ # This is largely based on the Daemonize library by Travis Whitton and
2
+ # Judson Lester. http://grub.ath.cx/daemonize. I cleaned it up a bit to
3
+ # meet Adhearsion's quality standards.
4
+ module Adhearsion
5
+ module CustomDaemonizer
6
+
7
+ # Try to fork if at all possible retrying every 5 sec if the
8
+ # maximum process limit for the system has been reached
9
+ def safefork
10
+ begin
11
+ pid = fork
12
+ return pid if pid
13
+ rescue Errno::EWOULDBLOCK
14
+ sleep 5
15
+ retry
16
+ end
17
+ end
18
+
19
+ # This method causes the current running process to become a daemon
20
+ def daemonize(log_file='/dev/null')
21
+ oldmode = 0
22
+ srand # Split rand streams between spawning and daemonized process
23
+ safefork and exit # Fork and exit from the parent
24
+
25
+ # Detach from the controlling terminal
26
+ unless sess_id = Process.setsid
27
+ raise 'Cannot detach from controlled terminal'
28
+ end
29
+
30
+ # Prevent the possibility of acquiring a controlling terminal
31
+ if oldmode.zero?
32
+ trap 'SIGHUP', 'IGNORE'
33
+ exit if pid = safefork
34
+ end
35
+
36
+ Dir.chdir "/" # Release old working directory
37
+ File.umask 0000 # Ensure sensible umask
38
+
39
+ STDIN.reopen "/dev/null"
40
+ STDOUT.reopen '/dev/null', "a"
41
+ STDERR.reopen log_file
42
+ return oldmode ? sess_id : 0
43
+ end
44
+ end
45
+ end
@@ -0,0 +1 @@
1
+ Infinity = 1.0/0.0
@@ -0,0 +1,5 @@
1
+ module Kernel
2
+ def new_guid(args)
3
+
4
+ end
5
+ end
File without changes
@@ -0,0 +1,17 @@
1
+ class Object
2
+ def metaclass
3
+ class << self
4
+ self
5
+ end
6
+ end
7
+
8
+ def meta_eval(&block)
9
+ metaclass.instance_eval &block
10
+ end
11
+
12
+ def meta_def(name, &block)
13
+ meta_eval do
14
+ define_method name, &block
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ class Numeric
2
+ def digit() self end
3
+ def digits() self end
4
+ end
File without changes
@@ -0,0 +1,11 @@
1
+ module PseudoUuidGenerator
2
+ def uuid
3
+ returning Array.new(32) { String.random_char } do |string|
4
+ [8, 13, 18, 23].each do |index|
5
+ string.insert index, '-'
6
+ end
7
+ end.join
8
+ end
9
+ end
10
+
11
+ include PseudoUuidGenerator
@@ -0,0 +1,73 @@
1
+ module Adhearsion
2
+ class DrbDoor
3
+
4
+ include Singleton
5
+
6
+ def add(interface, name, meth)
7
+ @interfaces ||= {}
8
+ @interfaces[interface] ||= returning(Object.new) { |obj| obj.metaclass.send(:attr_accessor, :__methods) }
9
+ obj = @interfaces[interface]
10
+ obj.__methods ||= {}
11
+ obj.__methods[name] = meth
12
+ obj.instance_eval(<<-STR, __FILE__, __LINE__)
13
+ def #{name}(*args, &block)
14
+ begin
15
+ __methods["#{name}"].call(*args, &block)
16
+ rescue => exception
17
+ raise RuntimeError, exception.message, exception.backtrace
18
+ end
19
+ end
20
+ STR
21
+ end
22
+
23
+ def method_missing(name, *args, &block)
24
+ return Module.const_get(name) if name.to_s =~ /^[A-Z]/
25
+ super unless @interfaces && @interfaces.has_key?(name.to_s)
26
+ @interfaces[name.to_s]
27
+ end
28
+ end
29
+
30
+ module Publishable
31
+ def self.included(base)
32
+ base.send(:alias_method_chain, :initialize, :publishable)
33
+ base.extend(ClassMethods)
34
+ end
35
+
36
+ def initialize_with_publishable(*args, &block)
37
+ initialize_without_publishable(*args, &block)
38
+ self.class.published_instance_methods.each do |(sym, interface)|
39
+ DrbDoor.instance.add(interface, sym.to_s, self.method(sym))
40
+ end
41
+ end
42
+
43
+ module ClassMethods
44
+ attr_reader :interface
45
+ attr_reader :published_instance_methods
46
+
47
+ def publish(options={}, &block)
48
+ @interface = options.delete(:through).to_s || self.to_s
49
+ begin
50
+ @capture = true
51
+ yield
52
+ ensure
53
+ @capture = false
54
+ end
55
+ end
56
+
57
+ def method_added(sym)
58
+ return if not @capture
59
+ if sym.to_s !~ /method_added/
60
+ @published_instance_methods ||= []
61
+ @published_instance_methods << [sym, @interface]
62
+ end
63
+ end
64
+
65
+ def singleton_method_added(sym)
66
+ return if not @capture
67
+ if sym.to_s !~ /method_added/
68
+ DrbDoor.instance.add(@interface, sym.to_s, method(sym.to_s))
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,40 @@
1
+ class Module
2
+
3
+ # In OOP, relationships between classes should be treated as *properties* of those classes. Often, in a complex OO
4
+ # architecture, you'll end up with many relationships that intermingle in monolithic ways, blunting the effectiveness of
5
+ # subclassing.
6
+ #
7
+ # For example, say you have an Automobile class which, in its constructor, instantiates a new Battery class and performs
8
+ # some operations on it such as calling an install() method. Let's also assume the Automobile class exposes a repair()
9
+ # method which uses a class-level method of Battery to diagnose your own instance of Battery. If the result of the
10
+ # diagnosis shows that the Battery is bad, the Automobile will instantiate a new Battery object and replace the old battery
11
+ # with the new one.
12
+ #
13
+ # Now, what if you wish to create a new Automobile derived from existing technology: a HybridAutomobile subclass. For this
14
+ # particular HybridAutomobile class, let's simply say the only difference between it and its parent is which kind of
15
+ # Battery it uses -- it requires its own special subclass of Battery. With Automobile's current implementation, its
16
+ # references to which Battery it instantiates and uses are embedded in the immutable method defintions. This
17
+ # HybridAutomobile needs to override which Battery its superclass' methods use and nothing else.
18
+ #
19
+ # For this reason, the Battery class which Automobile uses is semantically a property which others may want to override.
20
+ # In OOP theory, we define overridable properties in the form of methods and override those methods in the subclasses.
21
+ #
22
+ # This method exposes one method which creates human-readable semantics to defining these relationships as properties. It's
23
+ # used as follows:
24
+ #
25
+ # class Automobile
26
+ # relationship :battery => Battery
27
+ # relationship :chassis => Chassis
28
+ # # Other properties and instance methods here....
29
+ # end
30
+ #
31
+ # class HybridAutomobile < Automobile
32
+ # relationship :battery => HybridBattery
33
+ # end
34
+ def relationships(relationship_mapping)
35
+ relationship_mapping.each_pair do |class_name, class_object|
36
+ define_method(class_name) { class_object }
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,26 @@
1
+ class String
2
+
3
+ def unindent
4
+ gsub(/^\s*/,'')
5
+ end
6
+
7
+ def unindent!
8
+ gsub!(/^\s*/,'')
9
+ end
10
+
11
+ def self.random_char
12
+ case random_digit = rand(62)
13
+ when 0...10 : random_digit.to_s
14
+ when 10...36 : (random_digit + 55).chr
15
+ when 36...62 : (random_digit + 61).chr
16
+ end
17
+ end
18
+
19
+ def self.random(length_of_string=8)
20
+ Array.new(length_of_string) { random_char }.join
21
+ end
22
+
23
+ def nameify() downcase.gsub(/[^\w]/, '') end
24
+ def nameify!() replace nameify end
25
+
26
+ end
@@ -0,0 +1,13 @@
1
+ class Thread
2
+ class << self
3
+
4
+ # Syntactically sugar Thread.current since it's used so much.
5
+ #
6
+ # Allows:
7
+ # Thread.me.extend DSL::Dialplan::ThreadMixin
8
+ # Thread.my.call.io = io
9
+
10
+ alias me current
11
+ alias my current
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ require 'thread'
2
+ class Object
3
+ def synchronize(&block)
4
+ @mutex ||= Mutex.new
5
+ @mutex.synchronize &block
6
+ end
7
+ end
File without changes
@@ -0,0 +1,9 @@
1
+ module Adhearsion
2
+ module Distributed
3
+ module Gateway
4
+ module REST
5
+
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Adhearsion
2
+ module Distributed
3
+ module Gateway
4
+ module SOAP
5
+
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Adhearsion
2
+ module Distributed
3
+ module Gateway
4
+ module XMLRPC
5
+
6
+ end
7
+ end
8
+ end
9
+ end
File without changes
File without changes
@@ -0,0 +1,57 @@
1
+ module Adhearsion
2
+
3
+
4
+ module Hooks
5
+
6
+ class GenericHook
7
+
8
+ def initialize
9
+ @hooks = []
10
+ end
11
+
12
+ def create_hook(&block)
13
+ @hooks.synchronize do
14
+ @hooks << block
15
+ end
16
+ end
17
+
18
+ # TODO: This is hardly thread safe!
19
+ def trigger_hooks
20
+ @hooks.each &:call
21
+ end
22
+
23
+ end
24
+
25
+ class HookWithArguments < GenericHook
26
+ def trigger_hooks(*args)
27
+ @hooks.each { |hook| hook.call(*args) }
28
+ end
29
+ end
30
+
31
+ ThreadsJoinedAfterInitialized = GenericHook.new
32
+
33
+ OnFailedCall = HookWithArguments.new
34
+ OnHungupCall = HookWithArguments.new
35
+ AfterInitialized = GenericHook.new
36
+ BeforeCall = GenericHook.new
37
+ AfterCall = GenericHook.new
38
+ TearDown = GenericHook.new
39
+
40
+ class << TearDown
41
+ def aliases
42
+ [:before_shutdown]
43
+ end
44
+
45
+ def catch_termination_signals
46
+ %w'INT TERM'.each do |sig|
47
+ trap sig do
48
+ ahn_log "Shutting down gracefully at #{Time.now}."
49
+ Adhearsion::Hooks::TearDown.trigger_hooks
50
+ exit
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ end