adf_builder 1.0.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.
@@ -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
- value = @attributes[validation[:attribute]]
23
- next if value.nil? # Allow nil unless presence validation is added
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
- allowed = validation[:in]
28
- unless allowed.include?(value)
29
- raise AdfBuilder::Error,
30
- "Invalid value for #{validation[:attribute]}: #{value}. Allowed: #{allowed.join(", ")}"
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AdfBuilder
4
- VERSION = "1.0.0"
4
+ VERSION = "1.2.1"
5
5
  end
data/lib/adf_builder.rb CHANGED
@@ -4,164 +4,22 @@ require "ox"
4
4
  require "json"
5
5
 
6
6
  require_relative "adf_builder/version"
7
-
8
- # CUSTOMER
9
- require_relative "adf_builder/customer/customer"
10
- require_relative "adf_builder/customer/timeframe"
11
-
12
- # BASE
13
- require_relative "adf_builder/base/base"
14
- require_relative "adf_builder/base/prospect"
15
- require_relative "adf_builder/base/request_date"
16
-
17
- # PROVIDER
18
- require_relative "adf_builder/provider/provider"
19
-
20
- # SHARED
21
- require_relative "adf_builder/shared/id"
22
- require_relative "adf_builder/shared/contact"
23
-
24
- # VEHICLES
25
- require_relative "adf_builder/vehicles/vehicles"
26
- require_relative "adf_builder/vehicles/colorcombinations"
27
- require_relative "adf_builder/vehicles/price"
28
-
29
- # VENDOR
30
- require_relative "adf_builder/vendor/vendor"
31
-
32
- # v1.0 DSL
33
- # v1.0 DSL
34
7
  require_relative "adf_builder/validations"
8
+
9
+ # Nodes
35
10
  require_relative "adf_builder/nodes/node"
36
11
  require_relative "adf_builder/nodes/prospect"
12
+ require_relative "adf_builder/nodes/shared"
37
13
  require_relative "adf_builder/nodes/vehicle"
14
+ require_relative "adf_builder/nodes/vehicle_nodes"
38
15
  require_relative "adf_builder/nodes/customer"
16
+ require_relative "adf_builder/nodes/vendor"
17
+ require_relative "adf_builder/nodes/provider"
18
+
19
+ # Core
39
20
  require_relative "adf_builder/serializer"
40
21
  require_relative "adf_builder/dsl"
41
22
 
42
23
  module AdfBuilder
43
24
  class Error < StandardError; end
