punchblock 1.9.4 → 2.0.0.beta1

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -2
  4. data/CHANGELOG.md +17 -0
  5. data/Gemfile +1 -0
  6. data/Guardfile +4 -0
  7. data/README.markdown +6 -0
  8. data/Rakefile +16 -0
  9. data/benchmarks/ami_event_name_comparison.rb +14 -0
  10. data/benchmarks/channel.rb +27 -0
  11. data/lib/punchblock/client.rb +2 -6
  12. data/lib/punchblock/command/accept.rb +3 -24
  13. data/lib/punchblock/command/answer.rb +3 -24
  14. data/lib/punchblock/command/dial.rb +24 -76
  15. data/lib/punchblock/command/hangup.rb +3 -19
  16. data/lib/punchblock/command/join.rb +21 -70
  17. data/lib/punchblock/command/mute.rb +3 -3
  18. data/lib/punchblock/command/redirect.rb +6 -39
  19. data/lib/punchblock/command/reject.rb +14 -54
  20. data/lib/punchblock/command/unjoin.rb +8 -40
  21. data/lib/punchblock/command/unmute.rb +3 -3
  22. data/lib/punchblock/command_node.rb +0 -17
  23. data/lib/punchblock/component/asterisk/agi/command.rb +20 -127
  24. data/lib/punchblock/component/asterisk/ami/action.rb +30 -117
  25. data/lib/punchblock/component/component_node.rb +1 -1
  26. data/lib/punchblock/component/input.rb +89 -268
  27. data/lib/punchblock/component/output.rb +106 -154
  28. data/lib/punchblock/component/prompt.rb +51 -0
  29. data/lib/punchblock/component/record.rb +41 -130
  30. data/lib/punchblock/component.rb +1 -0
  31. data/lib/punchblock/connection/asterisk.rb +31 -4
  32. data/lib/punchblock/connection/xmpp.rb +6 -14
  33. data/lib/punchblock/core_ext/blather/stanza.rb +1 -1
  34. data/lib/punchblock/event/active_speaker.rb +2 -10
  35. data/lib/punchblock/event/answered.rb +3 -3
  36. data/lib/punchblock/event/asterisk/ami/event.rb +15 -47
  37. data/lib/punchblock/event/complete.rb +26 -48
  38. data/lib/punchblock/event/dtmf.rb +3 -13
  39. data/lib/punchblock/event/end.rb +10 -11
  40. data/lib/punchblock/event/joined.rb +5 -25
  41. data/lib/punchblock/event/offer.rb +4 -25
  42. data/lib/punchblock/event/ringing.rb +3 -3
  43. data/lib/punchblock/event/unjoined.rb +5 -25
  44. data/lib/punchblock/event.rb +0 -10
  45. data/lib/punchblock/has_headers.rb +20 -26
  46. data/lib/punchblock/rayo_node.rb +46 -23
  47. data/lib/punchblock/ref.rb +39 -18
  48. data/lib/punchblock/translator/asterisk/agi_app.rb +15 -0
  49. data/lib/punchblock/translator/asterisk/agi_command.rb +3 -1
  50. data/lib/punchblock/translator/asterisk/ami_error_converter.rb +20 -0
  51. data/lib/punchblock/translator/asterisk/call.rb +60 -39
  52. data/lib/punchblock/translator/asterisk/channel.rb +41 -0
  53. data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +4 -1
  54. data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +4 -4
  55. data/lib/punchblock/translator/asterisk/component/composed_prompt.rb +62 -0
  56. data/lib/punchblock/translator/asterisk/component/input.rb +1 -0
  57. data/lib/punchblock/translator/asterisk/component/mrcp_native_prompt.rb +56 -0
  58. data/lib/punchblock/translator/asterisk/component/mrcp_prompt.rb +53 -0
  59. data/lib/punchblock/translator/asterisk/component/mrcp_recog_prompt.rb +99 -0
  60. data/lib/punchblock/translator/asterisk/component/output.rb +30 -22
  61. data/lib/punchblock/translator/asterisk/component/record.rb +8 -6
  62. data/lib/punchblock/translator/asterisk/component.rb +6 -5
  63. data/lib/punchblock/translator/asterisk/unimrcp_app.rb +26 -0
  64. data/lib/punchblock/translator/asterisk.rb +24 -28
  65. data/lib/punchblock/translator/dtmf_recognizer.rb +39 -20
  66. data/lib/punchblock/translator/freeswitch/call.rb +15 -14
  67. data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +5 -4
  68. data/lib/punchblock/translator/freeswitch/component/flite_output.rb +1 -1
  69. data/lib/punchblock/translator/freeswitch/component/input.rb +5 -0
  70. data/lib/punchblock/translator/freeswitch/component/output.rb +2 -2
  71. data/lib/punchblock/translator/freeswitch/component/record.rb +19 -13
  72. data/lib/punchblock/translator/freeswitch/component/tts_output.rb +2 -2
  73. data/lib/punchblock/translator/freeswitch/component.rb +2 -5
  74. data/lib/punchblock/translator/freeswitch.rb +2 -2
  75. data/lib/punchblock/translator/input_component.rb +33 -13
  76. data/lib/punchblock/uri_list.rb +21 -0
  77. data/lib/punchblock/version.rb +1 -1
  78. data/lib/punchblock.rb +4 -3
  79. data/punchblock.gemspec +7 -3
  80. data/spec/punchblock/client/component_registry_spec.rb +1 -1
  81. data/spec/punchblock/client_spec.rb +10 -26
  82. data/spec/punchblock/command/accept_spec.rb +41 -7
  83. data/spec/punchblock/command/answer_spec.rb +51 -7
  84. data/spec/punchblock/command/dial_spec.rb +56 -14
  85. data/spec/punchblock/command/hangup_spec.rb +41 -7
  86. data/spec/punchblock/command/join_spec.rb +53 -11
  87. data/spec/punchblock/command/mute_spec.rb +19 -4
  88. data/spec/punchblock/command/redirect_spec.rb +40 -10
  89. data/spec/punchblock/command/reject_spec.rb +43 -11
  90. data/spec/punchblock/command/unjoin_spec.rb +40 -9
  91. data/spec/punchblock/command/unmute_spec.rb +19 -4
  92. data/spec/punchblock/command_node_spec.rb +0 -4
  93. data/spec/punchblock/component/asterisk/agi/command_spec.rb +16 -39
  94. data/spec/punchblock/component/asterisk/ami/action_spec.rb +50 -53
  95. data/spec/punchblock/component/component_node_spec.rb +3 -5
  96. data/spec/punchblock/component/input_spec.rb +194 -61
  97. data/spec/punchblock/component/output_spec.rb +194 -62
  98. data/spec/punchblock/component/prompt_spec.rb +132 -0
  99. data/spec/punchblock/component/record_spec.rb +70 -32
  100. data/spec/punchblock/connection/asterisk_spec.rb +17 -3
  101. data/spec/punchblock/connection/freeswitch_spec.rb +4 -4
  102. data/spec/punchblock/connection/xmpp_spec.rb +20 -38
  103. data/spec/punchblock/event/answered_spec.rb +12 -10
  104. data/spec/punchblock/event/asterisk/ami/event_spec.rb +27 -22
  105. data/spec/punchblock/event/complete_spec.rb +15 -19
  106. data/spec/punchblock/event/dtmf_spec.rb +5 -6
  107. data/spec/punchblock/event/end_spec.rb +20 -10
  108. data/spec/punchblock/event/joined_spec.rb +8 -7
  109. data/spec/punchblock/event/offer_spec.rb +41 -12
  110. data/spec/punchblock/event/ringing_spec.rb +12 -10
  111. data/spec/punchblock/event/started_speaking_spec.rb +5 -6
  112. data/spec/punchblock/event/stopped_speaking_spec.rb +5 -6
  113. data/spec/punchblock/event/unjoined_spec.rb +7 -7
  114. data/spec/punchblock/ref_spec.rb +86 -9
  115. data/spec/punchblock/translator/asterisk/call_spec.rb +317 -154
  116. data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +28 -5
  117. data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +15 -13
  118. data/spec/punchblock/translator/asterisk/component/composed_prompt_spec.rb +237 -0
  119. data/spec/punchblock/translator/asterisk/component/input_spec.rb +171 -14
  120. data/spec/punchblock/translator/asterisk/component/mrcp_native_prompt_spec.rb +652 -0
  121. data/spec/punchblock/translator/asterisk/component/mrcp_prompt_spec.rb +646 -0
  122. data/spec/punchblock/translator/asterisk/component/output_spec.rb +127 -77
  123. data/spec/punchblock/translator/asterisk/component/record_spec.rb +17 -8
  124. data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +2 -2
  125. data/spec/punchblock/translator/asterisk/component_spec.rb +3 -7
  126. data/spec/punchblock/translator/asterisk_spec.rb +20 -24
  127. data/spec/punchblock/translator/freeswitch/call_spec.rb +103 -99
  128. data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +17 -8
  129. data/spec/punchblock/translator/freeswitch/component/input_spec.rb +26 -14
  130. data/spec/punchblock/translator/freeswitch/component/output_spec.rb +30 -52
  131. data/spec/punchblock/translator/freeswitch/component/record_spec.rb +23 -19
  132. data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +18 -8
  133. data/spec/punchblock/translator/freeswitch/component_spec.rb +4 -8
  134. data/spec/punchblock/translator/freeswitch_spec.rb +11 -14
  135. data/spec/punchblock/uri_list_spec.rb +49 -0
  136. data/spec/punchblock_spec.rb +11 -1
  137. data/spec/spec_helper.rb +7 -11
  138. data/spec/support/mock_connection_with_event_handler.rb +1 -1
  139. metadata +104 -24
  140. data/lib/punchblock/header.rb +0 -9
  141. data/lib/punchblock/key_value_pair_node.rb +0 -51
  142. data/spec/punchblock/header_spec.rb +0 -11
