spectifly 0.0.1
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 +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +128 -0
- data/Rakefile +8 -0
- data/lib/entities/association.entity +11 -0
- data/lib/entities/entity.entity +16 -0
- data/lib/entities/field.entity +35 -0
- data/lib/entities/related_entity.entity +28 -0
- data/lib/spectifly.rb +7 -0
- data/lib/spectifly/base.rb +8 -0
- data/lib/spectifly/base/association.rb +18 -0
- data/lib/spectifly/base/builder.rb +102 -0
- data/lib/spectifly/base/configuration.rb +19 -0
- data/lib/spectifly/base/entity_node.rb +55 -0
- data/lib/spectifly/base/field.rb +42 -0
- data/lib/spectifly/base/types.rb +27 -0
- data/lib/spectifly/configuration.rb +17 -0
- data/lib/spectifly/entity.rb +106 -0
- data/lib/spectifly/json.rb +8 -0
- data/lib/spectifly/json/association.rb +19 -0
- data/lib/spectifly/json/builder.rb +21 -0
- data/lib/spectifly/json/field.rb +28 -0
- data/lib/spectifly/json/types.rb +6 -0
- data/lib/spectifly/support.rb +32 -0
- data/lib/spectifly/tasks.rb +20 -0
- data/lib/spectifly/version.rb +3 -0
- data/lib/spectifly/xsd.rb +8 -0
- data/lib/spectifly/xsd/association.rb +31 -0
- data/lib/spectifly/xsd/builder.rb +43 -0
- data/lib/spectifly/xsd/field.rb +92 -0
- data/lib/spectifly/xsd/types.rb +32 -0
- data/lib/tasks/spectifly.rake +6 -0
- data/spec/expectations/extended.xsd +15 -0
- data/spec/expectations/group.json +37 -0
- data/spec/expectations/group.xsd +39 -0
- data/spec/expectations/individual.json +57 -0
- data/spec/expectations/individual.xsd +47 -0
- data/spec/expectations/presented/masterless_group.json +30 -0
- data/spec/expectations/presented/masterless_group.xsd +34 -0
- data/spec/expectations/presented/positionless_individual.json +44 -0
- data/spec/expectations/presented/positionless_individual.xsd +35 -0
- data/spec/fixtures/group.entity +23 -0
- data/spec/fixtures/individual.entity +33 -0
- data/spec/fixtures/invalid/multiple_root.entity +8 -0
- data/spec/fixtures/invalid/no_fields.entity +2 -0
- data/spec/fixtures/presenters/masterless_group.entity +8 -0
- data/spec/fixtures/presenters/positionless_individual.entity +12 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/spectifly/base/builder_spec.rb +29 -0
- data/spec/spectifly/base/entity_node_spec.rb +29 -0
- data/spec/spectifly/base/field_spec.rb +100 -0
- data/spec/spectifly/configuration_spec.rb +42 -0
- data/spec/spectifly/entity_spec.rb +189 -0
- data/spec/spectifly/json/builder_spec.rb +42 -0
- data/spec/spectifly/json/field_spec.rb +26 -0
- data/spec/spectifly/support_spec.rb +53 -0
- data/spec/spectifly/xsd/builder_spec.rb +51 -0
- data/spec/spectifly/xsd/field_spec.rb +12 -0
- data/spec/spectifly/xsd/types_spec.rb +11 -0
- data/spec/support/path_helper.rb +28 -0
- data/spectifly.gemspec +32 -0
- metadata +251 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
{
|
2
|
+
"individual": {
|
3
|
+
"belongs_to": {
|
4
|
+
"party": {
|
5
|
+
"type": "group",
|
6
|
+
"required": true,
|
7
|
+
"description": "Which funtime party this individual happy with is"
|
8
|
+
}
|
9
|
+
},
|
10
|
+
"name": {
|
11
|
+
"type": "string",
|
12
|
+
"multiple": false,
|
13
|
+
"required": true,
|
14
|
+
"description": "The individual's name",
|
15
|
+
"example": "Wussy O'Weakling",
|
16
|
+
"restrictions": {
|
17
|
+
"unique": true
|
18
|
+
}
|
19
|
+
},
|
20
|
+
"age": {
|
21
|
+
"type": "integer",
|
22
|
+
"multiple": false,
|
23
|
+
"required": false,
|
24
|
+
"validations": [
|
25
|
+
"Must be non-negative"
|
26
|
+
]
|
27
|
+
},
|
28
|
+
"joy": {
|
29
|
+
"type": "percent",
|
30
|
+
"multiple": false,
|
31
|
+
"required": false,
|
32
|
+
"restrictions": {
|
33
|
+
"minimum_value": 0,
|
34
|
+
"maximum_value": 100
|
35
|
+
}
|
36
|
+
},
|
37
|
+
"pickled": {
|
38
|
+
"type": "boolean",
|
39
|
+
"multiple": false,
|
40
|
+
"required": false,
|
41
|
+
"description": "Whether or not this individual is pickled"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
|
3
|
+
<xs:include schemaLocation="group.xsd"/>
|
4
|
+
<xs:include schemaLocation="extended.xsd"/>
|
5
|
+
<xs:element name="Individual" type="individualType"/>
|
6
|
+
<xs:complexType name="individualType">
|
7
|
+
<xs:sequence>
|
8
|
+
<xs:element name="Name" type="xs:string">
|
9
|
+
<xs:annotation>
|
10
|
+
<xs:documentation>The individual's name</xs:documentation>
|
11
|
+
<xs:documentation>Example: Wussy O'Weakling</xs:documentation>
|
12
|
+
</xs:annotation>
|
13
|
+
</xs:element>
|
14
|
+
<xs:element name="Age" type="xs:nonNegativeInteger" minOccurs="0"/>
|
15
|
+
<xs:element name="Joy" minOccurs="0">
|
16
|
+
<xs:simpleType>
|
17
|
+
<xs:restriction base="percentType">
|
18
|
+
<xs:minInclusive value="0"/>
|
19
|
+
<xs:maxInclusive value="100"/>
|
20
|
+
</xs:restriction>
|
21
|
+
</xs:simpleType>
|
22
|
+
</xs:element>
|
23
|
+
<xs:element name="Pickled" type="xs:boolean" minOccurs="0">
|
24
|
+
<xs:annotation>
|
25
|
+
<xs:documentation>Whether or not this individual is pickled</xs:documentation>
|
26
|
+
</xs:annotation>
|
27
|
+
</xs:element>
|
28
|
+
<xs:element name="Party" type="groupType" minOccurs="0">
|
29
|
+
<xs:annotation>
|
30
|
+
<xs:documentation>Which funtime party this individual happy with is</xs:documentation>
|
31
|
+
</xs:annotation>
|
32
|
+
</xs:element>
|
33
|
+
</xs:sequence>
|
34
|
+
</xs:complexType>
|
35
|
+
</xs:schema>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Group:
|
2
|
+
Description: A load of peoples
|
3
|
+
Fields:
|
4
|
+
Group ID:
|
5
|
+
Description: Identifier used to register group for scams
|
6
|
+
Validations:
|
7
|
+
- Must match regex "^[0-9]{2}(-?[0-9]{5})$"
|
8
|
+
- Must be unique
|
9
|
+
|
10
|
+
Name*:
|
11
|
+
Description: The name of this group
|
12
|
+
Validations: Must match regex "group"
|
13
|
+
|
14
|
+
Related Entities:
|
15
|
+
Has Many:
|
16
|
+
Peeps:
|
17
|
+
Description: Who is in the group
|
18
|
+
Type: Individual
|
19
|
+
|
20
|
+
Has One:
|
21
|
+
Master*:
|
22
|
+
Description: Who is the master of the group
|
23
|
+
Type: Individual
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Individual:
|
2
|
+
Description: An Individual
|
3
|
+
Fields:
|
4
|
+
Name*:
|
5
|
+
Description: The individual's name
|
6
|
+
Example: Randy McTougherson
|
7
|
+
Unique: True
|
8
|
+
|
9
|
+
Age:
|
10
|
+
Type: Integer
|
11
|
+
Validations: Must be non-negative
|
12
|
+
|
13
|
+
Happiness:
|
14
|
+
Type: Percent
|
15
|
+
Minimum Value: 0
|
16
|
+
Maximum Value: 100
|
17
|
+
|
18
|
+
Positions:
|
19
|
+
Description: Which positions individual occupies in a group
|
20
|
+
Multiple: True
|
21
|
+
Valid Values:
|
22
|
+
- Lotus
|
23
|
+
- Pole
|
24
|
+
- Third
|
25
|
+
|
26
|
+
Pickled?*:
|
27
|
+
Description: Whether or not this individual is pickled
|
28
|
+
|
29
|
+
Related Entities:
|
30
|
+
Belongs To:
|
31
|
+
Party*:
|
32
|
+
Description: Which funtime party this individual happy with is
|
33
|
+
Type: Group
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
|
+
|
4
|
+
require_relative '../lib/spectifly'
|
5
|
+
require_relative '../lib/spectifly/xsd'
|
6
|
+
require_relative '../lib/spectifly/json'
|
7
|
+
|
8
|
+
# Requires supporting files with custom matchers and macros, etc,
|
9
|
+
# in ./support/ and its subdirectories.
|
10
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
describe Spectifly::Base::Builder do
|
5
|
+
describe '.from_path' do
|
6
|
+
it 'generates builder from entity at given path' do
|
7
|
+
path_builder = described_class.from_path(fixture_path('individual'))
|
8
|
+
path_builder.root.should == 'Individual'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#build' do
|
13
|
+
it 'raises subclass responsibility error' do
|
14
|
+
entity = Spectifly::Entity.parse(fixture_path('individual'))
|
15
|
+
expect {
|
16
|
+
described_class.new(entity).build
|
17
|
+
}.to raise_error("Subclass Responsibility")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#custom_types' do
|
22
|
+
it 'return an array of all non-built-in types in result' do
|
23
|
+
entity = Spectifly::Entity.parse(fixture_path('group'))
|
24
|
+
described_class.new(entity).custom_types.should =~ [
|
25
|
+
'individual'
|
26
|
+
]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spectifly::Base::EntityNode do
|
4
|
+
describe 'uniqueness restriction' do
|
5
|
+
it 'unique should be false by default and there should be no unique restriction' do
|
6
|
+
field = described_class.new("Mini me")
|
7
|
+
field.should_not be_unique
|
8
|
+
field.restrictions.keys.should_not be_include('unique')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'adds a restriction and returns true for unique? if there is a uniqueness validation' do
|
12
|
+
field = described_class.new("Little Snowflake", {"Validations" => "must be unique"})
|
13
|
+
field.should be_unique
|
14
|
+
field.restrictions.keys.include?('unique').should be_true
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'adds a restriction and returns true for unique? if there is an attribute Unique set to true' do
|
18
|
+
field = described_class.new("Little Snowflake", {"Unique" => "true"})
|
19
|
+
field.should be_unique
|
20
|
+
field.restrictions.keys.include?('unique').should be_true
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'throws an error if the two ways of setting uniqueness contradict each other' do
|
24
|
+
lambda {
|
25
|
+
field = described_class.new("Little Snowflake?", {"Validations" => "must be unique", "Unique" => false})
|
26
|
+
}.should raise_error
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spectifly::Base::Field do
|
4
|
+
describe '#name' do
|
5
|
+
it 'returns tokenized version of field name' do
|
6
|
+
field = described_class.new('A really cool hat')
|
7
|
+
field.name.should == 'a_really_cool_hat'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.initialize' do
|
12
|
+
it 'throws an exception if Boolean shortcut conflicts with type' do
|
13
|
+
expect {
|
14
|
+
described_class.new('Caramel tuba?', 'Type' => 'DateTime')
|
15
|
+
}.to raise_error(ArgumentError, "Boolean field has conflicting type")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#type' do
|
20
|
+
it 'defaults to string if no type specified' do
|
21
|
+
field = described_class.new('A really cool hat')
|
22
|
+
field.type.should == 'string'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns boolean if field name has "?" token' do
|
26
|
+
field = described_class.new('A really cool hat?')
|
27
|
+
field.type.should == 'boolean'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns type if specified' do
|
31
|
+
field = described_class.new('some field', 'Type' => 'Rhubarb')
|
32
|
+
field.type.should == 'rhubarb'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#extract_restrictions' do
|
37
|
+
it 'sets up minimum and maximum value restrictions' do
|
38
|
+
field = described_class.new('some field', {
|
39
|
+
'Minimum Value' => 3, 'Maximum Value' => 145
|
40
|
+
})
|
41
|
+
field.restrictions.should == {
|
42
|
+
'minimum_value' => 3,
|
43
|
+
'maximum_value' => 145
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'sets up enumerations' do
|
48
|
+
field = described_class.new('some field', {
|
49
|
+
'Valid Values' => [34, 52, 100, 4]
|
50
|
+
})
|
51
|
+
field.restrictions.should == {
|
52
|
+
'valid_values' => [34, 52, 100, 4]
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'pulls regex restriction from validations' do
|
57
|
+
field = described_class.new('some field', {
|
58
|
+
'Validations' => 'Must match regex "^[0-9]{4}"'
|
59
|
+
})
|
60
|
+
field.validations.should be_empty
|
61
|
+
field.restrictions.should == {
|
62
|
+
'regex' => /^[0-9]{4}/
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'sets restrictions to empty hash if none exist' do
|
67
|
+
field = described_class.new('some field')
|
68
|
+
field.restrictions.should be_empty
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#multiple?' do
|
73
|
+
it 'returns true if multiple set to true' do
|
74
|
+
field = described_class.new('some field', 'Multiple' => true)
|
75
|
+
field.should be_multiple
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns false if multiple set to anything but true' do
|
79
|
+
field = described_class.new('some field', 'Multiple' => 'Whatever')
|
80
|
+
field.should_not be_multiple
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'returns false if multiple not set' do
|
84
|
+
field = described_class.new('some field')
|
85
|
+
field.should_not be_multiple
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#required?' do
|
90
|
+
it 'returns true if field name has "*" token' do
|
91
|
+
field = described_class.new('some field*')
|
92
|
+
field.should be_required
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns false if field name does not have "*" token' do
|
96
|
+
field = described_class.new('some field')
|
97
|
+
field.should_not be_required
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spectifly::Configuration do
|
4
|
+
let(:configuration_args) {
|
5
|
+
{
|
6
|
+
:entity_path => base_fixture_path
|
7
|
+
}
|
8
|
+
}
|
9
|
+
describe '.initialize' do
|
10
|
+
it 'succeeds if entity and destination paths provided' do
|
11
|
+
expect { described_class.new(configuration_args) }.not_to raise_error
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'fails if no entity path provided' do
|
15
|
+
configuration_args.delete(:entity_path)
|
16
|
+
expect { described_class.new(configuration_args) }.to raise_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#presenter_path' do
|
21
|
+
it 'returns configured value if set' do
|
22
|
+
configuration = described_class.new(
|
23
|
+
configuration_args.merge(:presenter_path => 'goose')
|
24
|
+
)
|
25
|
+
configuration.presenter_path.should == 'goose'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns nil if no presenter path exists at entity path' do
|
29
|
+
configuration = described_class.new(
|
30
|
+
configuration_args.merge(:entity_path => spec_path)
|
31
|
+
)
|
32
|
+
configuration.presenter_path.should be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns {entity_path}/presenters if exists' do
|
36
|
+
configuration = described_class.new(
|
37
|
+
configuration_args
|
38
|
+
)
|
39
|
+
configuration.presenter_path.should == base_presenter_path
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spectifly::Entity do
|
4
|
+
before :each do
|
5
|
+
@entity = Spectifly::Entity.parse(fixture_path('individual'))
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '.from_directory' do
|
9
|
+
it 'returns entities generated from files at given path' do
|
10
|
+
entities = Spectifly::Entity.from_directory(fixture_path)
|
11
|
+
entities.keys.should =~ ['individual', 'group']
|
12
|
+
entities.values.map(&:class).uniq.should == [Spectifly::Entity]
|
13
|
+
entities.values.map(&:name).should =~ ['individual', 'group']
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'includes presenters if option passed' do
|
17
|
+
entities = Spectifly::Entity.from_directory(
|
18
|
+
fixture_path, :presenter_path => base_presenter_path
|
19
|
+
)
|
20
|
+
entities.keys.should =~ ['individual', 'group', 'positionless_individual', 'masterless_group']
|
21
|
+
entities.values.map(&:class).uniq.should == [Spectifly::Entity]
|
22
|
+
entities.values.map(&:name).should =~ ['individual', 'group', 'positionless_individual', 'masterless_group']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '.parse' do
|
27
|
+
it 'delegates to initializer' do
|
28
|
+
Spectifly::Entity.should_receive(:new).with(:arguments)
|
29
|
+
Spectifly::Entity.parse(:arguments)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '.new' do
|
34
|
+
it 'raises error if file not found' do
|
35
|
+
expect {
|
36
|
+
Spectifly::Entity.parse(fixture_path('missing'))
|
37
|
+
}.to raise_error
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'raises Invalid if file has multiple roots' do
|
41
|
+
expect {
|
42
|
+
Spectifly::Entity.parse(fixture_path('invalid/multiple_root'))
|
43
|
+
}.to raise_error(Spectifly::Entity::Invalid)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'raises Invalid if file has no fields' do
|
47
|
+
expect {
|
48
|
+
Spectifly::Entity.parse(fixture_path('invalid/multiple_root'))
|
49
|
+
}.to raise_error(Spectifly::Entity::Invalid)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#root' do
|
54
|
+
it 'returns root element of parsed yaml' do
|
55
|
+
@entity.root.should == 'Individual'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#name' do
|
60
|
+
before :each do
|
61
|
+
@presenter_entity = Spectifly::Entity.parse(
|
62
|
+
fixture_path('presenters/positionless_individual')
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'returns name from entity file' do
|
67
|
+
@entity.name.should == 'individual'
|
68
|
+
@presenter_entity.name.should == 'positionless_individual'
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'returns presenter name when presented' do
|
72
|
+
@entity.present_as(@presenter_entity).name.should == 'positionless_individual'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#presented_as' do
|
77
|
+
it 'returns nil if not presented' do
|
78
|
+
@entity.presented_as.should be_nil
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'returns presenter if presented' do
|
82
|
+
@presenter_entity = Spectifly::Entity.parse(
|
83
|
+
fixture_path('presenters/positionless_individual')
|
84
|
+
)
|
85
|
+
@entity.present_as(@presenter_entity).presented_as.should == @presenter_entity
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#metadata' do
|
90
|
+
it 'returns metadata from parsed yaml' do
|
91
|
+
@entity.metadata.should == {
|
92
|
+
"Description" => "An Individual"
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#fields' do
|
98
|
+
it 'returns fields from parsed yaml' do
|
99
|
+
@entity.fields.should == {
|
100
|
+
"Name*" => {
|
101
|
+
"Description" => "The individual's name",
|
102
|
+
"Example" => "Randy McTougherson",
|
103
|
+
"Unique" => true
|
104
|
+
},
|
105
|
+
"Age" => {
|
106
|
+
"Type" => "Integer",
|
107
|
+
"Validations" => "Must be non-negative"
|
108
|
+
},
|
109
|
+
"Happiness" => {
|
110
|
+
"Type" => "Percent",
|
111
|
+
"Minimum Value" => 0,
|
112
|
+
"Maximum Value" => 100
|
113
|
+
},
|
114
|
+
"Positions" => {
|
115
|
+
"Description" => "Which positions individual occupies in a group",
|
116
|
+
"Multiple" => true,
|
117
|
+
"Valid Values" => [
|
118
|
+
'Lotus',
|
119
|
+
'Pole',
|
120
|
+
'Third'
|
121
|
+
]
|
122
|
+
},
|
123
|
+
"Pickled?*" => {
|
124
|
+
"Description" => "Whether or not this individual is pickled"
|
125
|
+
}
|
126
|
+
}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#present_as' do
|
131
|
+
before :each do
|
132
|
+
@presenter_entity = Spectifly::Entity.parse(fixture_path('presenters/positionless_individual'))
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'raises exception if presenter entity has different root' do
|
136
|
+
@presenter_entity.instance_variable_set(:@root, 'Whatever')
|
137
|
+
expect {
|
138
|
+
@entity.present_as(@presenter_entity)
|
139
|
+
}.to raise_error(ArgumentError, "Presenter entity has different root")
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'uses presenter fields only, but merges metadata and field attributes' do
|
143
|
+
@merged_entity = @entity.present_as(@presenter_entity)
|
144
|
+
@merged_entity.fields.should == {
|
145
|
+
"Name*" => {
|
146
|
+
"Description" => "The individual's name",
|
147
|
+
"Example" => "Wussy O'Weakling",
|
148
|
+
"Unique" => true
|
149
|
+
},
|
150
|
+
"Age" => {
|
151
|
+
"Type" => "Integer",
|
152
|
+
"Validations" => "Must be non-negative"
|
153
|
+
},
|
154
|
+
"Joy" => {
|
155
|
+
"Type" => "Percent",
|
156
|
+
"Minimum Value" => 0,
|
157
|
+
"Maximum Value" => 100,
|
158
|
+
"Inherits From" => "Happiness"
|
159
|
+
},
|
160
|
+
"Pickled?" => {
|
161
|
+
"Description" => "Whether or not this individual is pickled"
|
162
|
+
}
|
163
|
+
}
|
164
|
+
@merged_entity.metadata.should == {
|
165
|
+
"Description" => "A Positionless Individual"
|
166
|
+
}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#relationships' do
|
171
|
+
it 'returns relationships from parsed yaml' do
|
172
|
+
@group_entity = Spectifly::Entity.parse(fixture_path('group'))
|
173
|
+
@group_entity.relationships.should == {
|
174
|
+
"Has Many" => {
|
175
|
+
"Peeps" => {
|
176
|
+
"Description" => "Who is in the group",
|
177
|
+
"Type" => "Individual"
|
178
|
+
}
|
179
|
+
},
|
180
|
+
"Has One" => {
|
181
|
+
"Master*" => {
|
182
|
+
"Description" => "Who is the master of the group",
|
183
|
+
"Type" => "Individual"
|
184
|
+
}
|
185
|
+
}
|
186
|
+
}
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|