44
-
45
- class Builder
46
- def initialize
47
- @doc = init_doc
48
- @base = Base.new(@doc)
49
- end
50
-
51
- def prospect
52
- @base.prospect
53
- end
54
-
55
- # output the XML
56
- def to_xml
57
- Ox.dump(@doc, {})
58
- end
59
-
60
- # def an example of minimal XML taken from ADF spec file http://adfxml.info/adf_spec.pdf
61
- def minimal_lead
62
- prospect = Ox::Element.new("prospect")
63
-
64
- request_date = Ox::Element.new("requestdate")
65
- request_date << "2000-03-30T15:30:20-08:00"
66
-
67
- vehicle = Ox::Element.new("vehicle")
68
- year = Ox::Element.new("year")
69
- year << "1999"
70
-
71
- make = Ox::Element.new("make")
72
- make << "Chevrolet"
73
-
74
- model = Ox::Element.new("model")
75
- model << "Blazer"
76
-
77
- vehicle << year << make << model
78
-
79
- customer = Ox::Element.new("customer")
80
-
81
- contact = Ox::Element.new("contact")
82
-
83
- name = Ox::Element.new("name")
84
- name[:part] = "full"
85
- name << "John Doe"
86
-
87
- phone = Ox::Element.new("phone")
88
- phone << "393-999-3922"
89
-
90
- contact << name << phone
91
- customer << contact
92
-
93
- vendor = Ox::Element.new("vendor")
94
-
95
- contact = Ox::Element.new("contact")
96
- name = Ox::Element.new("name")
97
- name[:part] = "full"
98
- name << "Acura of Bellevue"
99
-
100
- contact << name
101
- vendor << contact
102
-
103
- prospect << request_date << vehicle << customer << vendor
104
- @doc.remove_children_by_path("adf/prospect")
105
- @doc.adf << prospect
106
- Ox.dump(@doc, {})
107
- end
108
-
109
- # go back to the initial structure
110
- def reset_doc
111
- @doc.adf.prospect.remove_children_by_path("*")
112
- end
113
-
114
- # all the files will start with this same header
115
- def init_doc
116
- doc = Ox::Document.new
117
- instruct = Ox::Instruct.new(:xml)
118
- instruct[:version] = "1.0"
119
- doc << instruct
120
- doc << Ox::Raw.new("")
121
- instruct = Ox::Instruct.new("ADF")
122
- instruct[:version] = "1.0"
123
- doc << instruct
124
- adf = Ox::Element.new("adf")
125
- doc << adf
126
- doc
127
- end
128
-
129
- # we will either create a new node with the value or replace the one if it is available
130
- def self.update_node(parent_node, key, value, params = {})
131
- key = key.to_s
132
- value = value.to_s
133
- if parent_node.locate(key).size.positive?
134
- node = parent_node.locate(key).first
135
- node.replace_text(value)
136
- else
137
- node = (Ox::Element.new(key) << value)
138
- parent_node << node
139
- end
140
-
141
- AdfBuilder::Builder.update_params(node, key, params)
142
- end
143
-
144
- # update the params by first checking if they are valid params and then checking if the values are valid if necessary
145
- def self.update_params(node, key, params)
146
- return true if params.empty?
147
-
148
- key = key.to_sym
149
- valid_values = params[:valid_values]
150
- valid_parameters = params[:valid_parameters]
151
- _params = AdfBuilder::Builder.whitelabel_params(params, valid_parameters, key)
152
- _params.each do |k, v|
153
- node[k] = v if (valid_values[key][k] == true) || valid_values[key][k].include?(v.to_s)
154
- end
155
- end
156
-
157
- # clear out the opts that don't match valid keys
158
- def self.whitelabel_params(opts, valid_parameters, key)
159
- opts.slice(*valid_parameters[key])
160
- end
161
-
162
- def self.valid_child?(parent, tag_name, index)
163
- child = parent.locate(tag_name)[index]
164
- [!child.nil?, child]
165
- end
166
- end
167
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adf_builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - marcus.salinas
@@ -100,26 +100,18 @@ files:
100
100
  - bin/console
101
101
  - bin/setup
102
102
  - lib/adf_builder.rb
103
- - lib/adf_builder/base/base.rb
104
- - lib/adf_builder/base/prospect.rb
105
- - lib/adf_builder/base/request_date.rb
106
- - lib/adf_builder/customer/customer.rb
107
- - lib/adf_builder/customer/timeframe.rb
108
103
  - lib/adf_builder/data/iso-4217-currency-codes.json
109
104
  - lib/adf_builder/dsl.rb
110
105
  - lib/adf_builder/nodes/customer.rb
111
106
  - lib/adf_builder/nodes/node.rb
112
107
  - lib/adf_builder/nodes/prospect.rb
108
+ - lib/adf_builder/nodes/provider.rb
109
+ - lib/adf_builder/nodes/shared.rb
113
110
  - lib/adf_builder/nodes/vehicle.rb
114
- - lib/adf_builder/provider/provider.rb
111
+ - lib/adf_builder/nodes/vehicle_nodes.rb
112
+ - lib/adf_builder/nodes/vendor.rb
115
113
  - lib/adf_builder/serializer.rb
116
- - lib/adf_builder/shared/contact.rb
117
- - lib/adf_builder/shared/id.rb
118
114
  - lib/adf_builder/validations.rb