@@ -6,18 +6,52 @@ module Punchblock
6
6
  module Command
7
7
  describe Hangup do
8
8
  it 'registers itself' do
9
- RayoNode.class_from_registration(:hangup, 'urn:xmpp:rayo:1').should be == Hangup
9
+ RayoNode.class_from_registration(:hangup, 'urn:xmpp:rayo:1').should be == described_class
10
10
  end
11
11
 
12
- it_should_behave_like 'command_headers'
13
-
14
12
  describe "from a stanza" do
15
- let(:stanza) { '<hangup xmlns="urn:xmpp:rayo:1"/>' }
13
+ let(:stanza) do
14
+ <<-STANZA
15
+ <hangup xmlns="urn:xmpp:rayo:1">
16
+ <header name="X-skill" value="agent" />
17
+ <header name="X-customer-id" value="8877" />
18
+ </hangup>
19
+ STANZA
20
+ end
21
+
22
+ subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
23
+
24
+ it { should be_instance_of described_class }
25
+ its(:headers) { should == { 'X-skill' => 'agent', 'X-customer-id' => '8877' } }
26
+
27
+ context "with no headers provided" do
28
+ let(:stanza) { '<hangup xmlns="urn:xmpp:rayo:1"/>' }
29
+
30
+ its(:headers) { should == {} }
31
+ end
32
+ end
33
+
34
+ describe "when setting options in initializer" do
35
+ subject { described_class.new headers: { 'X-skill' => 'agent', 'X-customer-id' => '8877' } }
36
+
37
+ its(:headers) { should == { 'X-skill' => 'agent', 'X-customer-id' => '8877' } }
16
38
 
