lutaml-model 0.3.23 → 0.3.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +35 -16
- data/README.adoc +274 -28
- data/lib/lutaml/model/attribute.rb +18 -8
- data/lib/lutaml/model/error/type_error.rb +9 -0
- data/lib/lutaml/model/error/unknown_type_error.rb +9 -0
- data/lib/lutaml/model/error/validation_error.rb +0 -1
- data/lib/lutaml/model/error.rb +2 -0
- data/lib/lutaml/model/serialize.rb +7 -2
- data/lib/lutaml/model/type/boolean.rb +38 -0
- data/lib/lutaml/model/type/date.rb +35 -0
- data/lib/lutaml/model/type/date_time.rb +32 -4
- data/lib/lutaml/model/type/decimal.rb +42 -0
- data/lib/lutaml/model/type/float.rb +37 -0
- data/lib/lutaml/model/type/hash.rb +62 -0
- data/lib/lutaml/model/type/integer.rb +41 -0
- data/lib/lutaml/model/type/string.rb +49 -0
- data/lib/lutaml/model/type/time.rb +49 -0
- data/lib/lutaml/model/type/time_without_date.rb +37 -5
- data/lib/lutaml/model/type/value.rb +52 -0
- data/lib/lutaml/model/type.rb +50 -114
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/builder/nokogiri.rb +5 -2
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +2 -1
- data/lib/lutaml/model/xml_adapter/xml_document.rb +0 -2
- data/lutaml-model.gemspec +1 -1
- data/spec/address_spec.rb +170 -0
- data/spec/fixtures/address.rb +33 -0
- data/spec/fixtures/person.rb +73 -0
- data/spec/fixtures/sample_model.rb +40 -0
- data/spec/fixtures/vase.rb +38 -0
- data/spec/fixtures/xml/special_char.xml +13 -0
- data/spec/lutaml/model/attribute_spec.rb +112 -0
- data/spec/lutaml/model/collection_spec.rb +299 -0
- data/spec/lutaml/model/comparable_model_spec.rb +106 -0
- data/spec/lutaml/model/custom_model_spec.rb +410 -0
- data/spec/lutaml/model/custom_serialization_spec.rb +170 -0
- data/spec/lutaml/model/defaults_spec.rb +221 -0
- data/spec/lutaml/model/delegation_spec.rb +340 -0
- data/spec/lutaml/model/inheritance_spec.rb +92 -0
- data/spec/lutaml/model/json_adapter_spec.rb +37 -0
- data/spec/lutaml/model/key_value_mapping_spec.rb +86 -0
- data/spec/lutaml/model/map_content_spec.rb +118 -0
- data/spec/lutaml/model/mixed_content_spec.rb +625 -0
- data/spec/lutaml/model/namespace_spec.rb +57 -0
- data/spec/lutaml/model/ordered_content_spec.rb +83 -0
- data/spec/lutaml/model/render_nil_spec.rb +138 -0
- data/spec/lutaml/model/schema/json_schema_spec.rb +79 -0
- data/spec/lutaml/model/schema/relaxng_schema_spec.rb +60 -0
- data/spec/lutaml/model/schema/xsd_schema_spec.rb +55 -0
- data/spec/lutaml/model/schema/yaml_schema_spec.rb +47 -0
- data/spec/lutaml/model/serializable_spec.rb +297 -0
- data/spec/lutaml/model/serializable_validation_spec.rb +85 -0
- data/spec/lutaml/model/simple_model_spec.rb +314 -0
- data/spec/lutaml/model/toml_adapter_spec.rb +39 -0
- data/spec/lutaml/model/type/boolean_spec.rb +54 -0
- data/spec/lutaml/model/type/date_spec.rb +118 -0
- data/spec/lutaml/model/type/date_time_spec.rb +127 -0
- data/spec/lutaml/model/type/decimal_spec.rb +125 -0
- data/spec/lutaml/model/type/float_spec.rb +191 -0
- data/spec/lutaml/model/type/hash_spec.rb +63 -0
- data/spec/lutaml/model/type/integer_spec.rb +145 -0
- data/spec/lutaml/model/type/string_spec.rb +150 -0
- data/spec/lutaml/model/type/time_spec.rb +142 -0
- data/spec/lutaml/model/type/time_without_date_spec.rb +125 -0
- data/spec/lutaml/model/type_spec.rb +276 -0
- data/spec/lutaml/model/utils_spec.rb +79 -0
- data/spec/lutaml/model/validation_spec.rb +83 -0
- data/spec/lutaml/model/with_child_mapping_spec.rb +174 -0
- data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +56 -0
- data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +56 -0
- data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +61 -0
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +251 -0
- data/spec/lutaml/model/xml_adapter_spec.rb +178 -0
- data/spec/lutaml/model/xml_mapping_spec.rb +863 -0
- data/spec/lutaml/model/yaml_adapter_spec.rb +30 -0
- data/spec/lutaml/model_spec.rb +1 -0
- data/spec/person_spec.rb +161 -0
- data/spec/spec_helper.rb +33 -0
- metadata +66 -2
data/lib/lutaml/model/version.rb
CHANGED
@@ -39,6 +39,8 @@ module Lutaml
|
|
39
39
|
)
|
40
40
|
add_namespace_prefix(prefix)
|
41
41
|
|
42
|
+
element_name = "#{element_name}_" if respond_to?(element_name)
|
43
|
+
|
42
44
|
if block_given?
|
43
45
|
public_send(element_name, attributes) do
|
44
46
|
xml.parent.namespace = nil if prefix.nil? && !prefix_unset
|
@@ -54,7 +56,8 @@ module Lutaml
|
|
54
56
|
element = element.xml.parent
|
55
57
|
end
|
56
58
|
|
57
|
-
|
59
|
+
text_node = ::Nokogiri::XML::Text.new(text.to_s, element)
|
60
|
+
element.add_child(text_node)
|
58
61
|
end
|
59
62
|
|
60
63
|
def add_namespace_prefix(prefix)
|
@@ -64,7 +67,7 @@ module Lutaml
|
|
64
67
|
end
|
65
68
|
|
66
69
|
def method_missing(method_name, *args, &block)
|
67
|
-
if
|
70
|
+
if block_given?
|
68
71
|
xml.public_send(method_name, *args, &block)
|
69
72
|
else
|
70
73
|
xml.public_send(method_name, *args)
|
@@ -14,6 +14,7 @@ module Lutaml
|
|
14
14
|
|
15
15
|
def to_xml(options = {})
|
16
16
|
builder = Builder::Ox.build
|
17
|
+
builder.xml.instruct(:xml, encoding: options[:encoding] || "UTF-8", version: options[:version])
|
17
18
|
|
18
19
|
if @root.is_a?(Lutaml::Model::XmlAdapter::OxElement)
|
19
20
|
@root.build_xml(builder)
|
@@ -26,7 +27,7 @@ module Lutaml
|
|
26
27
|
end
|
27
28
|
|
28
29
|
xml_data = builder.xml.to_s
|
29
|
-
options[:declaration] ?
|
30
|
+
options[:declaration] ? xml_data : xml_data.sub(/\A<\?xml[^>]*\?>\n?/, "")
|
30
31
|
end
|
31
32
|
|
32
33
|
private
|
data/lutaml-model.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
# RubyGem that have been added into git.
|
26
26
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
27
27
|
`git ls-files -z`.split("\x0").reject do |f|
|
28
|
-
f.match(%r{^(test|
|
28
|
+
f.match(%r{^(test|features)/})
|
29
29
|
end
|
30
30
|
end
|
31
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "fixtures/address"
|
3
|
+
require_relative "fixtures/person"
|
4
|
+
|
5
|
+
RSpec.describe Address do
|
6
|
+
let(:person1) do
|
7
|
+
{
|
8
|
+
first_name: "Tom",
|
9
|
+
last_name: "Warren",
|
10
|
+
age: 40,
|
11
|
+
height: 5.8,
|
12
|
+
birthdate: Date.new(1980, 2, 15),
|
13
|
+
last_login: "1980-02-15T10:00:00Z",
|
14
|
+
wakeup_time: "07:30:00",
|
15
|
+
active: true,
|
16
|
+
}
|
17
|
+
end
|
18
|
+
let(:person2) do
|
19
|
+
{
|
20
|
+
first_name: "Jack",
|
21
|
+
last_name: "Warren",
|
22
|
+
age: 35,
|
23
|
+
height: 5.9,
|
24
|
+
birthdate: Date.new(1985, 5, 20),
|
25
|
+
last_login: "1985-05-20T09:00:00Z",
|
26
|
+
wakeup_time: "06:45:00",
|
27
|
+
active: false,
|
28
|
+
}
|
29
|
+
end
|
30
|
+
let(:attributes) do
|
31
|
+
{
|
32
|
+
country: "USA",
|
33
|
+
post_code: "01001",
|
34
|
+
person: [person1, person2],
|
35
|
+
}
|
36
|
+
end
|
37
|
+
let(:address) { described_class.new(attributes) }
|
38
|
+
|
39
|
+
it "serializes to JSON with a collection of persons" do
|
40
|
+
expected_json = {
|
41
|
+
country: "USA",
|
42
|
+
postCode: "01001",
|
43
|
+
person: [
|
44
|
+
{
|
45
|
+
firstName: "Tom",
|
46
|
+
lastName: "Warren",
|
47
|
+
age: 40,
|
48
|
+
height: 5.8,
|
49
|
+
birthdate: "1980-02-15",
|
50
|
+
lastLogin: "1980-02-15T10:00:00+00:00",
|
51
|
+
wakeupTime: "07:30:00",
|
52
|
+
active: true,
|
53
|
+
},
|
54
|
+
{
|
55
|
+
firstName: "Jack",
|
56
|
+
lastName: "Warren",
|
57
|
+
age: 35,
|
58
|
+
height: 5.9,
|
59
|
+
birthdate: "1985-05-20",
|
60
|
+
lastLogin: "1985-05-20T09:00:00+00:00",
|
61
|
+
wakeupTime: "06:45:00",
|
62
|
+
active: false,
|
63
|
+
},
|
64
|
+
],
|
65
|
+
}.to_json
|
66
|
+
|
67
|
+
expect(address.to_json).to eq(expected_json)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "deserializes from JSON with a collection of persons" do
|
71
|
+
json = {
|
72
|
+
country: "USA",
|
73
|
+
postCode: "01001",
|
74
|
+
person: [
|
75
|
+
{
|
76
|
+
firstName: "Tom",
|
77
|
+
lastName: "Warren",
|
78
|
+
age: 40,
|
79
|
+
height: 5.8,
|
80
|
+
birthdate: "1980-02-15",
|
81
|
+
lastLogin: "1980-02-15T10:00:00Z",
|
82
|
+
wakeupTime: "07:30:00",
|
83
|
+
active: true,
|
84
|
+
},
|
85
|
+
{
|
86
|
+
firstName: "Jack",
|
87
|
+
lastName: "Warren",
|
88
|
+
age: 35,
|
89
|
+
height: 5.9,
|
90
|
+
birthdate: "1985-05-20",
|
91
|
+
lastLogin: "1985-05-20T09:00:00Z",
|
92
|
+
wakeupTime: "06:45:00",
|
93
|
+
active: false,
|
94
|
+
},
|
95
|
+
],
|
96
|
+
}.to_json
|
97
|
+
|
98
|
+
address_from_json = described_class.from_json(json)
|
99
|
+
expect(address_from_json.country).to eq("USA")
|
100
|
+
expect(address_from_json.post_code).to eq("01001")
|
101
|
+
expect(address_from_json.person.first.first_name).to eq("Tom")
|
102
|
+
expect(address_from_json.person.last.first_name).to eq("Jack")
|
103
|
+
end
|
104
|
+
|
105
|
+
it "serializes to XML with a collection of persons" do
|
106
|
+
expected_xml = <<~XML
|
107
|
+
<Address xmlns:p="http://example.com/person" xmlns:nsp1="http://example.com/nsp1">
|
108
|
+
<Country>USA</Country>
|
109
|
+
<PostCode>01001</PostCode>
|
110
|
+
<p:Person>
|
111
|
+
<nsp1:FirstName>Tom</nsp1:FirstName>
|
112
|
+
<nsp1:LastName>Warren</nsp1:LastName>
|
113
|
+
<p:Age>40</p:Age>
|
114
|
+
<p:Height>5.8</p:Height>
|
115
|
+
<p:Birthdate>1980-02-15</p:Birthdate>
|
116
|
+
<p:LastLogin>1980-02-15T10:00:00+00:00</p:LastLogin>
|
117
|
+
<p:WakeupTime>07:30:00</p:WakeupTime>
|
118
|
+
<p:Active>true</p:Active>
|
119
|
+
</p:Person>
|
120
|
+
<p:Person>
|
121
|
+
<nsp1:FirstName>Jack</nsp1:FirstName>
|
122
|
+
<nsp1:LastName>Warren</nsp1:LastName>
|
123
|
+
<p:Age>35</p:Age>
|
124
|
+
<p:Height>5.9</p:Height>
|
125
|
+
<p:Birthdate>1985-05-20</p:Birthdate>
|
126
|
+
<p:LastLogin>1985-05-20T09:00:00+00:00</p:LastLogin>
|
127
|
+
<p:WakeupTime>06:45:00</p:WakeupTime>
|
128
|
+
<p:Active>false</p:Active>
|
129
|
+
</p:Person>
|
130
|
+
</Address>
|
131
|
+
XML
|
132
|
+
|
133
|
+
expect(address.to_xml).to be_equivalent_to(expected_xml)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "deserializes from XML with a collection of persons" do
|
137
|
+
xml = <<~XML
|
138
|
+
<Address xmlns:p="http://example.com/person" xmlns:nsp1="http://example.com/nsp1">
|
139
|
+
<Country>USA</Country>
|
140
|
+
<PostCode>01001</PostCode>
|
141
|
+
<Person>
|
142
|
+
<nsp1:FirstName>Tom</nsp1:FirstName>
|
143
|
+
<nsp1:LastName>Warren</nsp1:LastName>
|
144
|
+
<Age>40</Age>
|
145
|
+
<Height>5.8</Height>
|
146
|
+
<Birthdate>1980-02-15</Birthdate>
|
147
|
+
<LastLogin>1980-02-15T10:00:00Z</LastLogin>
|
148
|
+
<WakeupTime>07:30:00</WakeupTime>
|
149
|
+
<Active>true</Active>
|
150
|
+
</Person>
|
151
|
+
<Person>
|
152
|
+
<nsp1:FirstName>Jack</nsp1:FirstName>
|
153
|
+
<nsp1:LastName>Warren</nsp1:LastName>
|
154
|
+
<Age>35</Age>
|
155
|
+
<Height>5.9</Height>
|
156
|
+
<Birthdate>1985-05-20</Birthdate>
|
157
|
+
<LastLogin>1985-05-20T09:00:00Z</LastLogin>
|
158
|
+
<WakeupTime>06:45:00</WakeupTime>
|
159
|
+
<Active>false</Active>
|
160
|
+
</Person>
|
161
|
+
</Address>
|
162
|
+
XML
|
163
|
+
|
164
|
+
address_from_xml = described_class.from_xml(xml)
|
165
|
+
expect(address_from_xml.country).to eq("USA")
|
166
|
+
expect(address_from_xml.post_code).to eq("01001")
|
167
|
+
expect(address_from_xml.person.first.first_name).to eq("Tom")
|
168
|
+
expect(address_from_xml.person.last.first_name).to eq("Jack")
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "lutaml/model"
|
2
|
+
require_relative "person"
|
3
|
+
|
4
|
+
class Address < Lutaml::Model::Serializable
|
5
|
+
attribute :country, Lutaml::Model::Type::String
|
6
|
+
attribute :post_code, Lutaml::Model::Type::String
|
7
|
+
attribute :person, Person, collection: true
|
8
|
+
|
9
|
+
json do
|
10
|
+
map "country", to: :country
|
11
|
+
map "postCode", to: :post_code
|
12
|
+
map "person", to: :person
|
13
|
+
end
|
14
|
+
|
15
|
+
xml do
|
16
|
+
root "Address"
|
17
|
+
map_element "Country", to: :country
|
18
|
+
map_element "PostCode", to: :post_code
|
19
|
+
map_element "Person", to: :person
|
20
|
+
end
|
21
|
+
|
22
|
+
yaml do
|
23
|
+
map "country", to: :country
|
24
|
+
map "postCode", to: :post_code
|
25
|
+
map "person", to: :person
|
26
|
+
end
|
27
|
+
|
28
|
+
toml do
|
29
|
+
map "country", to: :country
|
30
|
+
map "post_code", to: :post_code
|
31
|
+
map "person", to: :person
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "lutaml/model"
|
2
|
+
|
3
|
+
class Person < Lutaml::Model::Serializable
|
4
|
+
attribute :first_name, Lutaml::Model::Type::String
|
5
|
+
attribute :last_name, Lutaml::Model::Type::String
|
6
|
+
attribute :age, Lutaml::Model::Type::Integer
|
7
|
+
attribute :height, Lutaml::Model::Type::Float
|
8
|
+
attribute :birthdate, Lutaml::Model::Type::Date
|
9
|
+
attribute :last_login, Lutaml::Model::Type::DateTime
|
10
|
+
attribute :wakeup_time, Lutaml::Model::Type::TimeWithoutDate
|
11
|
+
attribute :active, Lutaml::Model::Type::Boolean
|
12
|
+
|
13
|
+
xml do
|
14
|
+
root "Person"
|
15
|
+
namespace "http://example.com/person", "p"
|
16
|
+
|
17
|
+
map_element "FirstName",
|
18
|
+
to: :first_name,
|
19
|
+
namespace: "http://example.com/nsp1",
|
20
|
+
prefix: "nsp1"
|
21
|
+
map_element "LastName",
|
22
|
+
to: :last_name,
|
23
|
+
namespace: "http://example.com/nsp1",
|
24
|
+
prefix: "nsp1"
|
25
|
+
map_element "Age", to: :age
|
26
|
+
map_element "Height", to: :height
|
27
|
+
map_element "Birthdate", to: :birthdate
|
28
|
+
map_element "LastLogin", to: :last_login
|
29
|
+
map_element "WakeupTime", to: :wakeup_time
|
30
|
+
map_element "Active", to: :active
|
31
|
+
end
|
32
|
+
|
33
|
+
json do
|
34
|
+
map "firstName", to: :first_name
|
35
|
+
map "lastName", to: :last_name
|
36
|
+
map "age", to: :age
|
37
|
+
map "height", to: :height
|
38
|
+
map "birthdate", to: :birthdate
|
39
|
+
map "lastLogin", to: :last_login
|
40
|
+
map "wakeupTime", to: :wakeup_time
|
41
|
+
map "active", to: :active
|
42
|
+
end
|
43
|
+
|
44
|
+
yaml do
|
45
|
+
map "firstName", to: :first_name
|
46
|
+
map "lastName", with: { to: :yaml_from_last_name, from: :yaml_to_last_name }
|
47
|
+
map "age", to: :age
|
48
|
+
map "height", to: :height
|
49
|
+
map "birthdate", to: :birthdate
|
50
|
+
map "lastLogin", to: :last_login
|
51
|
+
map "wakeupTime", to: :wakeup_time
|
52
|
+
map "active", to: :active
|
53
|
+
end
|
54
|
+
|
55
|
+
toml do
|
56
|
+
map "first_name", to: :first_name
|
57
|
+
map "last_name", to: :last_name
|
58
|
+
map "age", to: :age
|
59
|
+
map "height", to: :height
|
60
|
+
map "birthdate", to: :birthdate
|
61
|
+
map "last_login", to: :last_login
|
62
|
+
map "wakeup_time", to: :wakeup_time
|
63
|
+
map "active", to: :active
|
64
|
+
end
|
65
|
+
|
66
|
+
def yaml_from_last_name(model, doc)
|
67
|
+
doc["lastName"] = model.last_name
|
68
|
+
end
|
69
|
+
|
70
|
+
def yaml_to_last_name(model, value)
|
71
|
+
model.last_name = value
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "lutaml/model"
|
2
|
+
|
3
|
+
class SampleModelTag < Lutaml::Model::Serializable
|
4
|
+
attribute :text, :string, default: -> { "" }
|
5
|
+
|
6
|
+
xml do
|
7
|
+
root "Tag"
|
8
|
+
map_content to: :text
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class SampleModel < Lutaml::Model::Serializable
|
13
|
+
attribute :name, :string, default: -> { "Anonymous" }
|
14
|
+
attribute :age, :integer, default: -> { 18 }
|
15
|
+
attribute :balance, :decimal, default: -> { BigDecimal("0.0") }
|
16
|
+
attribute :tags, SampleModelTag, collection: true
|
17
|
+
attribute :preferences, :hash, default: -> { { notifications: true } }
|
18
|
+
attribute :status, :string, default: -> { "active" }
|
19
|
+
attribute :large_number, :integer, default: -> { 0 }
|
20
|
+
attribute :email, :string, default: -> { "example@example.com" }
|
21
|
+
attribute :role, :string, values: %w[user admin guest], default: -> { "user" }
|
22
|
+
|
23
|
+
xml do
|
24
|
+
root "SampleModel"
|
25
|
+
map_element "Name", to: :name
|
26
|
+
map_element "Age", to: :age
|
27
|
+
map_element "Balance", to: :balance
|
28
|
+
map_element "Tags", to: :tags
|
29
|
+
map_element "Preferences", to: :preferences
|
30
|
+
map_element "Status", to: :status
|
31
|
+
map_element "LargeNumber", to: :large_number
|
32
|
+
map_element "Email", to: :email
|
33
|
+
map_element "Role", to: :role
|
34
|
+
end
|
35
|
+
|
36
|
+
yaml do
|
37
|
+
map "name", to: :name
|
38
|
+
map "age", to: :age
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "lutaml/model"
|
2
|
+
|
3
|
+
class Vase < Lutaml::Model::Serializable
|
4
|
+
attribute :height, Lutaml::Model::Type::Float
|
5
|
+
attribute :diameter, Lutaml::Model::Type::Float
|
6
|
+
attribute :material, Lutaml::Model::Type::String
|
7
|
+
attribute :manufacturer, Lutaml::Model::Type::String
|
8
|
+
|
9
|
+
json do
|
10
|
+
map "height", to: :height
|
11
|
+
map "diameter", to: :diameter
|
12
|
+
map "material", to: :material
|
13
|
+
map "manufacturer", to: :manufacturer
|
14
|
+
end
|
15
|
+
|
16
|
+
yaml do
|
17
|
+
map "height", to: :height
|
18
|
+
map "diameter", to: :diameter
|
19
|
+
map "material", to: :material
|
20
|
+
map "manufacturer", to: :manufacturer
|
21
|
+
end
|
22
|
+
|
23
|
+
toml do
|
24
|
+
map "height", to: :height
|
25
|
+
map "diameter", to: :diameter
|
26
|
+
map "material", to: :material
|
27
|
+
map "manufacturer", to: :manufacturer
|
28
|
+
end
|
29
|
+
|
30
|
+
xml do
|
31
|
+
root "vase"
|
32
|
+
namespace "https://example.com/vase/1.0"
|
33
|
+
map_element "height", to: :height
|
34
|
+
map_element "diameter", to: :diameter
|
35
|
+
map_element "material", to: :material
|
36
|
+
map_attribute "manufacturer", to: :manufacturer
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<article>
|
2
|
+
<back>
|
3
|
+
<ref-list>
|
4
|
+
<ref>
|
5
|
+
<element-citation>
|
6
|
+
<source>Continuity of care: report of a scoping exercise for
|
7
|
+
the national co-ordinating centre for NHS Service Delivery and
|
8
|
+
Organisation R&D (NCCSDO), Summer 2000</source>
|
9
|
+
</element-citation>
|
10
|
+
</ref>
|
11
|
+
</ref-list>
|
12
|
+
</back>
|
13
|
+
</article>
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "lutaml/model"
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
RSpec.describe Lutaml::Model::Attribute do
|
6
|
+
subject(:name_attr) do
|
7
|
+
described_class.new("name", :string)
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:test_record_class) do
|
11
|
+
Class.new(Lutaml::Model::Serializable) do
|
12
|
+
attribute :age, :integer
|
13
|
+
attribute :image, :string
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
before do
|
18
|
+
stub_const("TestRecord", test_record_class)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "cast to integer when assigning age" do
|
22
|
+
obj = TestRecord.new
|
23
|
+
|
24
|
+
expect { obj.age = "20" }.to change { obj.age }.from(nil).to(20)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "cast to string when assigning image file" do
|
28
|
+
obj = TestRecord.new
|
29
|
+
|
30
|
+
expect { obj.image = Pathname.new("avatar.png") }
|
31
|
+
.to change { obj.image }
|
32
|
+
.from(nil)
|
33
|
+
.to("avatar.png")
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#validate_type!" do
|
37
|
+
let(:validate_type) { name_attr.method(:validate_type!) }
|
38
|
+
|
39
|
+
it "return true if type is a class" do
|
40
|
+
expect(validate_type.call(TestRecord)).to be(true)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "return true if type is a valid symbol" do
|
44
|
+
expect(validate_type.call(:string)).to be(true)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "return true if type is a valid string" do
|
48
|
+
expect(validate_type.call("String")).to be(true)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "raise exception if type is invalid symbol" do
|
52
|
+
expect do
|
53
|
+
validate_type.call(:foo)
|
54
|
+
end.to raise_error(StandardError, "Unknown Lutaml::Model::Type: foo")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "raise exception if type is invalid string" do
|
58
|
+
expect do
|
59
|
+
validate_type.call("foo")
|
60
|
+
end.to raise_error(StandardError, "Unknown Lutaml::Model::Type: foo")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#cast_type!" do
|
65
|
+
it "cast :string to Lutaml::Model::Type::String" do
|
66
|
+
expect(name_attr.cast_type!(:string)).to eq(Lutaml::Model::Type::String)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "cast :integer to Lutaml::Model::Type::Integer" do
|
70
|
+
expect(name_attr.cast_type!(:integer)).to eq(Lutaml::Model::Type::Integer)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "raises ArgumentError on unknown type" do
|
74
|
+
expect { name_attr.cast_type!(:foobar) }
|
75
|
+
.to raise_error(ArgumentError, "Unknown Lutaml::Model::Type: foobar")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#default?" do
|
80
|
+
context "when default is not set" do
|
81
|
+
let(:attribute) { described_class.new("name", :string) }
|
82
|
+
|
83
|
+
it { expect(attribute.default).to be_nil }
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when default is set as a proc" do
|
87
|
+
it "returns the value" do
|
88
|
+
attribute = described_class.new("name", :string, default: -> { "John" })
|
89
|
+
expect(attribute.default).to eq("John")
|
90
|
+
end
|
91
|
+
|
92
|
+
it "returns the value casted to correct type" do
|
93
|
+
file = Pathname.new("avatar.png")
|
94
|
+
attribute = described_class.new("image", :string, default: -> { file })
|
95
|
+
|
96
|
+
expect(attribute.default).to eq("avatar.png")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when default is set as value" do
|
101
|
+
it "returns the value" do
|
102
|
+
attribute = described_class.new("name", :string, default: "John Doe")
|
103
|
+
expect(attribute.default).to eq("John Doe")
|
104
|
+
end
|
105
|
+
|
106
|
+
it "returns the value casted to correct type" do
|
107
|
+
attribute = described_class.new("age", :integer, default: "24")
|
108
|
+
expect(attribute.default).to eq(24)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|