adf_builder 1.1.0 → 1.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +1 -1
- data/lib/adf_builder/nodes/shared.rb +4 -2
- data/lib/adf_builder/nodes/vehicle.rb +8 -1
- data/lib/adf_builder/nodes/vehicle_nodes.rb +57 -2
- data/lib/adf_builder/serializer.rb +8 -3
- data/lib/adf_builder/validations.rb +22 -8
- data/lib/adf_builder/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f5c6497310cd559356bd6e358243d2dd2ed5d2a859330fe403ae959b32592b0b
|
|
4
|
+
data.tar.gz: 77e66f74d658adc2022d401d85a037549f8f92c91d984c265db337a33c05353c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8aba468994e77c3af346c7f6dccbdd4eed16fd858ccf6206226c90d97a5e1126d75bc5083440d40ce1ac3233d2b6f0395b899fcce70afc76ccba7691867e779f
|
|
7
|
+
data.tar.gz: 215970d63f001f71e21c55651368c9ebab28dafd9e5f26d19519dbff6c897ed4859443623f01d3a99a5c014743d00f8e74b351eda0b371d28e578edc744d5582
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## [1.2.2] - 2026-01-19
|
|
2
|
+
- **Strict Validations**: Added ISO 4217 currency validation for `Price`, `Amount`, and `Balance`.
|
|
3
|
+
|
|
4
|
+
## [1.2.1] - 2026-01-19
|
|
5
|
+
- **Strict Validations**: Added `presence` validation for `Vehicle` (year, make, model required).
|
|
6
|
+
|
|
7
|
+
## [1.2.0] - 2026-01-19
|
|
8
|
+
- **Strict Validations**: Added validation for `Vehicle` condition, `Option` weighting (range), `Finance` method, and required `ID` source.
|
|
9
|
+
|
|
1
10
|
## [1.1.0] - 2026-01-19
|
|
2
11
|
- **Feature Complete**: Implemented all ADF 1.0 nodes and attributes including `Vendor`, `Provider`, and complex `Vehicle` tags (`Finance`, `Option`, `Odometer`, `ColorCombination`, `ImageTag`, `Price`).
|
|
3
12
|
- **Singular Field logic**: Methods for singular fields (e.g. `vehicle.year`) now correctly replace existing values instead of appending.
|
data/Gemfile.lock
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
module AdfBuilder
|
|
4
4
|
module Nodes
|
|
5
5
|
class Id < Node
|
|
6
|
-
def initialize(value, sequence: nil
|
|
6
|
+
def initialize(value, source:, sequence: nil)
|
|
7
7
|
super()
|
|
8
|
+
raise ArgumentError, "Source is required" if source.nil?
|
|
9
|
+
|
|
8
10
|
@tag_name = :id
|
|
9
11
|
@value = value
|
|
10
12
|
@attributes[:sequence] = sequence if sequence
|
|
11
|
-
@attributes[:source] = source
|
|
13
|
+
@attributes[:source] = source
|
|
12
14
|
end
|
|
13
15
|
end
|
|
14
16
|
|
|
@@ -5,6 +5,7 @@ module AdfBuilder
|
|
|
5
5
|
class Vehicle < Node
|
|
6
6
|
validates_inclusion_of :status, in: %i[new used]
|
|
7
7
|
validates_inclusion_of :interest, in: %i[buy lease sell trade-in test-drive]
|
|
8
|
+
validates_presence_of :year, :make, :model
|
|
8
9
|
|
|
9
10
|
def initialize
|
|
10
11
|
super
|
|
@@ -14,13 +15,19 @@ module AdfBuilder
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
# Simple Text Elements (Singular)
|
|
17
|
-
|
|
18
|
+
# Simple Text Elements (Singular)
|
|
19
|
+
%i[year make model vin stock trim doors bodystyle transmission pricecomments comments].each do |tag|
|
|
18
20
|
define_method(tag) do |value|
|
|
19
21
|
remove_children(tag)
|
|
20
22
|
add_child(GenericNode.new(tag, {}, value))
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
|
|
26
|
+
def condition(value)
|
|
27
|
+
remove_children(:condition)
|
|
28
|
+
add_child(Condition.new(value))
|
|
29
|
+
end
|
|
30
|
+
|
|
24
31
|
def interest(value)
|
|
25
32
|
@attributes[:interest] = value
|
|
26
33
|
end
|
|
@@ -26,10 +26,62 @@ module AdfBuilder
|
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
class Condition < Node
|
|
30
|
+
VALID_VALUES = %w[excellent good fair poor unknown].freeze
|
|
31
|
+
|
|
32
|
+
def initialize(value)
|
|
33
|
+
super()
|
|
34
|
+
@tag_name = :condition
|
|
35
|
+
unless VALID_VALUES.include?(value.to_s.downcase)
|
|
36
|
+
raise AdfBuilder::Error, "Invalid condition: #{value}. Must be one of: #{VALID_VALUES.join(", ")}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@value = value
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class Weighting < Node
|
|
44
|
+
def initialize(value)
|
|
45
|
+
super()
|
|
46
|
+
@tag_name = :weighting
|
|
47
|
+
int_val = value.to_i
|
|
48
|
+
unless int_val.between?(-100, 100)
|
|
49
|
+
raise AdfBuilder::Error, "Weighting must be between -100 and 100. Got: #{value}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
@value = value
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class FinanceMethod < Node
|
|
57
|
+
VALID_VALUES = %w[cash finance lease].freeze
|
|
58
|
+
|
|
59
|
+
def initialize(value)
|
|
60
|
+
super()
|
|
61
|
+
@tag_name = :method
|
|
62
|
+
unless VALID_VALUES.include?(value.to_s.downcase)
|
|
63
|
+
raise AdfBuilder::Error, "Invalid finance method: #{value}. Must be one of: #{VALID_VALUES.join(", ")}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@value = value
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Common ISO 4217 codes (Top valid ones per spec/common usage)
|
|
71
|
+
# Keeping it as a constant for reuse.
|
|
72
|
+
# This list can be expanded but covers major currencies.
|
|
73
|
+
ISO_4217 = %w[
|
|
74
|
+
USD EUR GBP JPY AUD CAD CHF CNY SEK NZD
|
|
75
|
+
MXN SGD HKD NOK KRW TRY RUB INR BRL ZAR
|
|
76
|
+
DKK PLN TWD THB IDR HUF CZK ILS CLP PHP
|
|
77
|
+
AED COP SAR MYR RON PEN VND NGN
|
|
78
|
+
].freeze
|
|
79
|
+
|
|
29
80
|
class Price < Node
|
|
30
81
|
validates_inclusion_of :type, in: %i[quote offer msrp invoice call appraisal asking]
|
|
31
82
|
validates_inclusion_of :delta, in: %i[absolute relative percentage]
|
|
32
83
|
validates_inclusion_of :relativeto, in: %i[msrp invoice]
|
|
84
|
+
validates_inclusion_of :currency, in: ISO_4217
|
|
33
85
|
|
|
34
86
|
def initialize(value, type: :quote, currency: nil, delta: nil, relativeto: nil, source: nil)
|
|
35
87
|
super()
|
|
@@ -46,6 +98,7 @@ module AdfBuilder
|
|
|
46
98
|
class Amount < Node
|
|
47
99
|
validates_inclusion_of :type, in: %i[downpayment monthly total]
|
|
48
100
|
validates_inclusion_of :limit, in: %i[maximum minimum exact]
|
|
101
|
+
validates_inclusion_of :currency, in: ISO_4217
|
|
49
102
|
|
|
50
103
|
def initialize(value, type: :total, limit: :maximum, currency: nil)
|
|
51
104
|
super()
|
|
@@ -59,6 +112,7 @@ module AdfBuilder
|
|
|
59
112
|
|
|
60
113
|
class Balance < Node
|
|
61
114
|
validates_inclusion_of :type, in: %i[finance residual]
|
|
115
|
+
validates_inclusion_of :currency, in: ISO_4217
|
|
62
116
|
|
|
63
117
|
def initialize(value, type: :finance, currency: nil)
|
|
64
118
|
super()
|
|
@@ -76,7 +130,8 @@ module AdfBuilder
|
|
|
76
130
|
end
|
|
77
131
|
|
|
78
132
|
def method(value)
|
|
79
|
-
|
|
133
|
+
remove_children(:method)
|
|
134
|
+
add_child(FinanceMethod.new(value))
|
|
80
135
|
end
|
|
81
136
|
|
|
82
137
|
def amount(value, type: :total, limit: :maximum, currency: nil)
|
|
@@ -107,7 +162,7 @@ module AdfBuilder
|
|
|
107
162
|
end
|
|
108
163
|
|
|
109
164
|
def weighting(value)
|
|
110
|
-
add_child(
|
|
165
|
+
add_child(Weighting.new(value))
|
|
111
166
|
end
|
|
112
167
|
|
|
113
168
|
def price(value, **attrs)
|
|
@@ -4,8 +4,10 @@ require "ox"
|
|
|
4
4
|
|
|
5
5
|
module AdfBuilder
|
|
6
6
|
class Serializer
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
class << self
|
|
8
|
+
def to_xml(root_node)
|
|
9
|
+
new(root_node).to_xml
|
|
10
|
+
end
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
def initialize(root_node)
|
|
@@ -13,7 +15,10 @@ module AdfBuilder
|
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def to_xml
|
|
16
|
-
|
|
18
|
+
# Validate the entire tree before serializing to ensure data integrity
|
|
19
|
+
@root_node.validate!
|
|
20
|
+
|
|
21
|
+
doc = Ox::Document.new(version: "1.0")
|
|
17
22
|
|
|
18
23
|
# XML Instruction
|
|
19
24
|
instruct = Ox::Instruct.new(:xml)
|
|
@@ -12,6 +12,13 @@ module AdfBuilder
|
|
|
12
12
|
@validations << { type: :inclusion, attribute: attribute, in: binding.local_variable_get(:in) }
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
def validates_presence_of(*attributes)
|
|
16
|
+
@validations ||= []
|
|
17
|
+
attributes.each do |attr|
|
|
18
|
+
@validations << { type: :presence, attribute: attr }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
15
22
|
def validations
|
|
16
23
|
@validations || []
|
|
17
24
|
end
|
|
@@ -19,15 +26,22 @@ module AdfBuilder
|
|
|
19
26
|
|
|
20
27
|
def validate!
|
|
21
28
|
self.class.validations.each do |validation|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
next unless validation[:type] == :inclusion
|
|
29
|
+
if validation[:type] == :inclusion
|
|
30
|
+
value = @attributes[validation[:attribute]]
|
|
31
|
+
next if value.nil?
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
allowed = validation[:in]
|
|
34
|
+
unless allowed.include?(value)
|
|
35
|
+
raise AdfBuilder::Error,
|
|
36
|
+
"Invalid value for #{validation[:attribute]}: #{value}. Allowed: #{allowed.join(", ")}"
|
|
37
|
+
end
|
|
38
|
+
elsif validation[:type] == :presence
|
|
39
|
+
# Check children for a node with tag_name == attribute
|
|
40
|
+
target_tag = validation[:attribute]
|
|
41
|
+
found = @children.any? { |c| c.tag_name == target_tag }
|
|
42
|
+
unless found
|
|
43
|
+
raise AdfBuilder::Error, "Missing required Element: #{target_tag} in #{tag_name || self.class.name}"
|
|
44
|
+
end
|
|
31
45
|
end
|
|
32
46
|
end
|
|
33
47
|
|
data/lib/adf_builder/version.rb
CHANGED