17
- subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
39
+ describe "exporting to Rayo" do
40
+ it "should export to XML that can be understood by its parser" do
41
+ new_instance = RayoNode.from_xml subject.to_rayo
42
+ new_instance.should be_instance_of described_class
43
+ new_instance.headers.should == { 'X-skill' => 'agent', 'X-customer-id' => '8877' }
44
+ end
18
45
 
19
- it { should be_instance_of Hangup }
46
+ it "should render to a parent node if supplied" do
47
+ doc = Nokogiri::XML::Document.new
48
+ parent = Nokogiri::XML::Node.new 'foo', doc
49
+ doc.root = parent
50
+ rayo_doc = subject.to_rayo(parent)
51
+ rayo_doc.should == parent
52
+ end
53
+ end
20
54
  end
21
55
  end
22
56
  end
23
- end # Punchblock
57
+ end
@@ -5,59 +5,101 @@ require 'spec_helper'
5
5
  module Punchblock
6
6
  module Command
7
7
  describe Join do
8
-
9
8
  it 'registers itself' do
10
- RayoNode.class_from_registration(:join, 'urn:xmpp:rayo:1').should be == Join
9
+ RayoNode.class_from_registration(:join, 'urn:xmpp:rayo:1').should be == described_class
11
10
  end
12
11
 
