adhearsion 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +10 -0
  2. data/CHANGELOG +8 -0
  3. data/README.markdown +33 -0
  4. data/Rakefile +28 -68
  5. data/adhearsion.gemspec +19 -133
  6. data/app_generators/ahn/templates/Gemfile +0 -4
  7. data/app_generators/ahn/templates/components/disabled/restful_rpc/spec/restful_rpc_spec.rb +4 -16
  8. data/lib/adhearsion/cli.rb +17 -0
  9. data/lib/adhearsion/component_manager/component_tester.rb +1 -3
  10. data/lib/adhearsion/component_manager/spec_framework.rb +4 -10
  11. data/lib/adhearsion/foundation/object.rb +10 -0
  12. data/lib/adhearsion/version.rb +1 -1
  13. data/spec/ahn_command_spec.rb +284 -0
  14. data/spec/component_manager_spec.rb +292 -0
  15. data/spec/constants_spec.rb +8 -0
  16. data/spec/drb_spec.rb +65 -0
  17. data/spec/fixtures/dialplan.rb +3 -0
  18. data/spec/foundation/event_socket_spec.rb +168 -0
  19. data/spec/host_definitions_spec.rb +79 -0
  20. data/spec/initialization_spec.rb +163 -0
  21. data/spec/initializer/configuration_spec.rb +270 -0
  22. data/spec/initializer/loading_spec.rb +149 -0
  23. data/spec/initializer/paths_spec.rb +74 -0
  24. data/spec/logging_spec.rb +86 -0
  25. data/spec/relationship_properties_spec.rb +54 -0
  26. data/spec/silence.rb +10 -0
  27. data/spec/spec_helper.rb +101 -0
  28. data/spec/voip/asterisk/agi_server_spec.rb +473 -0
  29. data/spec/voip/asterisk/ami/ami_spec.rb +549 -0
  30. data/spec/voip/asterisk/ami/lexer/ami_fixtures.yml +30 -0
  31. data/spec/voip/asterisk/ami/lexer/lexer_story +291 -0
  32. data/spec/voip/asterisk/ami/lexer/lexer_story.rb +241 -0
  33. data/spec/voip/asterisk/ami/lexer/story_helper.rb +124 -0
  34. data/spec/voip/asterisk/ami/old_tests.rb +204 -0
  35. data/spec/voip/asterisk/ami/super_manager/super_manager_story +25 -0
  36. data/spec/voip/asterisk/ami/super_manager/super_manager_story.rb +15 -0
  37. data/spec/voip/asterisk/ami/super_manager/super_manager_story_helper.rb +5 -0
  38. data/spec/voip/asterisk/commands_spec.rb +2179 -0
  39. data/spec/voip/asterisk/config_file_generators/agents_spec.rb +251 -0
  40. data/spec/voip/asterisk/config_file_generators/queues_spec.rb +323 -0
  41. data/spec/voip/asterisk/config_file_generators/voicemail_spec.rb +306 -0
  42. data/spec/voip/asterisk/config_manager_spec.rb +127 -0
  43. data/spec/voip/asterisk/menu_command/calculated_match_spec.rb +109 -0
  44. data/spec/voip/asterisk/menu_command/matchers_spec.rb +97 -0
  45. data/spec/voip/call_routing_spec.rb +125 -0
  46. data/spec/voip/dialplan_manager_spec.rb +468 -0
  47. data/spec/voip/dsl/dialing_dsl_spec.rb +270 -0
  48. data/spec/voip/dsl/dispatcher_spec.rb +82 -0
  49. data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
  50. data/spec/voip/dsl/parser_spec.rb +69 -0
  51. data/spec/voip/freeswitch/basic_connection_manager_spec.rb +39 -0
  52. data/spec/voip/freeswitch/inbound_connection_manager_spec.rb +39 -0
  53. data/spec/voip/freeswitch/oes_server_spec.rb +9 -0
  54. data/spec/voip/numerical_string_spec.rb +61 -0
  55. data/spec/voip/phone_number_spec.rb +45 -0
  56. data/theatre-spec/dsl_examples/dynamic_stomp.rb +7 -0
  57. data/theatre-spec/dsl_examples/simple_before_call.rb +7 -0
  58. data/theatre-spec/dsl_spec.rb +43 -0
  59. data/theatre-spec/invocation_spec.rb +167 -0
  60. data/theatre-spec/namespace_spec.rb +125 -0
  61. data/theatre-spec/spec_helper.rb +37 -0
  62. data/theatre-spec/spec_helper_spec.rb +28 -0
  63. data/theatre-spec/theatre_class_spec.rb +150 -0
  64. metadata +171 -34
