punchblock 0.5.1 → 0.6.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.
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +3 -1
- data/bin/punchblock-console +19 -1
- data/lib/punchblock.rb +11 -4
- data/lib/punchblock/command/reject.rb +6 -2
- data/lib/punchblock/component.rb +1 -0
- data/lib/punchblock/component/asterisk.rb +10 -0
- data/lib/punchblock/component/asterisk/agi.rb +11 -0
- data/lib/punchblock/component/asterisk/agi/command.rb +157 -0
- data/lib/punchblock/component/asterisk/ami.rb +12 -0
- data/lib/punchblock/component/asterisk/ami/action.rb +144 -0
- data/lib/punchblock/component/input.rb +2 -2
- data/lib/punchblock/connection.rb +1 -0
- data/lib/punchblock/connection/asterisk.rb +31 -0
- data/lib/punchblock/core_ext/celluloid.rb +11 -0
- data/lib/punchblock/event.rb +1 -1
- data/lib/punchblock/event/asterisk.rb +9 -0
- data/lib/punchblock/event/asterisk/ami.rb +11 -0
- data/lib/punchblock/event/asterisk/ami/event.rb +66 -0
- data/lib/punchblock/event/complete.rb +20 -0
- data/lib/punchblock/event/dtmf.rb +19 -0
- data/lib/punchblock/event/end.rb +23 -0
- data/lib/punchblock/event/offer.rb +23 -0
- data/lib/punchblock/header.rb +4 -44
- data/lib/punchblock/key_value_pair_node.rb +50 -0
- data/lib/punchblock/rayo_node.rb +1 -1
- data/lib/punchblock/ref.rb +6 -0
- data/lib/punchblock/translator.rb +7 -0
- data/lib/punchblock/translator/asterisk.rb +74 -0
- data/lib/punchblock/translator/asterisk/ami_action.rb +86 -0
- data/lib/punchblock/translator/asterisk/call.rb +25 -0
- data/lib/punchblock/translator/asterisk/component.rb +11 -0
- data/lib/punchblock/version.rb +1 -1
- data/punchblock.gemspec +3 -1
- data/spec/punchblock/command/accept_spec.rb +8 -0
- data/spec/punchblock/command/answer_spec.rb +8 -0
- data/spec/punchblock/command/dial_spec.rb +22 -2
- data/spec/punchblock/command/hangup_spec.rb +8 -0
- data/spec/punchblock/command/join_spec.rb +21 -0
- data/spec/punchblock/command/mute_spec.rb +8 -0
- data/spec/punchblock/command/redirect_spec.rb +21 -0
- data/spec/punchblock/command/reject_spec.rb +19 -8
- data/spec/punchblock/command/unjoin_spec.rb +17 -0
- data/spec/punchblock/command/unmute_spec.rb +8 -0
- data/spec/punchblock/component/asterisk/agi/command_spec.rb +102 -0
- data/spec/punchblock/component/asterisk/ami/action_spec.rb +118 -0
- data/spec/punchblock/component/input_spec.rb +40 -0
- data/spec/punchblock/component/output_spec.rb +28 -0
- data/spec/punchblock/component/record_spec.rb +27 -0
- data/spec/punchblock/connection/asterisk_spec.rb +69 -0
- data/spec/punchblock/event/asterisk/ami/event_spec.rb +60 -0
- data/spec/punchblock/event/complete_spec.rb +8 -0
- data/spec/punchblock/event/dtmf_spec.rb +8 -0
- data/spec/punchblock/event/end_spec.rb +8 -0
- data/spec/punchblock/event/offer_spec.rb +15 -2
- data/spec/punchblock/ref_spec.rb +6 -0
- data/spec/punchblock/translator/asterisk/ami_action_spec.rb +149 -0
- data/spec/punchblock/translator/asterisk/call_spec.rb +18 -0
- data/spec/punchblock/translator/asterisk/component_spec.rb +11 -0
- data/spec/punchblock/translator/asterisk_spec.rb +150 -0
- data/spec/spec_helper.rb +42 -0
- metadata +92 -42
- data/lib/punchblock/event/info.rb +0 -15
- data/spec/punchblock/event/info_spec.rb +0 -30
|
@@ -75,6 +75,14 @@ module Punchblock
|
|
|
75
75
|
|
|
76
76
|
its(:name) { should == :error }
|
|
77
77
|
its(:details) { should == "Something really bad happened" }
|
|
78
|
+
|
|
79
|
+
describe "when setting options in initializer" do
|
|
80
|
+
subject do
|
|
81
|
+
Complete::Error.new :details => 'Ooops'
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
its(:details) { should == 'Ooops' }
|
|
85
|
+
end
|
|
78
86
|
end
|
|
79
87
|
end
|
|
80
88
|
end # Punchblock
|
|
@@ -19,6 +19,14 @@ module Punchblock
|
|
|
19
19
|
its(:signal) { should == '#' }
|
|
20
20
|
its(:xmlns) { should == 'urn:xmpp:rayo:1' }
|
|
21
21
|
end
|
|
22
|
+
|
|
23
|
+
describe "when setting options in initializer" do
|
|
24
|
+
subject do
|
|
25
|
+
DTMF.new :signal => '#'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
its(:signal) { should == '#' }
|
|
29
|
+
end
|
|
22
30
|
end
|
|
23
31
|
end
|
|
24
32
|
end # Punchblock
|
|
@@ -25,6 +25,14 @@ module Punchblock
|
|
|
25
25
|
its(:reason) { should == :timeout }
|
|
26
26
|
its(:xmlns) { should == 'urn:xmpp:rayo:1' }
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
describe "when setting options in initializer" do
|
|
30
|
+
subject do
|
|
31
|
+
End.new :reason => :hangup
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
its(:reason) { should == :hangup }
|
|
35
|
+
end
|
|
28
36
|
end
|
|
29
37
|
end
|
|
30
38
|
end # Punchblock
|
|
@@ -27,8 +27,21 @@ module Punchblock
|
|
|
27
27
|
it_should_behave_like 'event'
|
|
28
28
|
it_should_behave_like 'event_headers'
|
|
29
29
|
|
|
30
|
-
its(:to)
|
|
31
|
-
its(:from)
|
|
30
|
+
its(:to) { should == 'tel:+18003211212' }
|
|
31
|
+
its(:from) { should == 'tel:+13058881212' }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "when setting options in initializer" do
|
|
35
|
+
subject do
|
|
36
|
+
Offer.new :to => 'tel:+18003211212',
|
|
37
|
+
:from => 'tel:+13058881212',
|
|
38
|
+
:headers => { :x_skill => "agent", :x_customer_id => "8877" }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it_should_behave_like 'event_headers'
|
|
42
|
+
|
|
43
|
+
its(:to) { should == 'tel:+18003211212' }
|
|
44
|
+
its(:from) { should == 'tel:+13058881212' }
|
|
32
45
|
end
|
|
33
46
|
end
|
|
34
47
|
end
|
data/spec/punchblock/ref_spec.rb
CHANGED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
module Translator
|
|
5
|
+
class Asterisk
|
|
6
|
+
describe AMIAction do
|
|
7
|
+
let(:mock_ami_client) { mock 'RubyAMI::Client' }
|
|
8
|
+
|
|
9
|
+
let :command do
|
|
10
|
+
Punchblock::Component::Asterisk::AMI::Action.new :name => 'ExtensionStatus', :params => { :context => 'default', :exten => 'idonno' }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
subject { AMIAction.new command, mock_ami_client }
|
|
14
|
+
|
|
15
|
+
let :expected_action do
|
|
16
|
+
RubyAMI::Action.new 'ExtensionStatus', 'Context' => 'default', 'Exten' => 'idonno'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
context 'initial execution' do
|
|
20
|
+
let(:component_id) { UUIDTools::UUID.random_create }
|
|
21
|
+
|
|
22
|
+
let :expected_response do
|
|
23
|
+
Ref.new :id => component_id
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
before { UUIDTools::UUID.stubs :random_create => component_id }
|
|
27
|
+
|
|
28
|
+
it 'should send the appropriate RubyAMI::Action and send the component node a ref with the action ID' do
|
|
29
|
+
mock_ami_client.expects(:send_action).once.with(expected_action).returns(expected_action)
|
|
30
|
+
command.expects(:response=).once.with(expected_response)
|
|
31
|
+
subject.execute
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'when the AMI action completes' do
|
|
36
|
+
before do
|
|
37
|
+
command.request!
|
|
38
|
+
command.execute!
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
let :response do
|
|
42
|
+
RubyAMI::Response.new.tap do |r|
|
|
43
|
+
r['ActionID'] = "552a9d9f-46d7-45d8-a257-06fe95f48d99"
|
|
44
|
+
r['Message'] = 'Channel status will follow'
|
|
45
|
+
r["Exten"] = "idonno"
|
|
46
|
+
r["Context"] = "default"
|
|
47
|
+
r["Hint"] = ""
|
|
48
|
+
r["Status"] = "-1"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
let :expected_complete_reason do
|
|
53
|
+
Punchblock::Component::Asterisk::AMI::Action::Complete::Success.new :message => 'Channel status will follow', :attributes => {:exten => "idonno", :context => "default", :hint => "", :status => "-1"}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context 'for a non-causal action' do
|
|
57
|
+
it 'should send a complete event to the component node' do
|
|
58
|
+
subject.action.response = response
|
|
59
|
+
|
|
60
|
+
command.should be_complete
|
|
61
|
+
|
|
62
|
+
command.complete_event.resource(0.5).reason.should == expected_complete_reason
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context 'for a causal action' do
|
|
67
|
+
let :command do
|
|
68
|
+
Punchblock::Component::Asterisk::AMI::Action.new :name => 'CoreShowChannels'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
let :expected_action do
|
|
72
|
+
RubyAMI::Action.new 'CoreShowChannels'
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
let :event do
|
|
76
|
+
RubyAMI::Event.new('CoreShowChannel').tap do |e|
|
|
77
|
+
e['ActionID'] = "552a9d9f-46d7-45d8-a257-06fe95f48d99"
|
|
78
|
+
e['Channel'] = 'SIP/127.0.0.1-00000013'
|
|
79
|
+
e['UniqueID'] = '1287686437.19'
|
|
80
|
+
e['Context'] = 'adhearsion'
|
|
81
|
+
e['Extension'] = '23432'
|
|
82
|
+
e['Priority'] = '2'
|
|
83
|
+
e['ChannelState'] = '6'
|
|
84
|
+
e['ChannelStateDesc'] = 'Up'
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
let :terminating_event do
|
|
89
|
+
RubyAMI::Event.new('CoreShowChannelsComplete').tap do |e|
|
|
90
|
+
e['EventList'] = 'Complete'
|
|
91
|
+
e['ListItems'] = '3'
|
|
92
|
+
e['ActionID'] = 'umtLtvSg-RN5n-GEay-Z786-YdiaSLNXkcYN'
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
let :event_node do
|
|
97
|
+
Punchblock::Event::Asterisk::AMI::Event.new :name => 'CoreShowChannel', :attributes => {
|
|
98
|
+
:channel => 'SIP/127.0.0.1-00000013',
|
|
99
|
+
:uniqueid => '1287686437.19',
|
|
100
|
+
:context => 'adhearsion',
|
|
101
|
+
:extension => '23432',
|
|
102
|
+
:priority => '2',
|
|
103
|
+
:channelstate => '6',
|
|
104
|
+
:channelstatedesc => 'Up'
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
let :expected_complete_reason do
|
|
109
|
+
Punchblock::Component::Asterisk::AMI::Action::Complete::Success.new :message => 'Channel status will follow', :attributes => {:exten => "idonno", :context => "default", :hint => "", :status => "-1", :eventlist => 'Complete', :listitems => '3'}
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'should send events to the component node' do
|
|
113
|
+
command.register_event_handler Punchblock::Event::Asterisk::AMI::Event do |event|
|
|
114
|
+
@event = event
|
|
115
|
+
end
|
|
116
|
+
subject.action << event
|
|
117
|
+
subject.action << response
|
|
118
|
+
subject.action << terminating_event
|
|
119
|
+
@event.should == event_node
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'should send a complete event to the component node' do
|
|
123
|
+
subject.action << response
|
|
124
|
+
subject.action << terminating_event
|
|
125
|
+
|
|
126
|
+
command.complete_event.resource(0.5).reason.should == expected_complete_reason
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context 'with an error' do
|
|
131
|
+
let :error do
|
|
132
|
+
RubyAMI::Error.new.tap { |e| e.message = 'Action failed' }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
let :expected_complete_reason do
|
|
136
|
+
Punchblock::Event::Complete::Error.new :details => 'Action failed'
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it 'should send a complete event to the component node' do
|
|
140
|
+
subject.action << error
|
|
141
|
+
|
|
142
|
+
command.complete_event.resource(0.5).reason.should == expected_complete_reason
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
module Translator
|
|
5
|
+
class Asterisk
|
|
6
|
+
describe Call do
|
|
7
|
+
describe '#register_component' do
|
|
8
|
+
it 'should make the component accessible by ID' do
|
|
9
|
+
component_id = 'abc123'
|
|
10
|
+
component = mock 'Translator::Asterisk::Component', :id => component_id
|
|
11
|
+
subject.register_component component
|
|
12
|
+
subject.component_with_id(component_id).should be component
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
module Translator
|
|
5
|
+
describe Asterisk do
|
|
6
|
+
let(:ami_client) { mock 'RubyAMI::Client' }
|
|
7
|
+
let(:connection) { mock 'Connection::Asterisk' }
|
|
8
|
+
|
|
9
|
+
subject { Asterisk.new ami_client, connection }
|
|
10
|
+
|
|
11
|
+
its(:ami_client) { should be ami_client }
|
|
12
|
+
its(:connection) { should be connection }
|
|
13
|
+
|
|
14
|
+
describe '#execute_command' do
|
|
15
|
+
describe 'with a call command' do
|
|
16
|
+
let(:command) { Command::Answer.new }
|
|
17
|
+
let(:call_id) { 'abc123' }
|
|
18
|
+
|
|
19
|
+
it 'executes the call command' do
|
|
20
|
+
subject.actor_subject.expects(:execute_call_command).with do |c|
|
|
21
|
+
c.should be command
|
|
22
|
+
c.call_id.should == call_id
|
|
23
|
+
end
|
|
24
|
+
subject.execute_command command, :call_id => call_id
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe 'with a component command' do
|
|
29
|
+
let(:command) { Component::Stop.new }
|
|
30
|
+
let(:call_id) { 'abc123' }
|
|
31
|
+
let(:component_id) { '123abc' }
|
|
32
|
+
|
|
33
|
+
it 'executes the component command' do
|
|
34
|
+
subject.actor_subject.expects(:execute_component_command).with do |c|
|
|
35
|
+
c.should be command
|
|
36
|
+
c.call_id.should == call_id
|
|
37
|
+
c.component_id.should == component_id
|
|
38
|
+
end
|
|
39
|
+
subject.execute_command command, :call_id => call_id, :component_id => component_id
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe 'with a global command' do
|
|
44
|
+
let(:command) { Command::Dial.new }
|
|
45
|
+
|
|
46
|
+
it 'executes the command directly' do
|
|
47
|
+
subject.actor_subject.expects(:execute_global_command).with command
|
|
48
|
+
subject.execute_command command
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe '#register_call' do
|
|
54
|
+
it 'should make the call accessible by ID' do
|
|
55
|
+
call_id = 'abc123'
|
|
56
|
+
call = mock 'Translator::Asterisk::Call', :id => call_id
|
|
57
|
+
subject.register_call call
|
|
58
|
+
subject.call_with_id(call_id).should be call
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
describe '#execute_call_command' do
|
|
63
|
+
let(:call_id) { 'abc123' }
|
|
64
|
+
let(:call) { mock 'Translator::Asterisk::Call', :id => call_id }
|
|
65
|
+
let(:command) { mock 'Command::Answer', :call_id => call_id }
|
|
66
|
+
|
|
67
|
+
before do
|
|
68
|
+
subject.register_call call
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'sends the command to the call for execution' do
|
|
72
|
+
call.expects(:execute_command).once.with command
|
|
73
|
+
subject.execute_call_command command
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe '#execute_component_command' do
|
|
78
|
+
let(:call_id) { 'abc123' }
|
|
79
|
+
let(:call) { Translator::Asterisk::Call.new }
|
|
80
|
+
|
|
81
|
+
let(:component_id) { '123abc' }
|
|
82
|
+
let(:component) { mock 'Translator::Asterisk::Component', :id => component_id }
|
|
83
|
+
|
|
84
|
+
let(:command) { mock 'Component::Stop', :call_id => call_id, :component_id => component_id }
|
|
85
|
+
|
|
86
|
+
before do
|
|
87
|
+
call.stubs(:id).returns call_id
|
|
88
|
+
call.register_component component
|
|
89
|
+
subject.register_call call
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it 'sends the command to the component for execution' do
|
|
93
|
+
component.expects(:execute_command).once.with command
|
|
94
|
+
subject.execute_component_command command
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe '#execute_global_command' do
|
|
99
|
+
context 'with a Dial' do
|
|
100
|
+
pending
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context 'with an AMI action' do
|
|
104
|
+
let :command do
|
|
105
|
+
Component::Asterisk::AMI::Action.new :name => 'Status', :params => { :channel => 'foo' }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
let(:mock_action) { mock 'Asterisk::AMIAction' }
|
|
109
|
+
|
|
110
|
+
it 'should create a component actor and execute it asynchronously' do
|
|
111
|
+
Asterisk::AMIAction.expects(:new).once.with(command, subject.ami_client).returns mock_action
|
|
112
|
+
mock_action.expects(:execute!).once
|
|
113
|
+
subject.execute_global_command command
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe '#handle_ami_event' do
|
|
119
|
+
let :ami_event do
|
|
120
|
+
RubyAMI::Event.new('Newchannel').tap do |e|
|
|
121
|
+
e['Channel'] = "SIP/101-3f3f"
|
|
122
|
+
e['State'] = "Ring"
|
|
123
|
+
e['Callerid'] = "101"
|
|
124
|
+
e['Uniqueid'] = "1094154427.10"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
let :expected_pb_event do
|
|
129
|
+
Event::Asterisk::AMI::Event.new :name => 'Newchannel',
|
|
130
|
+
:attributes => { :channel => "SIP/101-3f3f",
|
|
131
|
+
:state => "Ring",
|
|
132
|
+
:callerid => "101",
|
|
133
|
+
:uniqueid => "1094154427.10"}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'should create a Punchblock AMI event object and pass it to the connection' do
|
|
137
|
+
subject.connection.expects(:handle_event).once.with expected_pb_event
|
|
138
|
+
subject.handle_ami_event ami_event
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
context 'with something that is not a RubyAMI::Event' do
|
|
142
|
+
it 'does not send anything to the connection' do
|
|
143
|
+
subject.connection.expects(:handle_event).never
|
|
144
|
+
subject.handle_ami_event :foo
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -20,6 +20,7 @@ def import_stanza(xml)
|
|
|
20
20
|
Blather::Stanza.import parse_stanza(xml).root
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
# FIXME: change this to rayo_event? It can be ambigous
|
|
23
24
|
shared_examples_for 'event' do
|
|
24
25
|
its(:call_id) { should == '9f00061' }
|
|
25
26
|
its(:component_id) { should == '1' }
|
|
@@ -41,3 +42,44 @@ shared_examples_for 'event_headers' do
|
|
|
41
42
|
its(:headers) { should == [Punchblock::Header.new(:x_skill, 'agent'), Punchblock::Header.new(:x_customer_id, '8877')]}
|
|
42
43
|
its(:headers_hash) { should == {:x_skill => 'agent', :x_customer_id => '8877'} }
|
|
43
44
|
end
|
|
45
|
+
|
|
46
|
+
shared_examples_for 'key_value_pairs' do
|
|
47
|
+
it 'will auto-inherit nodes' do
|
|
48
|
+
n = parse_stanza "<#{element_name} name='boo' value='bah' />"
|
|
49
|
+
h = class_name.new n.root
|
|
50
|
+
h.name.should == :boo
|
|
51
|
+
h.value.should == 'bah'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'has a name attribute' do
|
|
55
|
+
n = class_name.new :boo, 'bah'
|
|
56
|
+
n.name.should == :boo
|
|
57
|
+
n.name = :foo
|
|
58
|
+
n.name.should == :foo
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "substitutes - for _ on the name attribute when reading" do
|
|
62
|
+
n = parse_stanza "<#{element_name} name='boo-bah' value='foo' />"
|
|
63
|
+
h = class_name.new n.root
|
|
64
|
+
h.name.should == :boo_bah
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "substitutes _ for - on the name attribute when writing" do
|
|
68
|
+
h = class_name.new :boo_bah, 'foo'
|
|
69
|
+
h.to_xml.should == "<#{element_name} name=\"boo-bah\" value=\"foo\"/>"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'has a value param' do
|
|
73
|
+
n = class_name.new :boo, 'en'
|
|
74
|
+
n.value.should == 'en'
|
|
75
|
+
n.value = 'de'
|
|
76
|
+
n.value.should == 'de'
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'can determine equality' do
|
|
80
|
+
a = class_name.new :boo, 'bah'
|
|
81
|
+
a.should == class_name.new(:boo, 'bah')
|
|
82
|
+
a.should_not == class_name.new(:bah, 'bah')
|
|
83
|
+
a.should_not == class_name.new(:boo, 'boo')
|
|
84
|
+
end
|
|
85
|
+
end
|