13
12
  describe "when setting options in initializer" do
14
- subject { Join.new :call_id => 'abc123', :mixer_name => 'blah', :direction => :duplex, :media => :bridge }
13
+ subject { described_class.new :call_uri => 'abc123', :mixer_name => 'blah', :direction => :duplex, :media => :bridge }
15
14
 
16
- its(:call_id) { should be == 'abc123' }
15
+ its(:call_uri) { should be == 'abc123' }
17
16
  its(:mixer_name) { should be == 'blah' }
18
17
  its(:direction) { should be == :duplex }
19
18
  its(:media) { should be == :bridge }
19
+
20
+ context "with old call_id attribute" do
21
+ subject { described_class.new call_id: 'abc123' }
22
+
23
+ its(:call_uri) { should be == 'abc123' }
24
+ end
25
+
26
+ describe "exporting to Rayo" do
27
+ it "should export to XML that can be understood by its parser" do
28
+ new_instance = RayoNode.from_xml subject.to_rayo
29
+ new_instance.should be_instance_of described_class
30
+ new_instance.call_uri.should == 'abc123'
31
+ new_instance.mixer_name.should == 'blah'
32
+ new_instance.direction.should == :duplex
33
+ new_instance.media.should == :bridge
34
+ end
35
+
36
+ it "should render to a parent node if supplied" do
37
+ doc = Nokogiri::XML::Document.new
38
+ parent = Nokogiri::XML::Node.new 'foo', doc
39
+ doc.root = parent
40
+ rayo_doc = subject.to_rayo(parent)
41
+ rayo_doc.should == parent
42
+ end
43
+
44
+ context "when attributes are not set" do
45
+ subject { described_class.new call_uri: 'abc123' }
46
+
47
+ it "should not include them in the XML representation" do
48
+ subject.to_rayo['call-uri'].should == 'abc123'
49
+ subject.to_rayo['mixer-name'].should be_nil
50
+ end
51
+ end
52
+ end
20
53
  end
21
54
 
22
55
  describe "from a stanza" do
23
56
  let :stanza do
24
57
  <<-MESSAGE
25
58
  <join xmlns="urn:xmpp:rayo:1"
26
- call-id="abc123"
59
+ call-uri="abc123"
27
60
  mixer-name="blah"
28
61
  direction="duplex"
29
62
  media="bridge" />
30
63
  MESSAGE
31
64
  end
32
65
 
33
- subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
66
+ subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
34
67
 
35
- it { should be_instance_of Join }
68
+ it { should be_instance_of described_class }
36
69
 
37
- its(:call_id) { should be == 'abc123' }
70
+ its(:call_uri) { should be == 'abc123' }
38
71
  its(:mixer_name) { should be == 'blah' }
39
72
  its(:direction) { should be == :duplex }
40
73
  its(:media) { should be == :bridge }
74
+
75
+ context "when no attributes are set" do
76
+ let(:stanza) { '<join xmlns="urn:xmpp:rayo:1" />' }
77
+
78
+ its(:call_uri) { should be_nil }
79
+ its(:mixer_name) { should be_nil }
80
+ its(:direction) { should be_nil }
81
+ its(:media) { should be_nil }
82
+ end
41
83
  end
42
84
 
43
85
  describe "with a direction" do
44
86
  [nil, :duplex, :send, :recv].each do |direction|
45
87
  describe direction do
46
- subject { Join.new :direction => direction }
88
+ subject { described_class.new :direction => direction }
47
89
 
48
90
  its(:direction) { should be == direction }
49
91
  end
50
92
  end
51
93
 
52
94
  describe "no direction" do
53
- subject { Join.new }
95
+ subject { described_class.new }
54
96
 
55
97
  its(:direction) { should be_nil }
56
98
  end
57
99
 
58
100
  describe "blahblahblah" do
59
101
  it "should raise an error" do
60
- expect { Join.new(:direction => :blahblahblah) }.to raise_error ArgumentError
102
+ expect { described_class.new(:direction => :blahblahblah) }.to raise_error ArgumentError
61
103
  end
62
104
  end
63
105
  end
@@ -6,16 +6,31 @@ module Punchblock
6
6
  module Command
7
7
  describe Mute do
8
8
  it 'registers itself' do