@@ -0,0 +1,270 @@
1
+ require 'spec_helper'
2
+ require 'adhearsion/voip/dsl/dialing_dsl'
3
+
4
+ # Keep the monkey patches in a module and load that into Regexp
5
+ # eigenclasses during a before(:all) block?
6
+
7
+ describe "RouteRule Regexp assembling" do
8
+
9
+ it "should compile two Regexps" do
10
+ first, last = /jay/, /phillips/
11
+ r = first | last
12
+ r.patterns.should == [first, last]
13
+ end
14
+
15
+ it "should compile three or more Regexps" do
16
+ first, second, third = /lorem/, /ipsum/, /dolar/
17
+ r = first | second | third
18
+ r.patterns.should == [first, second, third]
19
+ end
20
+
21
+ end
22
+
23
+ describe "RouteRule assembling with one provider definition" do
24
+
25
+ before :each do
26
+ @provider = Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:icanhascheezburger?)
27
+ end
28
+
29
+ it "should store one pattern properly" do
30
+ pattern = /lorem/
31
+ route = pattern >> @provider
32
+ route.patterns.should == [pattern]
33
+ end
34
+
35
+ it "should store three patterns properly" do
36
+ first, second, third = /lorem/, /ipsum/, /dolar/
37
+ route = first | second | third >> @provider
38
+ route.patterns.should == [first, second, third]
39
+ route.providers.should == [@provider]
40
+ end
41
+
42
+ end
43
+
44
+ describe "RouteRule assembling with multiple patterns and multiple provider definitions" do
45
+
46
+ before(:each) do
47
+ 1.upto 3 do |i|
48
+ instance_variable_set "@prov_#{i}",
49
+ Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new("prov_#{i}")
50
+ instance_variable_set "@pattern_#{i}", /^#{i * 100}$/
51
+ end
52
+ end
53
+
54
+ it "should store the patterns properly" do
55
+ route_1 = @pattern_1 | @pattern_2 | @pattern_3 >> @prov_1 >> @prov_2 >> @prov_3
56
+ route_1.patterns.should == [@pattern_1, @pattern_2, @pattern_3]
57
+
58
+ route_2 = @pattern_2 | @pattern_3 | @pattern_1 >> @prov_3 >> @prov_2 >> @prov_1
59
+ route_2.patterns.should == [@pattern_2, @pattern_3, @pattern_1]
60
+ end
61
+
62
+ it "should store the providers properly" do
63
+ route_1 = @pattern_1 | @pattern_2 | @pattern_3 >> @prov_1 >> @prov_2 >> @prov_3
64
+ route_1.providers.should == [@prov_1, @prov_2, @prov_3]
65
+
66
+ route_2 = @pattern_2 | @pattern_3 | @pattern_1 >> @prov_3 >> @prov_2 >> @prov_1
67
+ route_2.patterns.should == [@pattern_2, @pattern_3, @pattern_1]
68
+ end
69
+ end
70
+
71
+ describe "The DialingDSL class internals" do
72
+
73
+ it "should allow Asterisk-like patterns" do
74
+ Adhearsion::VoIP::DSL::DialingDSL.class_eval do
75
+ _('23XX')
76
+ end.should be_an_instance_of Regexp
77
+ end
78
+
79
+ it "should define all of the VoIP constants" do
80
+ lambda do
81
+ Adhearsion::VoIP::Constants.constants.each do |constant|
82
+ eval "Adhearsion::VoIP::DSL::DialingDSL::#{constant}"
83
+ end
84
+ end.should_not raise_error NameError
85
+ end
86
+
87
+ # it "should define a DUNDI constant"
88
+
89
+ it "should synchronize access to the trunking information for Thread safety"
90
+
91
+ end
92
+
93
+ describe "The provider DSL's 'provider' macro" do
94
+
95
+ it "should make the providers available in the order they were received" do
96
+ provider_holder = Class.new Adhearsion::VoIP::DSL::DialingDSL
97
+ provider_holder.class_eval do
98
+ provider(:tweedledee) {}
99
+ provider(:tweedledum) {}
100
+ end
101
+ provider_holder.providers.map { |x| x.name }.should == [:tweedledee, :tweedledum]
102
+ end
103
+ it "should define a singleton method for the provider name given", :focus => true do
104
+ dsl_class = Class.new(Adhearsion::VoIP::DSL::DialingDSL)
105
+ dsl_class.class_eval do
106
+ class_variable_get(:@@providers).size.should == 0
107
+
108
+ provider(:icanhascheezburger?) {}
109
+
110
+ class_variable_get(:@@providers).size.should == 1
111
+ end
112
+ dsl_class.should respond_to(:icanhascheezburger?)
113
+ end
114
+ it "should not define a class-wide method for the provider name given" do
115
+ dsl_class = Class.new(Adhearsion::VoIP::DSL::DialingDSL)
116
+ dsl_class.class_eval do
117
+ provider(:icanhascheezburger?) {}
118
+ end
119
+ Adhearsion::VoIP::DSL::DialingDSL.class_eval do
120
+ class_variable_defined?(:@@providers).should == false
121
+ end
122
+ Adhearsion::VoIP::DSL::DialingDSL.should_not respond_to(:icanhascheezburger?)
123
+ end
124
+ it "should yield a ProviderDefinition object" do
125
+ possible_provider_definition = nil
126
+ Class.new(Adhearsion::VoIP::DSL::DialingDSL).class_eval do
127
+ provider(:blah) { |pd| possible_provider_definition = pd }
128
+ end
129
+ possible_provider_definition.should be_a_kind_of(Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition)
130
+ end
131
+ it "should raise an error when no block is given" do
132
+ the_following_code do
133
+ Class.new(Adhearsion::VoIP::DSL::DialingDSL).class_eval do
134
+ provider :explode
135
+ end
136
+ end.should raise_error ArgumentError
137
+ end
138
+ end
139
+
140
+ describe "The provider DSL's monkey patches to Regexp" do
141
+ it "should return a RouteRule when using Regexp#| with another Regexp" do
142
+ (// | //).should be_a_kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
143
+ end
144
+ it "should return a RouteRule when chaining three Regexp's with the | operator" do
145
+ (// | // | //).should be_a_kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
146
+ end
147
+ it "should return a RouteRule when Regexp#| is given a RouteRule" do
148
+ route_rule = Adhearsion::VoIP::DSL::DialingDSL::RouteRule.new :patterns => //
149
+ (// | route_rule).should be_a_kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
150
+ end
151
+ it "should return a RouteRule when Regexp#>> is given a ProviderDefinition" do
152
+ (/1/ >> Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:foo)).
153
+ should be_a_kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
154
+ end
155
+ it "should return a RouteRule when Regexp#>>() receives a ProviderDefinition" do
156
+ definition = Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:london)
157
+ (/foo/ >> definition).should be_a_kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
158
+ end
159
+ it "should raise an exception when Regexp#| receives something other than a RouteRule" do
160
+ bad_args = [ 0..100, 20, 45.55, {}, [] ]
161
+ bad_args.each do |arg|
162
+ the_following_code { /foo/ | arg }.should raise_error ArgumentError
163
+ end
164
+ end
165
+ it "should raise an exception when Regexp#>>() receives anything other than a ProviderDefintion or RouteRule" do
166
+ bad_args = [ 0..100, 20, 45.55, {}, [] ]
167
+ bad_args.each do |arg|
168
+ the_following_code { /foo/ >> arg }.should raise_error ArgumentError
169
+ end
170
+ end
171
+ end
172
+
173
+ describe "A RouteRule" do
174
+ it "should expose chained ProviderDefinitions properly" do
175
+ one, two, three = definitions = %w"foo bar qaz".map do |name|
176
+ Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new name
177
+ end
178
+ route = /^911$/ >> one >> two >> three
179
+ route.should be_a_kind_of(Adhearsion::VoIP::DSL::DialingDSL::RouteRule)
180
+ route.providers.should == definitions
181
+ end
182
+ it "should define attr_readers for providers and patterns" do
183
+ route = Adhearsion::VoIP::DSL::DialingDSL::RouteRule.new
184
+ route.should respond_to(:patterns)
185
+ route.should respond_to(:providers)
186
+ end
187
+ end
188
+
189
+ describe "The provider order modifiers" do
190
+ it "should support randomizing trunks", :ignore => true do
191
+ dsl = Class.new Adhearsion::VoIP::DSL::DialingDSL
192
+ dsl.class_eval do
193
+ provider(:l33thost) {}
194
+ provider(:h4xxhost) {}
195
+ route /\d+\*548/ >> random(l33thost, h4xxhost)
196
+ end
197
+ dsl.routes.first.provider_definitions.first.should be_a_kind_of(
198
+ Adhearsion::VoIP::DSL::DialingDSL::RandomRouteRule
199
+ )
200
+ end
201
+ end
202
+
203
+ describe "The provider DSL's 'route' builder" do
204
+ it "should register routes in the order received" do
205
+ dsl = Class.new Adhearsion::VoIP::DSL::DialingDSL
206
+ dsl.class_eval do
207
+ provider(:kewlphone) {}
208
+ [/1?4445556666/, /123/, /\d+\*548/].each do |r|
209
+ route r >> kewlphone
210
+ end
211
+ end
212
+ dsl.routes.map { |x| x.patterns }.flatten.should == [/1?4445556666/, /123/, /\d+\*548/]
213
+ end
214
+ end
215
+
216
+ describe "A ProviderDefinition" do
217
+ it "should store any arbitrary property" do
218
+ definition = Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new :foo
219
+ definition.qaz = :something
220
+ definition.qaz.should == :something
221
+ end
222
+ it "should define a >>() method" do
223
+ Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:arghh).should respond_to(:>>)
224
+ end
225
+
226
+ it "should format numbers properly" do
227
+ definition = Adhearsion::VoIP::DSL::DialingDSL::ProviderDefinition.new(:arghh)
228
+ definition.protocol = "SIP"
229
+ definition.format_number_for_platform("14445556666", :asterisk).should == "SIP/arghh/14445556666"
230
+ definition.protocol = "SCCP"
231
+ definition.format_number_for_platform("16663331111", :asterisk).should == "SCCP/arghh/16663331111"
232
+
233
+ end
234
+ end
235
+
236
+ describe "Routing with the interpreted route definitions" do
237
+ it "should use the first matching regular expression" do
238
+ dsl = Class.new Adhearsion::VoIP::DSL::DialingDSL
239
+ dsl.class_eval do
240
+ provider(:bad) {}
241
+ provider(:good) {}
242
+ route /^111$/ | /^222$/ | /^333$/ >> good >> bad
243
+ end
244
+
245
+ found = dsl.calculate_routes_for(333)
246
+
247
+ 1.should be found.size
248
+ found.first.size.should be 2
249
+ end
250
+
251
+ end
252
+
253
+ # @example = Class.new Adhearsion::VoIP::DSL::DialingDSL
254
+ # @example.class_eval do
255
+ #
256
+ # provider:kewlphone do |trunk|
257
+ # trunk.protocol :sip
258
+ # trunk.host "voip.nufone.com"
259
+ # trunk.username "phonedude"
260
+ # trunk.password "secret"
261
+ # trunk.enters :internal
262
+ # end
263
+ #
264
+ # route US_NUMBER | US_LOCAL_NUMBER >> voip_ms >> nufone
265
+ #
266
+ # route INTL_NUMBER >> random(voip_ms, nufone)
267
+ #
268
+ # # route _('NXX') >> DUNDI
269
+ #
270
+ # end
@@ -0,0 +1,82 @@
1
+ require File.dirname(__FILE__) + '/dispatcher_spec_helper'
2
+ require 'adhearsion/voip/dsl/dialplan/dispatcher'
3
+
4
+
5
+ describe "A EventCommand" do
6
+
7
+ it "should allow a block that's set to response_block()" do
8
+ block = lambda {}
9
+ cmd = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "foo", &block
10
+ cmd.response_block.should be(block)
11
+ end
12
+
13
+ it "should return specified return type with returns()" do
14
+ return_type = Numeric
15
+ cmd = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "foo", :returns => return_type
16
+ cmd.returns.should be(return_type)
17
+ end
18
+
19
+ end
20
+
21
+ describe "The abstract CommandDispatcher" do
22
+
23
+ it "should make an attribute reader for context()" do
24
+ context = "foo"
25
+ d = Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher.new String, context
26
+ d.context.should be(context)
27
+ end
28
+
29
+ it "should instantiate a new instance of the specified factory" do
30
+ d = Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher.new Hash
31
+ d.factory.should be_a_kind_of(Hash)
32
+ end
33
+
34
+ it "should pass the context to the factory when instantiating it" do
35
+ context = "shazbot"
36
+ klass = flexmock "a class that has one argument in its constructor"
37
+ klass.should_receive(:new).with(context)
38
+ d = Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher.new klass, context
39
+ end
40
+
41
+ it "should not allow calling dispatch!() directly" do
42
+ dispatcher = Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher.new MyFactory
43
+ lambda do
44
+ dispatcher.dispatch! nil
45
+ end.should raise_error(NotImplementedError)
46
+ end
47
+
48
+ it "should pass a method and any args onto its CommandFactory" do
49
+
50
+ weird_args = [1, 2, ["foo", nil], Object.new, 12.3..13.4]
51
+
52
+ bogus_command = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "123"
53
+
54
+ dispatcher = NilDispatcher.new MyFactory
55
+ flexmock(dispatcher.factory).should_receive(:monkey).with(*weird_args).and_return bogus_command
56
+ dispatcher.monkey(*weird_args)
57
+
58
+ end
59
+
60
+ it "should continue executing response_blocks until nil is returned" do
61
+ actual_executions, target_executions = 0, 5
62
+ response = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "1" do |response|
63
+ if response > target_executions
64
+ nil
65
+ else
66
+ actual_executions += 1
67
+ Adhearsion::VoIP::DSL::Dialplan::EventCommand.new(response + 1)
68
+ end
69
+ end
70
+ mock_factory_class = Class.new do
71
+ def initialize(*args)
72
+ end
73
+ def testplz
74
+ response
75
+ end
76
+ end
77
+ dispatcher = EvalDispatcher.new(mock_factory_class)
78
+ flexmock(dispatcher.factory).should_receive(:testplz).and_return(response)
79
+ dispatcher.testplz
80
+ actual_executions.should be(target_executions)
81
+ end
82
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ require 'adhearsion/voip/dsl/dialplan/dispatcher'
4
+
5
+ module StandardDispatcherBehavior
6
+ def xtest_standard_dispatcher_behavior
7
+ #"This it looks bogus. Not finished? Let's not check in failing specs ever if we can help it."
8
+ returned_event_command = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "ilikesexypants"
9
+ linking_event_command = Adhearsion::VoIP::DSL::Dialplan::EventCommand.new "ihavesexypants" do
10
+ returned_event_command
11
+ end
12
+
13
+ dispatcher = @dispatcher_class.new MyFactory
14
+ dispatcher.should_receive(:dispatch!).with(linking_event_command, returned_event_command).and_return(linking_event_command, returned_event_command)
15
+ # returned_event_command.should_receive(:command_block).and_return nil
16
+ dispatcher.dispatch! linking_event_command
17
+ end
18
+ end
19
+
20
+ class NilDispatcher < Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher
21
+ def dispatch!(string)
22
+ # Would send it off to the PBX here (or prepend something to the String)
23
+ end
24
+ end
25
+
26
+ class EvalDispatcher < Adhearsion::VoIP::DSL::Dialplan::CommandDispatcher
27
+ def dispatch!(event)
28
+ eval event.app.to_s
29
+ end
30
+ end
31
+
32
+ class MyFactory
33
+
34
+ def initialize(context)
35
+ @context = context
36
+ end
37
+
38
+ def sequence
39
+ all = []
40
+ EventCommand.new("2", :response => Numeric) do |response|
41
+ all << response
42
+ all.size > 3 ? all : nil
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ require 'adhearsion/voip/dsl/dialplan/parser'
4
+
5
+ describe "The Adhearsion VoIP dialplan parser" do
6
+
7
+ it "should return a list of dialplans properly from dialplan code" do
8
+ file = "foobar.rb"
9
+ flexstub(Adhearsion::AHN_CONFIG).should_receive(:files_from_setting).once.with("paths", "dialplan").and_return [file]
10
+
11
+ flexmock(File).should_receive(:exists?).with(file).and_return true
12
+ flexmock(File).should_receive(:read).once.with(file).and_return <<-DIALPLAN
13
+ internal {
14
+ play "hello-world"
15
+ }
16
+ monkeys {
17
+ play "tt-monkeys"
18
+ }
19
+ DIALPLAN
20
+ contexts = Adhearsion::VoIP::DSL::Dialplan::DialplanParser.get_contexts
21
+ contexts.keys.size.should be(2)
22
+ contexts.keys.should include(:internal)
23
+ contexts.keys.should include(:monkeys)
24
+ contexts.each_pair do |context, struct|
25
+ struct.should be_a_kind_of(OpenStruct)
26
+ %w"file name block".each do |method|
27
+ struct.should respond_to(method)
28
+ end
29
+ end
30
+ end
31
+
32
+ it "should warn when no dialplan paths were in the .ahnrc file" do
33
+ flexmock(Adhearsion::AHN_CONFIG).should_receive(:files_from_setting).once.with("paths", "dialplan").and_return []
34
+ flexmock(ahn_log.dialplan).should_receive(:warn).once.with(String)
35
+
36
+ # Not loading it here is the same as it not existing in the "paths" sub-Hash
37
+ Adhearsion::VoIP::DSL::Dialplan::DialplanParser.get_contexts
38
+ end
39
+
40
+ end
41
+
42
+ describe "The Adhearsion VoIP dialplan interpreter" do
43
+
44
+ it "should make dialplan contexts available within the context's block" do
45
+ file = "contexts_from_code_helper_pseudo_dialplan.rb"
46
+ flexstub(Adhearsion::AHN_CONFIG).should_receive(:files_from_setting).once.with("paths", "dialplan").and_return [file]
47
+
48
+ flexmock(File).should_receive(:exists?).with(file).and_return true
49
+ flexmock(File).should_receive(:read).with(file).and_return "foo { cool_method }"
50
+
51
+ contexts = Adhearsion::VoIP::DSL::Dialplan::DialplanParser.get_contexts
52
+
53
+ contexts.each_pair do |name, struct|
54
+ contexts.meta_def(name) { struct.code }
55
+ end
56
+
57
+ # Simulate incoming request
58
+ contexts = contexts.clone
59
+
60
+ call_variables = { "callerid" => "14445556666", "context" => "foo" }
61
+
62
+ call_variables.each_pair do |key, value|
63
+ contexts.meta_def(key) { value }
64
+ contexts.instance_variable_set "@#{key}", value
65
+ end
66
+
67
+ end
68
+
69
+ end