adf_builder 0.4.0 → 1.1.0
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/.gitignore +1 -0
- data/CHANGELOG.md +17 -1
- data/Gemfile.lock +4 -1
- data/README.md +95 -351
- data/adf_builder.gemspec +1 -0
- data/lib/adf_builder/dsl.rb +26 -0
- data/lib/adf_builder/nodes/customer.rb +58 -0
- data/lib/adf_builder/nodes/node.rb +81 -0
- data/lib/adf_builder/nodes/prospect.rb +44 -0
- data/lib/adf_builder/nodes/provider.rb +48 -0
- data/lib/adf_builder/nodes/shared.rb +91 -0
- data/lib/adf_builder/nodes/vehicle.rb +75 -0
- data/lib/adf_builder/nodes/vehicle_nodes.rb +137 -0
- data/lib/adf_builder/nodes/vendor.rb +33 -0
- data/lib/adf_builder/serializer.rb +84 -0
- data/lib/adf_builder/validations.rb +38 -0
- data/lib/adf_builder/version.rb +1 -1
- data/lib/adf_builder.rb +15 -147
- metadata +26 -13
- data/lib/adf_builder/base/base.rb +0 -13
- data/lib/adf_builder/base/prospect.rb +0 -34
- data/lib/adf_builder/base/request_date.rb +0 -22
- data/lib/adf_builder/customer/customer.rb +0 -50
- data/lib/adf_builder/customer/timeframe.rb +0 -44
- data/lib/adf_builder/provider/provider.rb +0 -53
- data/lib/adf_builder/shared/contact.rb +0 -44
- data/lib/adf_builder/shared/id.rb +0 -18
- data/lib/adf_builder/vehicles/colorcombinations.rb +0 -30
- data/lib/adf_builder/vehicles/price.rb +0 -43
- data/lib/adf_builder/vehicles/vehicles.rb +0 -123
- data/lib/adf_builder/vendor/vendor.rb +0 -31
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdfBuilder
|
|
4
|
+
module Nodes
|
|
5
|
+
class Node
|
|
6
|
+
include AdfBuilder::Validations
|
|
7
|
+
|
|
8
|
+
attr_reader :children, :attributes, :value, :tag_name
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@children = []
|
|
12
|
+
@attributes = {}
|
|
13
|
+
@value = nil
|
|
14
|
+
@tag_name = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def add_child(node)
|
|
18
|
+
@children << node
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def remove_children(tag_name)
|
|
22
|
+
@children.reject! { |c| c.tag_name == tag_name }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_xml
|
|
26
|
+
Serializer.to_xml(self)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def method_missing(method_name, *args, &block)
|
|
30
|
+
# Support for dynamic/custom tags
|
|
31
|
+
# usage: custom_tag "value", attr: "val"
|
|
32
|
+
# usage: custom_tag { ... }
|
|
33
|
+
|
|
34
|
+
tag_name = method_name
|
|
35
|
+
attributes = args.last.is_a?(Hash) ? args.last : {}
|
|
36
|
+
value = args.first unless args.first == attributes
|
|
37
|
+
|
|
38
|
+
# If it's a block, it's a structural node
|
|
39
|
+
if block_given?
|
|
40
|
+
node = GenericNode.new(tag_name, attributes)
|
|
41
|
+
node.instance_eval(&block)
|
|
42
|
+
add_child(node)
|
|
43
|
+
# If it has a value, it's a leaf node/element
|
|
44
|
+
elsif value
|
|
45
|
+
node = GenericNode.new(tag_name, attributes, value)
|
|
46
|
+
add_child(node)
|
|
47
|
+
else
|
|
48
|
+
# Just a tag with attributes? e.g. <flag active="true"/>
|
|
49
|
+
node = GenericNode.new(tag_name, attributes)
|
|
50
|
+
add_child(node)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
55
|
+
true
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class GenericNode < Node
|
|
60
|
+
def initialize(tag_name, attributes = {}, value = nil)
|
|
61
|
+
super()
|
|
62
|
+
@tag_name = tag_name
|
|
63
|
+
@attributes = attributes
|
|
64
|
+
@value = value
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class Root < Node
|
|
69
|
+
# The root context of the builder
|
|
70
|
+
def prospect(&block)
|
|
71
|
+
prospect = Prospect.new
|
|
72
|
+
prospect.instance_eval(&block) if block_given?
|
|
73
|
+
add_child(prospect)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def first_prospect
|
|
77
|
+
@children.find { |c| c.is_a?(Prospect) }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdfBuilder
|
|
4
|
+
module Nodes
|
|
5
|
+
class Prospect < Node
|
|
6
|
+
def request_date(date)
|
|
7
|
+
@attributes[:requestdate] = date
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def vehicle(&block)
|
|
11
|
+
vehicle = Vehicle.new
|
|
12
|
+
vehicle.instance_eval(&block) if block_given?
|
|
13
|
+
add_child(vehicle)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def customer(&block)
|
|
17
|
+
customer = Customer.new
|
|
18
|
+
customer.instance_eval(&block) if block_given?
|
|
19
|
+
add_child(customer)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def vendor(&block)
|
|
23
|
+
vendor = Vendor.new
|
|
24
|
+
vendor.instance_eval(&block) if block_given?
|
|
25
|
+
add_child(vendor)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def provider(&block)
|
|
29
|
+
provider = Provider.new
|
|
30
|
+
provider.instance_eval(&block) if block_given?
|
|
31
|
+
add_child(provider)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Helpers for Editing
|
|
35
|
+
def vehicles
|
|
36
|
+
@children.select { |c| c.is_a?(Vehicle) }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def customers
|
|
40
|
+
@children.select { |c| c.is_a?(Customer) }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdfBuilder
|
|
4
|
+
module Nodes
|
|
5
|
+
class Provider < Node
|
|
6
|
+
def initialize
|
|
7
|
+
super
|
|
8
|
+
@tag_name = :provider
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def id(value, sequence: nil, source: nil)
|
|
12
|
+
add_child(Id.new(value, sequence: sequence, source: source))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def name(value, part: nil, type: nil)
|
|
16
|
+
remove_children(:name)
|
|
17
|
+
add_child(Name.new(value, part: part, type: type))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def service(value)
|
|
21
|
+
remove_children(:service)
|
|
22
|
+
add_child(GenericNode.new(:service, {}, value))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def url(value)
|
|
26
|
+
remove_children(:url)
|
|
27
|
+
add_child(GenericNode.new(:url, {}, value))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def email(value, preferredcontact: nil)
|
|
31
|
+
remove_children(:email)
|
|
32
|
+
add_child(Email.new(value, preferredcontact: preferredcontact))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def phone(value, type: nil, time: nil, preferredcontact: nil)
|
|
36
|
+
remove_children(:phone)
|
|
37
|
+
add_child(Phone.new(value, type: type, time: time, preferredcontact: preferredcontact))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def contact(primary_contact: false, &block)
|
|
41
|
+
remove_children(:contact)
|
|
42
|
+
contact = Contact.new(primary_contact: primary_contact)
|
|
43
|
+
contact.instance_eval(&block) if block_given?
|
|
44
|
+
add_child(contact)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdfBuilder
|
|
4
|
+
module Nodes
|
|
5
|
+
class Id < Node
|
|
6
|
+
def initialize(value, sequence: nil, source: nil)
|
|
7
|
+
super()
|
|
8
|
+
@tag_name = :id
|
|
9
|
+
@value = value
|
|
10
|
+
@attributes[:sequence] = sequence if sequence
|
|
11
|
+
@attributes[:source] = source if source
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Phone < Node
|
|
16
|
+
def initialize(value, type: nil, time: nil, preferredcontact: nil)
|
|
17
|
+
super()
|
|
18
|
+
@tag_name = :phone
|
|
19
|
+
@value = value
|
|
20
|
+
@attributes[:type] = type if type
|
|
21
|
+
@attributes[:time] = time if time
|
|
22
|
+
@attributes[:preferredcontact] = preferredcontact if preferredcontact
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Email < Node
|
|
27
|
+
def initialize(value, preferredcontact: nil)
|
|
28
|
+
super()
|
|
29
|
+
@tag_name = :email
|
|
30
|
+
@value = value
|
|
31
|
+
@attributes[:preferredcontact] = preferredcontact if preferredcontact
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class Name < Node
|
|
36
|
+
def initialize(value, part: nil, type: nil)
|
|
37
|
+
super()
|
|
38
|
+
@tag_name = :name
|
|
39
|
+
@value = value
|
|
40
|
+
@attributes[:part] = part if part
|
|
41
|
+
@attributes[:type] = type if type
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Address < Node
|
|
46
|
+
def initialize(type: nil)
|
|
47
|
+
super()
|
|
48
|
+
@tag_name = :address
|
|
49
|
+
@attributes[:type] = type if type
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def street(value, line: nil)
|
|
53
|
+
node = GenericNode.new(:street, { line: line }.compact, value)
|
|
54
|
+
add_child(node)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Simple elements
|
|
58
|
+
%i[apartment city regioncode postalcode country].each do |tag|
|
|
59
|
+
define_method(tag) do |value|
|
|
60
|
+
add_child(GenericNode.new(tag, {}, value))
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class Contact < Node
|
|
66
|
+
def initialize(primary_contact: false)
|
|
67
|
+
super()
|
|
68
|
+
@tag_name = :contact
|
|
69
|
+
# primary_contact might be useful for logic but not an attribute
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def name(value, part: nil, type: nil)
|
|
73
|
+
add_child(Name.new(value, part: part, type: type))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def email(value, preferredcontact: nil)
|
|
77
|
+
add_child(Email.new(value, preferredcontact: preferredcontact))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def phone(value, type: nil, time: nil, preferredcontact: nil)
|
|
81
|
+
add_child(Phone.new(value, type: type, time: time, preferredcontact: preferredcontact))
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def address(type: nil, &block)
|
|
85
|
+
addr = Address.new(type: type)
|
|
86
|
+
addr.instance_eval(&block) if block_given?
|
|
87
|
+
add_child(addr)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdfBuilder
|
|
4
|
+
module Nodes
|
|
5
|
+
class Vehicle < Node
|
|
6
|
+
validates_inclusion_of :status, in: %i[new used]
|
|
7
|
+
validates_inclusion_of :interest, in: %i[buy lease sell trade-in test-drive]
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
super
|
|
11
|
+
@tag_name = :vehicle
|
|
12
|
+
@attributes[:status] = :new
|
|
13
|
+
@attributes[:interest] = :buy
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Simple Text Elements (Singular)
|
|
17
|
+
%i[year make model vin stock trim doors bodystyle transmission condition pricecomments comments].each do |tag|
|
|
18
|
+
define_method(tag) do |value|
|
|
19
|
+
remove_children(tag)
|
|
20
|
+
add_child(GenericNode.new(tag, {}, value))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def interest(value)
|
|
25
|
+
@attributes[:interest] = value
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def status(value)
|
|
29
|
+
@attributes[:status] = value
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Complex Elements
|
|
33
|
+
def id(value, sequence: nil, source: nil)
|
|
34
|
+
# id* is multiple, so just add
|
|
35
|
+
add_child(Id.new(value, sequence: sequence, source: source))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def odometer(value, status: nil, units: nil)
|
|
39
|
+
remove_children(:odometer)
|
|
40
|
+
add_child(Odometer.new(value, status: status, units: units))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def imagetag(value, width: nil, height: nil, alttext: nil)
|
|
44
|
+
remove_children(:imagetag)
|
|
45
|
+
add_child(ImageTag.new(value, width: width, height: height, alttext: alttext))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def price(value, **attrs)
|
|
49
|
+
remove_children(:price)
|
|
50
|
+
add_child(Price.new(value, **attrs))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def option(&block)
|
|
54
|
+
# option* is multiple
|
|
55
|
+
opt = Option.new
|
|
56
|
+
opt.instance_eval(&block) if block_given?
|
|
57
|
+
add_child(opt)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def finance(&block)
|
|
61
|
+
remove_children(:finance)
|
|
62
|
+
fin = Finance.new
|
|
63
|
+
fin.instance_eval(&block) if block_given?
|
|
64
|
+
add_child(fin)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def colorcombination(&block)
|
|
68
|
+
# colorcombination* is multiple
|
|
69
|
+
cc = ColorCombination.new
|
|
70
|
+
cc.instance_eval(&block) if block_given?
|
|
71
|
+
add_child(cc)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdfBuilder
|
|
4
|
+
module Nodes
|
|
5
|
+
class Odometer < Node
|
|
6
|
+
validates_inclusion_of :status, in: %i[unknown rolledover replaced original]
|
|
7
|
+
validates_inclusion_of :units, in: %i[km mi]
|
|
8
|
+
|
|
9
|
+
def initialize(value, status: nil, units: nil)
|
|
10
|
+
super()
|
|
11
|
+
@tag_name = :odometer
|
|
12
|
+
@value = value
|
|
13
|
+
@attributes[:status] = status if status
|
|
14
|
+
@attributes[:units] = units if units
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class ImageTag < Node
|
|
19
|
+
def initialize(value, width: nil, height: nil, alttext: nil)
|
|
20
|
+
super()
|
|
21
|
+
@tag_name = :imagetag
|
|
22
|
+
@value = value
|
|
23
|
+
@attributes[:width] = width if width
|
|
24
|
+
@attributes[:height] = height if height
|
|
25
|
+
@attributes[:alttext] = alttext if alttext
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class Price < Node
|
|
30
|
+
validates_inclusion_of :type, in: %i[quote offer msrp invoice call appraisal asking]
|
|
31
|
+
validates_inclusion_of :delta, in: %i[absolute relative percentage]
|
|
32
|
+
validates_inclusion_of :relativeto, in: %i[msrp invoice]
|
|
33
|
+
|
|
34
|
+
def initialize(value, type: :quote, currency: nil, delta: nil, relativeto: nil, source: nil)
|
|
35
|
+
super()
|
|
36
|
+
@tag_name = :price
|
|
37
|
+
@value = value
|
|
38
|
+
@attributes[:type] = type
|
|
39
|
+
@attributes[:currency] = currency if currency
|
|
40
|
+
@attributes[:delta] = delta if delta
|
|
41
|
+
@attributes[:relativeto] = relativeto if relativeto
|
|
42
|
+
@attributes[:source] = source if source
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class Amount < Node
|
|
47
|
+
validates_inclusion_of :type, in: %i[downpayment monthly total]
|
|
48
|
+
validates_inclusion_of :limit, in: %i[maximum minimum exact]
|
|
49
|
+
|
|
50
|
+
def initialize(value, type: :total, limit: :maximum, currency: nil)
|
|
51
|
+
super()
|
|
52
|
+
@tag_name = :amount
|
|
53
|
+
@value = value
|
|
54
|
+
@attributes[:type] = type
|
|
55
|
+
@attributes[:limit] = limit
|
|
56
|
+
@attributes[:currency] = currency if currency
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class Balance < Node
|
|
61
|
+
validates_inclusion_of :type, in: %i[finance residual]
|
|
62
|
+
|
|
63
|
+
def initialize(value, type: :finance, currency: nil)
|
|
64
|
+
super()
|
|
65
|
+
@tag_name = :balance
|
|
66
|
+
@value = value
|
|
67
|
+
@attributes[:type] = type
|
|
68
|
+
@attributes[:currency] = currency if currency
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class Finance < Node
|
|
73
|
+
def initialize
|
|
74
|
+
super
|
|
75
|
+
@tag_name = :finance
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def method(value)
|
|
79
|
+
add_child(GenericNode.new(:method, {}, value))
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def amount(value, type: :total, limit: :maximum, currency: nil)
|
|
83
|
+
add_child(Amount.new(value, type: type, limit: limit, currency: currency))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def balance(value, type: :finance, currency: nil)
|
|
87
|
+
add_child(Balance.new(value, type: type, currency: currency))
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class Option < Node
|
|
92
|
+
def initialize
|
|
93
|
+
super
|
|
94
|
+
@tag_name = :option
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def optionname(value)
|
|
98
|
+
add_child(GenericNode.new(:optionname, {}, value))
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def manufacturercode(value)
|
|
102
|
+
add_child(GenericNode.new(:manufacturercode, {}, value))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def stock(value)
|
|
106
|
+
add_child(GenericNode.new(:stock, {}, value))
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def weighting(value)
|
|
110
|
+
add_child(GenericNode.new(:weighting, {}, value))
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def price(value, **attrs)
|
|
114
|
+
add_child(Price.new(value, **attrs))
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
class ColorCombination < Node
|
|
119
|
+
def initialize
|
|
120
|
+
super
|
|
121
|
+
@tag_name = :colorcombination
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def interiorcolor(value)
|
|
125
|
+
add_child(GenericNode.new(:interiorcolor, {}, value))
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def exteriorcolor(value)
|
|
129
|
+
add_child(GenericNode.new(:exteriorcolor, {}, value))
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def preference(value)
|
|
133
|
+
add_child(GenericNode.new(:preference, {}, value))
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdfBuilder
|
|
4
|
+
module Nodes
|
|
5
|
+
class Vendor < Node
|
|
6
|
+
def initialize
|
|
7
|
+
super
|
|
8
|
+
@tag_name = :vendor
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def id(value, sequence: nil, source: nil)
|
|
12
|
+
add_child(Id.new(value, sequence: sequence, source: source))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def vendorname(value)
|
|
16
|
+
remove_children(:vendorname)
|
|
17
|
+
add_child(GenericNode.new(:vendorname, {}, value))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def url(value)
|
|
21
|
+
remove_children(:url)
|
|
22
|
+
add_child(GenericNode.new(:url, {}, value))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def contact(primary_contact: false, &block)
|
|
26
|
+
remove_children(:contact)
|
|
27
|
+
contact = Contact.new(primary_contact: primary_contact)
|
|
28
|
+
contact.instance_eval(&block) if block_given?
|
|
29
|
+
add_child(contact)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ox"
|
|
4
|
+
|
|
5
|
+
module AdfBuilder
|
|
6
|
+
class Serializer
|
|
7
|
+
def self.to_xml(node)
|
|
8
|
+
new(node).to_xml
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(root_node)
|
|
12
|
+
@root_node = root_node
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_xml
|
|
16
|
+
doc = Ox::Document.new
|
|
17
|
+
|
|
18
|
+
# XML Instruction
|
|
19
|
+
instruct = Ox::Instruct.new(:xml)
|
|
20
|
+
instruct[:version] = "1.0"
|
|
21
|
+
doc << instruct
|
|
22
|
+
|
|
23
|
+
# ADF Instruction
|
|
24
|
+
adf_instruct = Ox::Instruct.new("ADF")
|
|
25
|
+
adf_instruct[:version] = "1.0"
|
|
26
|
+
doc << adf_instruct
|
|
27
|
+
|
|
28
|
+
# ADF Root Element
|
|
29
|
+
adf = Ox::Element.new("adf")
|
|
30
|
+
doc << adf
|
|
31
|
+
|
|
32
|
+
@root_node.children.each do |child|
|
|
33
|
+
serialize_node(child, adf)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Ox.dump(doc)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def serialize_node(node, parent_element)
|
|
42
|
+
# Determine element name using tag_name to avoid conflict with DSL methods like 'name'
|
|
43
|
+
# Safest check: Does it have the instance variable set?
|
|
44
|
+
element_name = if node.instance_variable_defined?(:@tag_name) && node.instance_variable_get(:@tag_name)
|
|
45
|
+
node.instance_variable_get(:@tag_name).to_s
|
|
46
|
+
else
|
|
47
|
+
node.class.name.split("::").last.downcase
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# puts "DEBUG: Serializing #{node.class} as <#{element_name}>"
|
|
51
|
+
|
|
52
|
+
element = Ox::Element.new(element_name)
|
|
53
|
+
|
|
54
|
+
# Add attributes (XML attributes) or Simple Child Elements
|
|
55
|
+
node.attributes.each do |key, value|
|
|
56
|
+
if attribute?(key)
|
|
57
|
+
element[key] = value.to_s
|
|
58
|
+
else
|
|
59
|
+
# It's a simple child element
|
|
60
|
+
child_el = Ox::Element.new(key.to_s)
|
|
61
|
+
child_el << value.to_s
|
|
62
|
+
element << child_el
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Add Node-level Text Content (e.g. <name>John</name>)
|
|
67
|
+
element << node.value.to_s if node.respond_to?(:value) && node.value
|
|
68
|
+
|
|
69
|
+
# Recursively add children nodes
|
|
70
|
+
node.children.each do |child|
|
|
71
|
+
serialize_node(child, element)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
parent_element << element
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def attribute?(key)
|
|
78
|
+
%i[
|
|
79
|
+
part type status sequence source id valid preferredcontact time
|
|
80
|
+
interest units width height alttext limit currency delta relativeto line
|
|
81
|
+
].include?(key)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdfBuilder
|
|
4
|
+
module Validations
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def validates_inclusion_of(attribute, in:)
|
|
11
|
+
@validations ||= []
|
|
12
|
+
@validations << { type: :inclusion, attribute: attribute, in: binding.local_variable_get(:in) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def validations
|
|
16
|
+
@validations || []
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def validate!
|
|
21
|
+
self.class.validations.each do |validation|
|
|
22
|
+
value = @attributes[validation[:attribute]]
|
|
23
|
+
next if value.nil? # Allow nil unless presence validation is added
|
|
24
|
+
|
|
25
|
+
next unless validation[:type] == :inclusion
|
|
26
|
+
|
|
27
|
+
allowed = validation[:in]
|
|
28
|
+
unless allowed.include?(value)
|
|
29
|
+
raise AdfBuilder::Error,
|
|
30
|
+
"Invalid value for #{validation[:attribute]}: #{value}. Allowed: #{allowed.join(", ")}"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Recursively validate children
|
|
35
|
+
@children.each(&:validate!)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/adf_builder/version.rb
CHANGED