9
- RayoNode.class_from_registration(:mute, 'urn:xmpp:rayo:1').should be == Mute
9
+ RayoNode.class_from_registration(:mute, 'urn:xmpp:rayo:1').should be == described_class
10
10
  end
11
11
 
12
12
  describe "from a stanza" do
13
13
  let(:stanza) { '<mute xmlns="urn:xmpp:rayo:1"/>' }
14
14
 
15
- subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
15
+ subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
16
16
 
17
- it { should be_instance_of Mute }
17
+ it { should be_instance_of described_class }
18
+ end
19
+
20
+ describe "exporting to Rayo" do
21
+ it "should export to XML that can be understood by its parser" do
22
+ new_instance = RayoNode.from_xml subject.to_rayo
23
+ new_instance.should be_instance_of described_class
24
+ end
25
+
26
+ it "should render to a parent node if supplied" do
27
+ doc = Nokogiri::XML::Document.new
28
+ parent = Nokogiri::XML::Node.new 'foo', doc
29
+ doc.root = parent
30
+ rayo_doc = subject.to_rayo(parent)
31
+ rayo_doc.should == parent
32
+ end
18
33
  end
19
34
  end
20
35
  end
21
- end # Punchblock
36
+ end
@@ -6,15 +6,39 @@ module Punchblock
6
6
  module Command
7
7
  describe Redirect do
8
8
  it 'registers itself' do
9
- RayoNode.class_from_registration(:redirect, 'urn:xmpp:rayo:1').should be == Redirect
9
+ RayoNode.class_from_registration(:redirect, 'urn:xmpp:rayo:1').should be == described_class
10
10
  end
11
11
 
12
12
  describe "when setting options in initializer" do
13
- subject { Redirect.new :to => 'tel:+14045551234', :headers => { :x_skill => 'agent', :x_customer_id => 8877 } }
14
-
15
- it_should_behave_like 'command_headers'
13
+ subject { described_class.new to: 'tel:+14045551234', headers: { 'X-skill' => 'agent', 'X-customer-id' => '8877' } }
16
14
 
17
15
  its(:to) { should be == 'tel:+14045551234' }
16
+ its(:headers) { should == { 'X-skill' => 'agent', 'X-customer-id' => '8877' } }
17
+
18
+ describe "exporting to Rayo" do
19
+ it "should export to XML that can be understood by its parser" do
20
+ new_instance = RayoNode.from_xml subject.to_rayo
21
+ new_instance.should be_instance_of described_class
22
+ new_instance.to.should == 'tel:+14045551234'
23
+ new_instance.headers.should == { 'X-skill' => 'agent', 'X-customer-id' => '8877' }
24
+ end
25
+
26
+ it "should render to a parent node if supplied" do
27
+ doc = Nokogiri::XML::Document.new
28
+ parent = Nokogiri::XML::Node.new 'foo', doc
29
+ doc.root = parent
30
+ rayo_doc = subject.to_rayo(parent)
31
+ rayo_doc.should == parent
32
+ end
33
+
34
+ context "when attributes are not set" do
35
+ subject { described_class.new }
36
+
37
+ it "should not include them in the XML representation" do
38
+ subject.to_rayo['to'].should be_nil
39
+ end
40
+ end
41
+ end
18
42
  end
19
43
 
20
44
  describe "from a stanza" do
@@ -23,19 +47,25 @@ module Punchblock
23
47
  <redirect xmlns='urn:xmpp:rayo:1'
24
48
  to='tel:+14045551234'>
25
49
  <!-- Signaling (e.g. SIP) Headers -->
26
- <header name="x-skill" value="agent" />
27
- <header name="x-customer-id" value="8877" />
50
+ <header name="X-skill" value="agent" />
51
+ <header name="X-customer-id" value="8877" />
28
52
  </redirect>
29
53
  MESSAGE
30
54
  end
31
55
 
32
- subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
33
-
34
- it { should be_instance_of Redirect }
56
+ subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
35
57
 
36
- it_should_behave_like 'command_headers'
58
+ it { should be_instance_of described_class }
37
59
 
38
60
  its(:to) { should be == 'tel:+14045551234' }
