adf_builder 1.1.0 → 1.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -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 +44 -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: 24b99369efbb491a84bd7a472de00624914228c6de3334e806ab46c7adbb9fa9
|
|
4
|
+
data.tar.gz: c9b0e631fa1118938a976d80e3be092d958c7fc35b7d2fe547bb291c4d4bbff9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8e46cdda771a5c61882464d1e21a4e1117d156c13603877a7cb35e50bc0cd45ef480236a8aa2add261b983e5ed11142f655e9611e6f97cf04c7944305b6c3640
|
|
7
|
+
data.tar.gz: 4560e7057db7c62d8a6bdc90e3b5413c99ae273c5f70a1fd66d621e3a8c3d574ee80e619797c0faf32ce6a6c6fbfd33976fadc3cbda26d66c1a24e673b911447
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [1.2.1] - 2026-01-19
|
|
2
|
+
- **Strict Validations**: Added `presence` validation for `Vehicle` (year, make, model required).
|
|
3
|
+
|
|
4
|
+
## [1.2.0] - 2026-01-19
|
|
5
|
+
- **Strict Validations**: Added validation for `Vehicle` condition, `Option` weighting (range), `Finance` method, and required `ID` source.
|
|
6
|
+
|
|
1
7
|
## [1.1.0] - 2026-01-19
|
|
2
8
|
- **Feature Complete**: Implemented all ADF 1.0 nodes and attributes including `Vendor`, `Provider`, and complex `Vehicle` tags (`Finance`, `Option`, `Odometer`, `ColorCombination`, `ImageTag`, `Price`).
|
|
3
9
|
- **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,6 +26,47 @@ 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
|
+
|
|
29
70
|
class Price < Node
|
|
30
71
|
validates_inclusion_of :type, in: %i[quote offer msrp invoice call appraisal asking]
|
|
31
72
|
validates_inclusion_of :delta, in: %i[absolute relative percentage]
|
|
@@ -76,7 +117,8 @@ module AdfBuilder
|
|
|
76
117
|
end
|
|
77
118
|
|
|
78
119
|
def method(value)
|
|
79
|
-
|
|
120
|
+
remove_children(:method)
|
|
121
|
+
add_child(FinanceMethod.new(value))
|
|
80
122
|
end
|
|
81
123
|
|
|
82
124
|
def amount(value, type: :total, limit: :maximum, currency: nil)
|
|
@@ -107,7 +149,7 @@ module AdfBuilder
|
|
|
107
149
|
end
|
|
108
150
|
|
|
109
151
|
def weighting(value)
|
|
110
|
-
add_child(
|
|
152
|
+
add_child(Weighting.new(value))
|
|
111
153
|
end
|
|
112
154
|
|
|
113
155
|
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