119
- - lib/adf_builder/vehicles/colorcombinations.rb
120
- - lib/adf_builder/vehicles/price.rb
121
- - lib/adf_builder/vehicles/vehicles.rb
122
- - lib/adf_builder/vendor/vendor.rb
123
115
  - lib/adf_builder/version.rb
124
116
  homepage: https://github.com/jippylong12/adf_builder
125
117
  licenses:
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class Base
5
- # initialize the prospect, id, and requestdate node
6
- def initialize(doc)
7
- @doc = doc
8
- @prospect = Prospect.new(@doc)
9
- end
10
-
11
- attr_reader :prospect
12
- end
13
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class Prospect
5
- STATUSES = {
6
- new: :new,
7
- resend: :resend
8
- }.freeze
9
-
10
- def initialize(doc)
11
- @doc = doc
12
- @doc.adf << Ox::Element.new("prospect")
13
- @prospect = @doc.adf.prospect
14
- @prospect[:status] = STATUSES[:new]
15
-
16
- @request_date = RequestDate.new(@prospect)
17
- @vehicles = Vehicles.new(@prospect)
18
- @customer = Customer.new(@prospect)
19
- @vendor = Vendor.new(@prospect)
20
- @provider = Provider.new(@prospect)
21
- end
22
-
23
- attr_reader :request_date, :vehicles, :customer, :vendor, :provider
24
-
25
- # set status to renew
26
- def set_renew
27
- @prospect[:status] = STATUSES[:resend]
28
- end
29
-
30
- def add_id(value, source = nil, sequence = 1)
31
- Id.new.add(@prospect, value, source, sequence)
32
- end
33
- end
34
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class RequestDate
5
- WITH_SYMBOLS = "%FT%T%:z"
6
- WITHOUT_SYMBOLS = "%Y%m%dT%H%M%S%z"
7
-
8
- def initialize(prospect_node)
9
- @request_date_node = Ox::Element.new("requestdate")
10
- @request_date_node << DateTime.now.strftime("%FT%T%:z")
11
- prospect_node << @request_date_node
12
- end
13
-
14
- def update_val(datetime_value, format = 1)
15
- if format == 1
16
- @request_date_node.replace_text(datetime_value.strftime(WITH_SYMBOLS))
17
- elsif format == 2
18
- @request_date_node.replace_text(datetime_value.strftime(WITHOUT_SYMBOLS))
19
- end
20
- end
21
- end
22
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class Customer
5
- def initialize(prospect)
6
- @customer = Ox::Element.new("customer")
7
- @contact = nil
8
- @timeframe = nil
9
-
10
- prospect << @customer
11
- end
12
-
13
- attr_reader :contact, :timeframe
14
-
15
- def add(name, opts = {})
16
- @contact = Contact.new(@customer, name, opts)
17
- end
18
-
19
- def add_id(index, value, source = nil, sequence = 1)
20
- if @prospect.locate("customer").empty?
21
- false
22
- else
23
- Id.new.add(@prospect.customer(index), value, source, sequence)
24
- end
25
- end
26
-
27
- # @param descriptin [String] - Description of customer’s timing intention.
28
- # @param earliest_date [DateTime] - Earliest date customer is interested in. If timeframe tag
29
- # is present, it is required to specify earliestdate and/or
30
- # latestdate
31
- # @param latest_date [DateTime] - Latest date customer is interested in. If timeframe tag
32
- # is present, it is required to specify earliestdate and/or
33
- # latestdate
34
- def add_timeframe(description, earliest_date = nil, latest_date = nil)
35
- return false if earliest_date.nil? && latest_date.nil?
36
-
37
- return false if earliest_date && (earliest_date.class != DateTime)
38
-
39
- return false if latest_date && (latest_date.class != DateTime)
40
-
41
- @timeframe = Timeframe.new(@customer, description, earliest_date, latest_date) if @timeframe.nil?
42
- end
43
-
44
- def update_comments(comments)
45
- return false if comments.class != String
46
-
47
- AdfBuilder::Builder.update_node(@customer, :comments, comments)
48
- end
49
- end
50
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class Timeframe
5
- def initialize(customer, description, earliest_date, latest_date)
6
- begin
7
- earliest_date = earliest_date.strftime("%FT%T%:z") if earliest_date
8
- latest_date = latest_date.strftime("%FT%T%:z") if latest_date
9
- rescue StandardError
10
- return nil
11
- end
12
-
13
- @timeframe = Ox::Element.new("timeframe")
14
-
15
- @timeframe << (Ox::Element.new("description") << description)
16
- @timeframe << (Ox::Element.new("earliestdate") << earliest_date) if earliest_date
17
- @timeframe << (Ox::Element.new("latestdate") << latest_date) if latest_date
18
- customer << @timeframe
19
- end
20
-
21
- def update_description(description)
22
- AdfBuilder::Builder.update_node(@timeframe, :description, description)
23
- end
24
-
25
- def update_earliest_date(date)
26
- begin
27
- date = date.strftime("%FT%T%:z")
28
- rescue StandardError
29
- return false
30
- end
31
- AdfBuilder::Builder.update_node(@timeframe, :earliestdate, date)
32
- end
33
-
34
- def update_latest_date(date)
35
- begin
36
- date = date.strftime("%FT%T%:z")
37
- rescue StandardError
38
- return false
39
- end
40
-
41
- AdfBuilder::Builder.update_node(@timeframe, :latestdate, date)
42
- end
43
- end
44
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class Provider
5
- FREE_TEXT_OPTIONAL_TAGS = %i[service url].freeze
6
-
7
- def initialize(prospect)
8
- @prospect = prospect
9
- @provider = nil
10
- @contact = nil
11
- end
12
-
13
- attr_reader :contact
14
-
15
- def add(name, params = {})
16
- @provider = Ox::Element.new("provider")
17
- params.merge!({ valid_values: AdfBuilder::Contact::VALID_VALUES,
18
- valid_parameters: AdfBuilder::Contact::VALID_PARAMETERS })
19
- AdfBuilder::Builder.update_node(@provider, :name, name, params)
20
- @prospect << @provider
21
- end
22
-
23
- def add_contact(name, opts = {})
24
- @contact = Contact.new(@provider, name, opts)
25
- end
26
-
27
- def add_phone(phone, params = {})
28
- params.merge!({ valid_values: AdfBuilder::Contact::VALID_VALUES,
29
- valid_parameters: AdfBuilder::Contact::VALID_PARAMETERS })
30
- AdfBuilder::Builder.update_node(@provider, :phone, phone, params)
31
- end
32
-
33
- def add_email(email, params = {})
34
- params.merge!({ valid_values: AdfBuilder::Contact::VALID_VALUES,
35
- valid_parameters: AdfBuilder::Contact::VALID_PARAMETERS })
36
- AdfBuilder::Builder.update_node(@provider, :email, email, params)
37
- end
38
-
39
- def update_tags_with_free_text(tags)
40
- tags.each do |key, value|
41
- AdfBuilder::Builder.update_node(@provider, key, value) if FREE_TEXT_OPTIONAL_TAGS.include? key.to_sym
42
- end
43
- end
44
-
45
- def add_id(index, value, source = nil, sequence = 1)
46
- if @prospect.locate("provider").empty?
47
- false
48
- else
49
- Id.new.add(@prospect.provider(index), value, source, sequence)
50
- end
51
- end
52
- end
53
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class Contact
5
- VALID_PARAMETERS = {
6
- name: %i[part type primarycontact],
7
- email: [:preferredcontact],
8
- phone: %i[type time preferredcontact]
9
- }.freeze
10
-
11
- VALID_VALUES = {
12
- name: {
13
- part: %w[first middle suffix last full],
14
- type: %w[individual business],
15
- primarycontact: %w[0 1]
16
- },
17
- email: {
18
- preferredcontact: %w[0 1]
19
- },
20
- phone: {
21
- preferredcontact: %w[0 1],
22
- type: %w[phone fax cellphone pager],
23
- time: %w[morning afternoon evening nopreference day]
24
- }
25
- }.freeze
26
-
27
- def initialize(parent_node, name, params = {})
28
- @contact = Ox::Element.new("contact")
29
- params.merge!({ valid_values: VALID_VALUES, valid_parameters: VALID_PARAMETERS })
30
- AdfBuilder::Builder.update_node(@contact, :name, name, params)
31
- parent_node << @contact
32
- end
33
-
34
- def add_phone(phone, params = {})
35
- params.merge!({ valid_values: VALID_VALUES, valid_parameters: VALID_PARAMETERS })
36
- AdfBuilder::Builder.update_node(@contact, :phone, phone, params)
37
- end
38
-
39
- def add_email(email, params = {})
40
- params.merge!({ valid_values: VALID_VALUES, valid_parameters: VALID_PARAMETERS })
41
- AdfBuilder::Builder.update_node(@contact, :email, email, params)
42
- end
43
- end
44
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class Id
5
- def initialize; end
6
-
7
- # add id tag to the form
8
- def add(parent_node, value, source = nil, sequence = 1)
9
- id_node = Ox::Element.new("id")
10
- id_node << value
11
- id_node[:sequence] = sequence
12
-
13
- id_node[:source] = source if source
14
-
15
- parent_node.prepend_child(id_node)
16
- end
17
- end
18
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class ColorCombinations
5
- FREE_TEXT_OPTIONAL_TAGS = %i[interiorcolor exteriorcolor preference].freeze
6
-
7
- def initialize(vehicle)
8
- @vehicle = vehicle
9
- @color_combination = nil
10
- end
11
-
12
- def add(interior_color, exterior_color, preference)
13
- @color_combination = Ox::Element.new("colorcombination")
14
- @color_combination <<
15
- (Ox::Element.new("interiorcolor") << interior_color) <<
16
- (Ox::Element.new("exteriorcolor") << exterior_color) <<
17
- (Ox::Element.new("preference") << preference.to_s)
18
- @vehicle << @color_combination
19
- end
20
-
21
- def update_tags(index, tags)
22
- valid, vehicle = AdfBuilder::Builder.valid_child?(@vehicle, "colorcombination", index)
23
- return unless valid
24
-
25
- tags.each do |key, value|
26
- AdfBuilder::Builder.update_node(vehicle, key, value) if FREE_TEXT_OPTIONAL_TAGS.include? key.to_sym
27
- end
28
- end
29
- end
30
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AdfBuilder
4
- class Price
5
- VALID_PARAMETERS = {
6
- price: %i[type currency delta relativeto source]
7
- }.freeze
8
-
9
- VALID_VALUES = {
10
- price: {
11
- type: %w[quote offer msrp invoice call appraisal asking],
12
- currency: true,
13
- delta: %w[absolute relative percentage],
14
- relativeto: %w[msrp invoice],
15
- source: true
16
- }
17
- }.freeze
18
-
19
- def initialize(parent_node, value, params = {})
20
- @parent_node = parent_node
21
- params.merge!({ valid_values: VALID_VALUES, valid_parameters: VALID_PARAMETERS })
22
- validate_currency(params)
23
- AdfBuilder::Builder.update_node(@parent_node, :price, value, params)
24
- @price = @parent_node.price
25
- end
26
-
27
- def update(value, params = {})
28
- params.merge!({ valid_values: VALID_VALUES, valid_parameters: VALID_PARAMETERS })
29
- AdfBuilder::Builder.update_node(@parent_node, :price, value, params)
30
- end
31
-
32
- def validate_currency(params)
33
- code = params[:currency]
34
- return unless code
35
-
36
- json = JSON.parse(File.read("./lib/adf_builder/data/iso-4217-currency-codes.json"))
37
- codes = json.map { |j| j["Alphabetic_Code"] }.reject(&:nil?)
38
- return if codes.include? code
39
-
40
- params.delete(:currency)
41
- end
42
- end
43
- end