61
+ its(:headers) { should == { 'X-skill' => 'agent', 'X-customer-id' => '8877' } }
62
+
63
+ context "with no headers or to provided" do
64
+ let(:stanza) { '<redirect xmlns="urn:xmpp:rayo:1"/>' }
65
+
66
+ its(:to) { should be_nil }
67
+ its(:headers) { should == {} }
68
+ end
39
69
  end
40
70
  end # Redirect
41
71
  end # Command
@@ -6,15 +6,39 @@ module Punchblock
6
6
  module Command
7
7
  describe Reject do
8
8
  it 'registers itself' do
9
- RayoNode.class_from_registration(:reject, 'urn:xmpp:rayo:1').should be == Reject
9
+ RayoNode.class_from_registration(:reject, 'urn:xmpp:rayo:1').should be == described_class
10
10
  end
11
11
 
12
12
  describe "when setting options in initializer" do
13
- subject { Reject.new :reason => :busy, :headers => { :x_skill => 'agent', :x_customer_id => 8877 } }
14
-
15
- it_should_behave_like 'command_headers'
13
+ subject { described_class.new reason: :busy, headers: { 'X-skill' => 'agent', 'X-customer-id' => '8877' } }
16
14
 
17
15
  its(:reason) { should be == :busy }
16
+ its(:headers) { should == { 'X-skill' => 'agent', 'X-customer-id' => '8877' } }
17
+
18
+ describe "exporting to Rayo" do
19
+ it "should export to XML that can be understood by its parser" do
20
+ new_instance = RayoNode.from_xml subject.to_rayo
21
+ new_instance.should be_instance_of described_class
22
+ new_instance.reason.should == :busy
23
+ new_instance.headers.should == { 'X-skill' => 'agent', 'X-customer-id' => '8877' }
24
+ end
25
+
26
+ it "should render to a parent node if supplied" do
27
+ doc = Nokogiri::XML::Document.new
28
+ parent = Nokogiri::XML::Node.new 'foo', doc
29
+ doc.root = parent
30
+ rayo_doc = subject.to_rayo(parent)
31
+ rayo_doc.should == parent
32
+ end
33
+
34
+ context "when attributes are not set" do
35
+ subject { described_class.new }
36
+
37
+ it "should not include them in the XML representation" do
38
+ subject.to_rayo.children.count.should == 0
39
+ end
40
+ end
41
+ end
18
42
  end
19
43
 
20
44
  describe "from a stanza" do
@@ -23,37 +47,45 @@ module Punchblock
23
47
  <reject xmlns='urn:xmpp:rayo:1'>
24
48
  <busy />
25
49
  <!-- Sample Headers (optional) -->
26
- <header name="x-reason-internal" value="bad-skill" />
50
+ <header name="X-skill" value="agent" />
51
+ <header name="X-customer-id" value="8877" />
27
52
  </reject>
28
53
  MESSAGE
29
54
  end
30
55
 
31
- subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
56
+ subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
32
57
 
33
- it { should be_instance_of Reject }
58
+ it { should be_instance_of described_class }
34
59
 
35
60
  its(:reason) { should be == :busy }
36
- its(:headers_hash) { should be == { :x_reason_internal => 'bad-skill' } }
61
+ its(:headers) { should == { 'X-skill' => 'agent', 'X-customer-id' => '8877' } }
62
+
63
+ context "with no headers or reason provided" do
64
+ let(:stanza) { '<reject xmlns="urn:xmpp:rayo:1"/>' }
65
+
66
+ its(:reason) { should be_nil }
67
+ its(:headers) { should == {} }
68
+ end
37
69
  end
38
70
 
39
71
  describe "with the reason" do
40
72
  [nil, :decline, :busy, :error].each do |reason|
41
73
  describe reason do
42
- subject { Reject.new :reason => reason }
74
+ subject { described_class.new :reason => reason }
43
75
 
44
76
  its(:reason) { should be == reason }
45
77
  end
46
78
  end
47
79
 
48
80
  describe "no reason" do
49
- subject { Reject.new }
81
+ subject { described_class.new }
50
82
 
51
83
  its(:reason) { should be_nil }
52
84
  end
53
85
 
54
86
  describe "blahblahblah" do
55
87
  it "should raise an error" do
56
- expect { Reject.new(:reason => :blahblahblah) }.to raise_error ArgumentError
88
+ expect { described_class.new(:reason => :blahblahblah) }.to raise_error ArgumentError
57
89
  end
58
90
  end
