spectifly 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|