gexf 0.0.2
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/.gitignore +0 -0
- data/lib/gexf.rb +21 -0
- data/lib/gexf/attribute.rb +92 -0
- data/lib/gexf/attribute/assignable.rb +81 -0
- data/lib/gexf/attribute/definable.rb +20 -0
- data/lib/gexf/document.rb +112 -0
- data/lib/gexf/edge.rb +73 -0
- data/lib/gexf/edgeset.rb +7 -0
- data/lib/gexf/graph.rb +82 -0
- data/lib/gexf/node.rb +52 -0
- data/lib/gexf/nodeset.rb +19 -0
- data/lib/gexf/set_of_sets.rb +38 -0
- data/lib/gexf/support.rb +18 -0
- data/lib/gexf/version.rb +3 -0
- data/lib/gexf/xml_serializer.rb +93 -0
- data/spec/gexf/attribute/assignable_spec.rb +118 -0
- data/spec/gexf/attribute/definable_spec.rb +66 -0
- data/spec/gexf/attribute_spec.rb +179 -0
- data/spec/gexf/edge_spec.rb +70 -0
- data/spec/gexf/edgeset_spec.rb +105 -0
- data/spec/gexf/graph_spec.rb +172 -0
- data/spec/gexf/node_spec.rb +105 -0
- data/spec/gexf/nodeset_spec.rb +4 -0
- data/spec/spec_helper.rb +2 -0
- metadata +125 -0
data/lib/gexf/node.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
class GEXF::Node
|
2
|
+
extend Forwardable
|
3
|
+
include GEXF::Attribute::Assignable
|
4
|
+
|
5
|
+
attr_reader :id, :label
|
6
|
+
|
7
|
+
def_delegators :@graph, :edgetype
|
8
|
+
|
9
|
+
def initialize(id, graph, opts={})
|
10
|
+
@graph = graph
|
11
|
+
@id = id_type(id)
|
12
|
+
@label = opts[:label] || @id
|
13
|
+
|
14
|
+
# see GEXF::Attribute::Assignable
|
15
|
+
@collection = graph.nodes
|
16
|
+
@attr_values = {}
|
17
|
+
|
18
|
+
set_attributes(opts.fetch(:attributes, {}))
|
19
|
+
end
|
20
|
+
|
21
|
+
def connect_to(target, opts={})
|
22
|
+
graph.nodes << target
|
23
|
+
graph.create_edge(self, target, opts)
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_and_connect_to(target_attr, opts={})
|
27
|
+
node = graph.create_node(target_attr)
|
28
|
+
connect_to(node, opts)
|
29
|
+
node
|
30
|
+
end
|
31
|
+
|
32
|
+
def connections(type=nil)
|
33
|
+
graph.edges[self.id].to_a
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_hash
|
37
|
+
{:id => id, :label => label}
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def set_attributes(attributes={})
|
42
|
+
attributes.each { |attr,value| self[attr]=value }
|
43
|
+
end
|
44
|
+
|
45
|
+
def id_type(id)
|
46
|
+
graph.idtype == GEXF::Graph::INTEGER ? id.to_i : id.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def graph
|
50
|
+
@graph
|
51
|
+
end
|
52
|
+
end
|
data/lib/gexf/nodeset.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class GEXF::NodeSet < Set
|
2
|
+
extend Forwardable
|
3
|
+
include GEXF::Attribute::Definable
|
4
|
+
|
5
|
+
def_delegators :@hash, :[], :fetch, :keys, :values
|
6
|
+
|
7
|
+
def <<(node)
|
8
|
+
@hash[node.id] = node if node.is_a?(GEXF::Node)
|
9
|
+
end
|
10
|
+
|
11
|
+
def each(&block)
|
12
|
+
@hash.values.each(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"<GEXF::NodeSet #{@hash.keys}>"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class GEXF::SetOfSets < Set
|
2
|
+
extend ::Forwardable
|
3
|
+
include GEXF::Attribute::Definable
|
4
|
+
|
5
|
+
def_delegators :@hash, :empty?
|
6
|
+
|
7
|
+
def [](node_id)
|
8
|
+
@hash[node_id]
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_a
|
12
|
+
uniq_items
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_hash
|
16
|
+
@hash
|
17
|
+
end
|
18
|
+
|
19
|
+
def each(&block)
|
20
|
+
uniq_items.each(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
[:size, :count, :length].each do |method|
|
24
|
+
define_method(method) do
|
25
|
+
uniq_items.count
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def append_to_key(key, value)
|
31
|
+
@hash[key] ||= Set.new
|
32
|
+
@hash[key] << value
|
33
|
+
end
|
34
|
+
|
35
|
+
def uniq_items
|
36
|
+
@hash.map {| _, v| v.to_a }.flatten.uniq
|
37
|
+
end
|
38
|
+
end
|
data/lib/gexf/support.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
GEXF::GRAPH_TYPES = (GEXF::Attribute::TYPES +
|
2
|
+
GEXF::Edge::TYPES +
|
3
|
+
GEXF::Graph::IDTYPES +
|
4
|
+
GEXF::Graph::MODES).uniq
|
5
|
+
|
6
|
+
class Hash
|
7
|
+
def symbolize_keys
|
8
|
+
hash = {}
|
9
|
+
each { |k,v| hash[k.to_sym] = delete(k) }
|
10
|
+
merge(hash)
|
11
|
+
end
|
12
|
+
|
13
|
+
def symbolize_graph_types
|
14
|
+
hash = {}
|
15
|
+
each { |k, v| hash[k] = delete(k).to_sym if GEXF::GRAPH_TYPES.include?(v.to_sym) }
|
16
|
+
merge(hash)
|
17
|
+
end
|
18
|
+
end
|
data/lib/gexf/version.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
class GEXF::XmlSerializer
|
2
|
+
|
3
|
+
GEXF_ATTRS = {
|
4
|
+
'xmlns' => '"http://www.gexf.net/1.2draft',
|
5
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
6
|
+
'xsi' => 'http://www.gexf.net/1.2draft http://www.gexf.net/1.2draft/gexf.xsd',
|
7
|
+
'version' => '1.2'
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize(graph)
|
11
|
+
@graph = graph
|
12
|
+
@document = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def serialize!
|
16
|
+
document.to_xml
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def g
|
21
|
+
@graph
|
22
|
+
end
|
23
|
+
|
24
|
+
def graph_attributes
|
25
|
+
{ :defaultedgetype => g.defaultedgetype,
|
26
|
+
:idtype => g.idtype,
|
27
|
+
:mode => g.mode }
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_attributes(xml)
|
31
|
+
%w(nodes edges).each do |type|
|
32
|
+
defined_attributes = g.send(type).defined_attributes
|
33
|
+
next if defined_attributes.empty?
|
34
|
+
|
35
|
+
xml.attributes(:class => type.gsub(/s$/,'')) {
|
36
|
+
defined_attributes.map do |id, attr|
|
37
|
+
xml.attribute(attr.to_hash) {
|
38
|
+
xml.default(attr.default) if attr.default
|
39
|
+
}
|
40
|
+
end
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_nodes(xml)
|
46
|
+
build_collection(xml, 'nodes')
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_edges(xml)
|
50
|
+
build_collection(xml, 'edges')
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_collection(xml, collection_name, tagname=nil)
|
54
|
+
tagname ||= collection_name.gsub /s$/,''
|
55
|
+
|
56
|
+
xml.send(collection_name) do
|
57
|
+
g.send(collection_name).each do |item|
|
58
|
+
build_item(xml, item, tagname)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_item(xml, item, tagname)
|
64
|
+
if item.attr_values.any?
|
65
|
+
xml.send(tagname, item.to_hash) do
|
66
|
+
xml.attvalues do
|
67
|
+
item.attr_values.each do |id, value|
|
68
|
+
value = value.join('|') if value.respond_to?(:join)
|
69
|
+
xml.attvalue(:for => id, :value => value)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
else
|
74
|
+
xml.send(tagname, item.to_hash)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def document
|
79
|
+
@document ||= build do |xml|
|
80
|
+
xml.gexf(GEXF_ATTRS) do
|
81
|
+
xml.graph(graph_attributes) do
|
82
|
+
build_attributes(xml)
|
83
|
+
build_nodes(xml)
|
84
|
+
build_edges(xml)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def build(&block)
|
91
|
+
Nokogiri::XML::Builder.new(:encoding => 'UTF-8', &block)
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module FakeClasses
|
4
|
+
class MyClass
|
5
|
+
include GEXF::Attribute::Assignable
|
6
|
+
|
7
|
+
def initialize(collection, attr_values)
|
8
|
+
@collection = collection
|
9
|
+
@attr_values = attr_values
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe GEXF::Attribute::Assignable do
|
15
|
+
|
16
|
+
let(:attribute1) { double('attribute1', :id => '1', :title => "attribute1", :default => nil) }
|
17
|
+
let(:attribute2) { double('attribute2', :id => '2', :title => "attribute2", :default => nil) }
|
18
|
+
let(:attribute3) { double('attribute3', :id => '3', :title => "attribute3", :default => nil) }
|
19
|
+
let(:frog) { GEXF::Attribute.new(4, 'frog', :default => true, :type => GEXF::Attribute::BOOLEAN) }
|
20
|
+
|
21
|
+
let(:attr_values) {{}}
|
22
|
+
|
23
|
+
let(:attributes) { { '1' => attribute1,
|
24
|
+
'2' => attribute2,
|
25
|
+
'3' => attribute3 } }
|
26
|
+
|
27
|
+
let(:collection) { double('collection', :attribute_definitions => attributes) }
|
28
|
+
|
29
|
+
subject { FakeClasses::MyClass.new(collection, attr_values) }
|
30
|
+
|
31
|
+
describe "#attributes" do
|
32
|
+
context "when graph has no attribute definition" do
|
33
|
+
let(:attributes) {{}}
|
34
|
+
its(:attributes) { should == attributes }
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when graph has attributes" do
|
38
|
+
context "node/edge has no values set" do
|
39
|
+
it "returns a hash of attributes with nil values" do
|
40
|
+
subject.attributes.should == {
|
41
|
+
'attribute1' => nil,
|
42
|
+
'attribute2' => nil,
|
43
|
+
'attribute3' => nil
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "node/edge has values" do
|
49
|
+
|
50
|
+
let(:attr_values) {{ '1' => 'foo',
|
51
|
+
'2' => 'bar'}}
|
52
|
+
|
53
|
+
it "returns a hash of attributes with non-nil values" do
|
54
|
+
subject.attributes.should == {
|
55
|
+
'attribute1' => 'foo',
|
56
|
+
'attribute2' => 'bar',
|
57
|
+
'attribute3' => nil
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#[]" do
|
65
|
+
context 'when attribute title does not exist' do
|
66
|
+
it "raises a warning, and returns nil" do
|
67
|
+
Kernel.should_receive(:warn).with("undefined attribute 'other-attribute'")
|
68
|
+
subject['other-attribute'].should be_nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
context "when node/edge has no attribute values" do
|
72
|
+
it "returns nil" do
|
73
|
+
Kernel.should_not_receive(:warn)
|
74
|
+
subject['attribute1'].should be_nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when node/edge has a value" do
|
79
|
+
let(:attr_values) {{ '1' => 'foo' }}
|
80
|
+
|
81
|
+
it "returns the value" do
|
82
|
+
subject[:attribute1].should == 'foo'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when attribute has a default value" do
|
87
|
+
let(:attributes) {{ frog.id => frog }}
|
88
|
+
|
89
|
+
it "returns the default value" do
|
90
|
+
subject[:frog].should == true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#[]=" do
|
96
|
+
|
97
|
+
let(:value) { '22' }
|
98
|
+
|
99
|
+
context 'when attribute title does not exist' do
|
100
|
+
it "prints a warning, does not set the attribute value" do
|
101
|
+
Kernel.should_receive(:warn).with("undefined attribute 'other-attribute'")
|
102
|
+
attr_values.should_not_receive(:[]=)
|
103
|
+
subject['other-attribute'] = value
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "when attribute title does exist" do
|
108
|
+
it "sets the attribute value" do
|
109
|
+
Kernel.should_not_receive(:warn)
|
110
|
+
attribute2.should_receive(:coherce).with(value).and_return(value)
|
111
|
+
attribute2.should_receive(:is_valid?).with(value).and_return(true)
|
112
|
+
attr_values.should_receive(:[]=).with('2', value)
|
113
|
+
subject['attribute2'] = value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module FakeClassess
|
4
|
+
class NodeSet < Set
|
5
|
+
include GEXF::Attribute::Definable
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe GEXF::Attribute::Definable do
|
10
|
+
let(:node1) { mock('node', :id => '1' )}
|
11
|
+
let(:node2) { mock('node', :id => '2' )}
|
12
|
+
let(:nodeset) { FakeClassess::NodeSet.new }
|
13
|
+
let(:attr_id) { '22' }
|
14
|
+
let(:title) { 'tags' }
|
15
|
+
let(:attr_type) { GEXF::Attribute::LIST_STRING }
|
16
|
+
let(:opts) {{ :type => attr_type }}
|
17
|
+
let(:arguments) {[attr_id, title, opts]}
|
18
|
+
|
19
|
+
before do
|
20
|
+
nodeset << node1 << node2
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#define_attribute" do
|
24
|
+
subject { nodeset.define_attribute(*arguments) }
|
25
|
+
|
26
|
+
it "Instantiates an new GEXF::Attribute" do
|
27
|
+
subject.should be_a_kind_of(GEXF::Attribute)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#attribute_definitions" do
|
32
|
+
|
33
|
+
let(:attribute) { mock('attribute') }
|
34
|
+
|
35
|
+
subject { nodeset }
|
36
|
+
|
37
|
+
before(:each) do
|
38
|
+
GEXF::Attribute.should_receive(:new).and_return(attribute)
|
39
|
+
nodeset.define_attribute(*arguments)
|
40
|
+
end
|
41
|
+
|
42
|
+
its(:attribute_definitions) { should have_key(attr_id) }
|
43
|
+
its(:attribute_definitions) { should have_value(attribute) }
|
44
|
+
its(:attribute_definitions) { should have(1).item }
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#attributes" do
|
48
|
+
let(:nodeattrs) {{ :foo => 'fooval', :bar => 'barval' }}
|
49
|
+
|
50
|
+
subject { nodeset.attributes }
|
51
|
+
|
52
|
+
before(:each) do
|
53
|
+
node1.stub(:attributes).and_return(nil)
|
54
|
+
node2.stub(:attributes).and_return(nodeattrs)
|
55
|
+
|
56
|
+
nodeset.define_attribute('1', 'foo')
|
57
|
+
nodeset.define_attribute('2', 'bar')
|
58
|
+
end
|
59
|
+
|
60
|
+
it "returns a hash of items with attributes" do
|
61
|
+
subject.should_not have_key('1')
|
62
|
+
subject.should have_key('2')
|
63
|
+
subject.should have_value(nodeattrs)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
TRUTHY_INPUTS = [1, '1', true, 'true']
|
4
|
+
FALSY_INPUTS = [0, '0', false, 'false']
|
5
|
+
EMPTY_ARRAY = []
|
6
|
+
EMPTY_STRING = []
|
7
|
+
OBJECT = Object.new
|
8
|
+
|
9
|
+
describe GEXF::Attribute do
|
10
|
+
|
11
|
+
let(:id) { 22 }
|
12
|
+
let(:type) { nil }
|
13
|
+
let(:mode) { nil }
|
14
|
+
let(:attr_class) { nil }
|
15
|
+
let(:title) { 'foo' }
|
16
|
+
let(:attr_options) { ['foo', 'bar', 'baz'] }
|
17
|
+
let(:title) { 'bar' }
|
18
|
+
let(:default) { 'foo' }
|
19
|
+
|
20
|
+
let(:options) {{ :mode => mode,
|
21
|
+
:class => attr_class,
|
22
|
+
:default => default,
|
23
|
+
:type => type,
|
24
|
+
:options => attr_options }}
|
25
|
+
|
26
|
+
let(:arguments) { [id, title, options] }
|
27
|
+
|
28
|
+
subject { GEXF::Attribute.new(*arguments) }
|
29
|
+
|
30
|
+
describe "getter methods" do
|
31
|
+
its(:title) { should == 'bar' }
|
32
|
+
its(:type) { should == GEXF::Attribute::STRING }
|
33
|
+
its(:id) { should == id.to_s }
|
34
|
+
its(:options) { should == attr_options }
|
35
|
+
its(:default) { should == default }
|
36
|
+
its(:mode) { should == GEXF::Attribute::STATIC }
|
37
|
+
its(:attr_class) { should == GEXF::Attribute::NODE }
|
38
|
+
|
39
|
+
context "with invalid type" do
|
40
|
+
let(:type) { :BANANA }
|
41
|
+
|
42
|
+
it "raises an ArgumentError" do
|
43
|
+
expect { subject }.to raise_error(ArgumentError)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
{:mode => :FOO, :attr_class => :BANANA}.each do |attr, invalid_value|
|
48
|
+
context "when :#{attr} is not valid" do
|
49
|
+
let(attr) { invalid_value }
|
50
|
+
|
51
|
+
it "raises an ArgumentError" do
|
52
|
+
expect { subject }.to raise_error(ArgumentError)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when 'options' do not include 'default' value" do
|
58
|
+
let(:default) { :bacon }
|
59
|
+
|
60
|
+
it "raises an ArgumentError" do
|
61
|
+
expect { subject }.to raise_error(ArgumentError)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "is_valid?" do
|
67
|
+
context "when :options is empty/nil" do
|
68
|
+
let(:attr_options) { nil }
|
69
|
+
|
70
|
+
it "returns true" do
|
71
|
+
subject.is_valid?('whaterver').should be_true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when :options is not empty" do
|
76
|
+
context "and :options include input value" do
|
77
|
+
it "returns true" do
|
78
|
+
subject.is_valid?('foo').should be_true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
context "and :options do not include input value" do
|
82
|
+
it "returns false" do
|
83
|
+
subject.is_valid?('bacon').should be_false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "coherce" do
|
90
|
+
|
91
|
+
subject { GEXF::Attribute.new(*arguments).coherce(value) }
|
92
|
+
|
93
|
+
context "when attribute type is :BOOLEAN" do
|
94
|
+
let(:type) { GEXF::Attribute::BOOLEAN }
|
95
|
+
|
96
|
+
context "Falsy inputs" do
|
97
|
+
FALSY_INPUTS.each do |value|
|
98
|
+
context "and input value is #{value}" do
|
99
|
+
let(:value) { value }
|
100
|
+
it { subject.should be_false }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
context "Truty inputs" do
|
105
|
+
TRUTHY_INPUTS.each do |value|
|
106
|
+
context "and input value is #{value}" do
|
107
|
+
let(:value) { value }
|
108
|
+
it { subject.should be_true }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
context "other input types" do
|
113
|
+
[22, -2, Object.new, [1,2,3], 'hello', :hi].each do |value|
|
114
|
+
context "input value is '#{value.inspect}'" do
|
115
|
+
let(:value) { value }
|
116
|
+
|
117
|
+
it { subject.should be_nil }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
[GEXF::Attribute::STRING, GEXF::Attribute::ANY_URI].each do |type|
|
124
|
+
context "when attribute type is #{type}" do
|
125
|
+
let(:type) { type }
|
126
|
+
|
127
|
+
[22, 2.1, Object.new, nil, true, false].each do |value|
|
128
|
+
context "and input value is '#{value.inspect}'" do
|
129
|
+
let(:value) { value }
|
130
|
+
it { should == value.to_s }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "when attribute type is :INTEGER" do
|
137
|
+
let(:type) { GEXF::Attribute::INTEGER }
|
138
|
+
|
139
|
+
[22, 2.1, nil].each do |value|
|
140
|
+
context "and input value is '#{value.inspect}'" do
|
141
|
+
let(:value) { value }
|
142
|
+
it { should == value.to_i }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
[Object.new, true, false].each do |value|
|
147
|
+
context "and input value is '#{value.inspect}'" do
|
148
|
+
let(:value) { value }
|
149
|
+
it { should be_nil }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "when attribute type is :LIST_STRING" do
|
155
|
+
let(:type) { GEXF::Attribute::LIST_STRING }
|
156
|
+
|
157
|
+
context "input is nil" do
|
158
|
+
let(:value) { nil }
|
159
|
+
|
160
|
+
it { subject.should == [] }
|
161
|
+
end
|
162
|
+
|
163
|
+
context "input is not empty" do
|
164
|
+
let(:value) { [:foo, :bar, 22] }
|
165
|
+
it { subject.should == value.map(&:to_s) }
|
166
|
+
end
|
167
|
+
|
168
|
+
context "input contains duplicates" do
|
169
|
+
let(:value) { [:foo, :bar, 22, 'foo'] }
|
170
|
+
it { subject.should == %w(foo bar 22) }
|
171
|
+
end
|
172
|
+
|
173
|
+
context "input contains nested lists" do
|
174
|
+
let(:value) { [:foo, :bar, 22, ['foo']] }
|
175
|
+
it { subject.should == %w(foo bar 22) }
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|