59
91
  end
@@ -5,34 +5,65 @@ require 'spec_helper'
5
5
  module Punchblock
6
6
  module Command
7
7
  describe Unjoin do
8
-
9
8
  it 'registers itself' do
10
- RayoNode.class_from_registration(:unjoin, 'urn:xmpp:rayo:1').should be == Unjoin
9
+ RayoNode.class_from_registration(:unjoin, 'urn:xmpp:rayo:1').should be == described_class
11
10
  end
12
11
 
13
12
  describe "when setting options in initializer" do
14
- subject { Unjoin.new :call_id => 'abc123', :mixer_name => 'blah' }
13
+ subject { Unjoin.new :call_uri => 'abc123', :mixer_name => 'blah' }
15
14
 
16
- its(:call_id) { should be == 'abc123' }
15
+ its(:call_uri) { should be == 'abc123' }
17
16
  its(:mixer_name) { should be == 'blah' }
17
+
18
+ context "with old call_id attribute" do
19
+ subject { described_class.new call_id: 'abc123' }
20
+
21
+ its(:call_uri) { should be == 'abc123' }
22
+ end
23
+
24
+ describe "exporting to Rayo" do
25
+ it "should export to XML that can be understood by its parser" do
26
+ new_instance = RayoNode.from_xml subject.to_rayo
27
+ new_instance.should be_instance_of described_class
28
+ new_instance.call_uri.should == 'abc123'
29
+ new_instance.mixer_name.should == 'blah'
30
+ end
31
+
32
+ it "should render to a parent node if supplied" do
33
+ doc = Nokogiri::XML::Document.new
34
+ parent = Nokogiri::XML::Node.new 'foo', doc
35
+ doc.root = parent
36
+ rayo_doc = subject.to_rayo(parent)
37
+ rayo_doc.should == parent
38
+ end
39
+
40
+ context "when attributes are not set" do
41
+ subject { described_class.new call_uri: 'abc123' }
42
+
43
+ it "should not include them in the XML representation" do
44
+ subject.to_rayo['call-uri'].should == 'abc123'
45
+ subject.to_rayo['mixer-name'].should be_nil
46
+ end
47
+ end
48
+ end
18
49
  end
19
50
 
20
51
  describe "from a stanza" do
21
52
  let :stanza do
22
53
  <<-MESSAGE
23
54
  <unjoin xmlns="urn:xmpp:rayo:1"
24
- call-id="abc123"
55
+ call-uri="abc123"
25
56
  mixer-name="blah" />
26
57
  MESSAGE
27
58
  end
28
59
 
29
- subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
60
+ subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
30
61
 
31
- it { should be_instance_of Unjoin }
62
+ it { should be_instance_of described_class }
32
63
 
33
- its(:call_id) { should be == 'abc123' }
64
+ its(:call_uri) { should be == 'abc123' }
34
65
  its(:mixer_name) { should be == 'blah' }
35
66
  end
36
67
  end
37
68
  end
38
- end # Punchblock
69
+ end
@@ -6,16 +6,31 @@ module Punchblock
6
6
  module Command
7
7
  describe Unmute do
8
8
  it 'registers itself' do
9
- RayoNode.class_from_registration(:unmute, 'urn:xmpp:rayo:1').should be == Unmute
9
+ RayoNode.class_from_registration(:unmute, 'urn:xmpp:rayo:1').should be == described_class
10
10
  end
11
11
 
12
12
  describe "from a stanza" do
13
13
  let(:stanza) { '<unmute xmlns="urn:xmpp:rayo:1"/>' }
14
14
 
15
- subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
15
+ subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
16
16
 
17
- it { should be_instance_of Unmute }
17
+ it { should be_instance_of described_class }
18
+ end
19
+
20
+ describe "exporting to Rayo" do
21
+ it "should export to XML that can be understood by its parser" do
22
+ new_instance = RayoNode.from_xml subject.to_rayo
23
+ new_instance.should be_instance_of described_class
24
+ end
25
+
26
+ it "should render to a parent node if supplied" do
27
+ doc = Nokogiri::XML::Document.new
28
+ parent = Nokogiri::XML::Node.new 'foo', doc
29
+ doc.root = parent
30
+ rayo_doc = subject.to_rayo(parent)
31
+ rayo_doc.should == parent
32
+ end
18
33
  end
19
34
  end
20
35
  end
21
- end # Punchblock
36
+ end
@@ -31,10 +31,6 @@ module Punchblock
31
31
  it "should raise a StateMachine::InvalidTransition when received a second time" do
32
32
  lambda { subject.request! }.should raise_error(StateMachine::InvalidTransition)
33
33
  end
34
-
35
- it "should prevent altering attributes" do
36
- lambda { subject.write_attr :foo, 'bar' }.should raise_error(StandardError, "Cannot alter attributes of a requested command")
37
- end
38
34
  end
39
35
 
40
36
  describe "#execute!" do
@@ -8,7 +8,7 @@ module Punchblock
8
8
  module AGI
9
9
  describe Command do
10
10
  it 'registers itself' do
11
- RayoNode.class_from_registration(:command, 'urn:xmpp:rayo:asterisk:agi:1').should be == Command
11
+ RayoNode.class_from_registration(:command, 'urn:xmpp:rayo:asterisk:agi:1').should be == described_class
12
12
  end
13
13
 
14
14
  describe "from a stanza" do
@@ -20,50 +20,27 @@ module Punchblock
20
20
  MESSAGE
21
21
  end
22
22
 
23
- subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
23
+ subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
24
24
 
25
25
  it { should be_instance_of Command }
26
26
 
27
27
  it_should_behave_like 'event'
28
28
 
29
- its(:name) { should be == 'GET VARIABLE' }
30
- its(:params) { should be == [Command::Param.new('UNIQUEID')] }
31
- its(:params_array) { should be == ['UNIQUEID'] }
29
+ its(:name) { should be == 'GET VARIABLE' }
30
+ its(:params) { should be == ['UNIQUEID'] }
32
31
  end
33
32
 
34
33
  describe "when setting options in initializer" do
35
34
  subject do
36
- Command.new :name => 'GET VARIABLE',
37
- :params => ['UNIQUEID']
35
+ described_class.new name: 'GET VARIABLE',
36
+ params: ['UNIQUEID']
38
37
  end
39
38
 
40
- its(:name) { should be == 'GET VARIABLE' }
41
- its(:params) { should be == [Command::Param.new('UNIQUEID')] }
42
- its(:params_array) { should be == ['UNIQUEID'] }
39
+ its(:name) { should be == 'GET VARIABLE' }
40
+ its(:params) { should be == ['UNIQUEID'] }
43
41
  end
44
42
 
45
43
  class Command
46
- describe Param do
47
- it 'will auto-inherit nodes' do
48
- n = parse_stanza "<param value='bah' />"
49
- h = Param.new n.root
50
- h.value.should be == 'bah'
51
- end
52
-
53
- it 'has a value attribute' do
54
- n = Param.new 'en'
55
- n.value.should be == 'en'
56
- n.value = 'de'
57
- n.value.should be == 'de'
58
- end
59
-
60
- it 'can determine equality' do
61
- a = Param.new 'bah'
62
- a.should be == Param.new('bah')
63
- a.should_not be == Param.new('boo')
64
- end
65
- end
66
-
67
44
  describe Complete::Success do
68
45
  let :stanza do
69
46
  <<-MESSAGE
@@ -77,9 +54,9 @@ module Punchblock
77
54
  MESSAGE
78
55
  end
79
56
 
80
- subject { RayoNode.import(parse_stanza(stanza).root).reason }
57
+ subject { RayoNode.from_xml(parse_stanza(stanza).root).reason }
81
58
 
82
- it { should be_instance_of Complete::Success }
59
+ it { should be_instance_of described_class }
83
60
 
84
61
  its(:name) { should be == :success }
85
62
  its(:code) { should be == 200 }
@@ -88,7 +65,7 @@ module Punchblock
88
65
 
89
66
  describe "when setting options in initializer" do
90
67
  subject do
91
- Complete::Success.new :code => 200, :result => 0, :data => '1187188485.0'
68
+ Complete::Success.new code: 200, result: 0, data: '1187188485.0'
92
69
  end
93
70
 
94
71
  its(:code) { should be == 200 }
@@ -97,8 +74,8 @@ module Punchblock
97
74
  end
98
75
  end
99
76
  end
100
- end # Command
101
- end # AGI
102
- end # Asterisk
103
- end # Component
104
- end # Punchblock
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end