cxml-ruby 0.4.0 → 0.7.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -0
  3. data/.rubocop.yml +4 -0
  4. data/CHANGELOG.md +18 -0
  5. data/cxml-ruby.gemspec +1 -0
  6. data/lib/cxml-ruby.rb +1 -1
  7. data/lib/cxml/address.rb +4 -1
  8. data/lib/cxml/comment.rb +9 -0
  9. data/lib/cxml/contact.rb +4 -1
  10. data/lib/cxml/country_code.rb +9 -0
  11. data/lib/cxml/credential.rb +1 -1
  12. data/lib/cxml/deposit_amount.rb +9 -0
  13. data/lib/cxml/document.rb +11 -6
  14. data/lib/cxml/document_node.rb +5 -5
  15. data/lib/cxml/invoice_detail_item.rb +11 -11
  16. data/lib/cxml/invoice_detail_item_reference.rb +3 -1
  17. data/lib/cxml/invoice_detail_request_header.rb +5 -5
  18. data/lib/cxml/invoice_detail_summary.rb +6 -4
  19. data/lib/cxml/item_detail.rb +5 -1
  20. data/lib/cxml/order_request_header.rb +11 -10
  21. data/lib/cxml/parser.rb +29 -2
  22. data/lib/cxml/phone.rb +13 -0
  23. data/lib/cxml/postal_address.rb +1 -1
  24. data/lib/cxml/telephone_number.rb +11 -0
  25. data/lib/cxml/version.rb +1 -1
  26. data/spec/document_spec.rb +33 -1
  27. data/spec/fixtures/1.2.014-cXML.dtd +4184 -0
  28. data/spec/fixtures/1.2.020-InvoiceDetail.dtd +4590 -0
  29. data/spec/fixtures/1.2.020-cXML.dtd +4917 -0
  30. data/spec/fixtures/1.2.037-InvoiceDetail.dtd +7287 -0
  31. data/spec/fixtures/invoice_taxes_at_line_multiple_taxes.xml +1 -3
  32. data/spec/fixtures/item_in.xml +2 -1
  33. data/spec/fixtures/{order_request.cxml → order_request.xml} +0 -0
  34. data/spec/fixtures/punch_out_order_message_doc.xml +1 -1
  35. data/spec/fixtures/punch_out_setup_request_doc_with_ship_to.xml +7 -0
  36. data/spec/fixtures/response_status_200.xml +1 -1
  37. data/spec/fixtures/response_status_400.xml +2 -2
  38. data/spec/invoice_detail_request_spec.rb +21 -1
  39. data/spec/item_in_spec.rb +5 -0
  40. data/spec/money_spec.rb +8 -0
  41. data/spec/output/.gitkeep +0 -0
  42. data/spec/punch_out_order_message_spec.rb +5 -0
  43. data/spec/punch_out_setup_request_spec.rb +2 -0
  44. data/spec/purchase_order_request_spec.rb +6 -1
  45. data/spec/sender_spec.rb +6 -0
  46. data/spec/spec_helper.rb +27 -0
  47. metadata +20 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca2ed654a5b8543d2beb69ec7acb0db49b2f1fbd7210ef1d4928b4da4fa0cb96
4
- data.tar.gz: 90b66c83fe8ea876050daad559ecd0b3349d578ab1ea21e0ef79e234c0382e44
3
+ metadata.gz: 1f43fac9295a9de5ac9f0c327a73b26260569c239c70bad553e8cb0721c5fb7b
4
+ data.tar.gz: 41e42f9b4a188923bf7c42105571c0f81da954fc82d4825d0c1c0dbd49ec7f93
5
5
  SHA512:
6
- metadata.gz: 12d39fe0bd266b4308853a8bd2a331cc546e0ca43643629dbe264ea3f44cdaeb5d55ac7590e42e1297b7dcd957d1f91daba4af96b19e96b0d92548f47f51f307
7
- data.tar.gz: 1c9ab1f5f5c03555e9ac12ceedd41afa016a25c38cde5e2eea01ee9792953fb1aad10bc3b47254729daf5563b178534b0c6bd5da2ae65e17bff334f28f4510b5
6
+ metadata.gz: 90361cf48f65bc79bde60722efe16be0f61f60e455998aa7c73bdbbcba7984b2c9b7b322b70579572d2d44988ed554db0f4ecd046038de6d0fc43086fe64fd77
7
+ data.tar.gz: 23892b7370c13805e5ad69c0c1bed7b2181c872abc8cb9abed99c074e7423f28d764d8cfa3889593cd0a528ec3674b5384b4f5d5a97bcf59c576adebbf06cd61
@@ -15,6 +15,7 @@ jobs:
15
15
  ruby-version: 2.6.x
16
16
  - name: Test with Rake
17
17
  run: |
18
+ sudo apt-get install libxml2-utils
18
19
  gem install bundler
19
20
  bundle install --jobs 4 --retry 3
20
21
  bundle exec rake
@@ -2,6 +2,7 @@ AllCops:
2
2
  Exclude:
3
3
  - Gemfile
4
4
  - vendor/**/*
5
+ NewCops: enable
5
6
 
6
7
  # # Disable checking for block length
7
8
  Metrics/BlockLength:
@@ -54,6 +55,9 @@ Style/Documentation:
54
55
  Style/ClassAndModuleChildren:
55
56
  Enabled: false
56
57
 
58
+ Style/ArrayCoercion:
59
+ Enabled: false
60
+
57
61
  Style/HashEachMethods:
58
62
  Enabled: true
59
63
 
@@ -14,6 +14,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
14
14
 
15
15
  ---
16
16
 
17
+ ## [0.7.0] - 2021-01-12
18
+ ### Added
19
+ - Support parsing Phone tags.
20
+
21
+ ## [0.6.1] - 2020-09-04
22
+ ### Fixed
23
+ - Handle parsing CDATA tags in cXML content (Thanks @CRiva!).
24
+
25
+ ## [0.6.0] - 2020-05-01
26
+ ### Fixed
27
+ - Conform to cXML DTD spec for ordered output of child nodes.
28
+ ### Added
29
+ - Support parsing and validating output against DTDs in specs.
30
+
31
+ ## [0.5.0] - 2020-04-30
32
+ ### Added
33
+ - Support parsing and specifying different DTDs.
34
+
17
35
  ## [0.4.0] - 2020-04-20
18
36
  ### Changed
19
37
  - Return parsed nodes as plain string if they have no attributes and only string content.
@@ -12,6 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.authors = ['Josh Beckman', 'Eleni Chappen']
13
13
  s.email = ['josh@officeluv.com', 'eleni@officeluv.com']
14
14
 
15
+ s.required_ruby_version = '>= 2.4'
15
16
  s.add_dependency('ox', '~> 2.13')
16
17
 
17
18
  s.add_development_dependency('pry', '~> 0.12')
@@ -26,7 +26,7 @@ module CXML
26
26
  def self.logger
27
27
  return @logger if @logger
28
28
 
29
- @logger ||= Logger.new(STDOUT, level: :warn)
29
+ @logger ||= Logger.new($stdout, level: :warn)
30
30
  end
31
31
 
32
32
  def self.logger=(new_logger)
@@ -8,9 +8,12 @@ module CXML
8
8
  iso_country_code
9
9
  ]
10
10
  accessible_nodes %i[
11
- email
12
11
  name
13
12
  postal_address
13
+ email
14
+ phone
15
+ fax
16
+ url
14
17
  ]
15
18
  end
16
19
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CXML
4
+ class Comments < DocumentNode
5
+ accessible_attributes %i[
6
+ xml_lang
7
+ ]
8
+ end
9
+ end
@@ -8,9 +8,12 @@ module CXML
8
8
  address_id
9
9
  ]
10
10
  accessible_nodes %i[
11
- email
12
11
  name
13
12
  postal_address
13
+ email
14
+ phone
15
+ fax
16
+ url
14
17
  ]
15
18
  end
16
19
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CXML
4
+ class CountryCode < DocumentNode
5
+ accessible_attributes %i[
6
+ iso_country_code
7
+ ]
8
+ end
9
+ end
@@ -41,8 +41,8 @@ module CXML
41
41
  type
42
42
  ]
43
43
  accessible_nodes %i[
44
- shared_secret
45
44
  identity
45
+ shared_secret
46
46
  credential_mac
47
47
  ]
48
48
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CXML
4
+ class DepositAmount < DocumentNode
5
+ accessible_nodes %i[
6
+ money
7
+ ]
8
+ end
9
+ end
@@ -2,11 +2,13 @@
2
2
 
3
3
  module CXML
4
4
  class Document < DocumentNode
5
+ attr_writer :dtd
6
+
5
7
  accessible_attributes %i[
6
- version
7
8
  payload_id
8
- xml_lang
9
9
  timestamp
10
+ version
11
+ xml_lang
10
12
  ]
11
13
  accessible_nodes %i[
12
14
  header
@@ -27,6 +29,10 @@ module CXML
27
29
  @version ||= '1.2.037'
28
30
  end
29
31
 
32
+ def dtd
33
+ @dtd ||= 'cXML'
34
+ end
35
+
30
36
  # Check if document is request
31
37
  # @return [Boolean]
32
38
  def request?
@@ -59,18 +65,17 @@ module CXML
59
65
  'cXML'
60
66
  end
61
67
 
62
- private
63
-
64
68
  def dtd_url
65
- "http://xml.cxml.org/schemas/cXML/#{version}/cXML.dtd"
69
+ "http://xml.cxml.org/schemas/cXML/#{version}/#{dtd}.dtd"
66
70
  end
67
71
 
72
+ private
73
+
68
74
  def ox_doc
69
75
  doc = Ox::Document.new
70
76
  instruct = Ox::Instruct.new(:xml)
71
77
  instruct[:version] = '1.0'
72
78
  instruct[:encoding] = 'UTF-8'
73
- instruct[:standalone] = 'yes'
74
79
  doc << instruct
75
80
  doc << Ox::DocType.new("cXML SYSTEM \"#{dtd_url}\"")
76
81
  doc
@@ -54,7 +54,7 @@ module CXML
54
54
 
55
55
  def to_element
56
56
  element = ox_element
57
- element << content if content
57
+ element << content.to_s if content
58
58
  self.class.nodes.each do |child_node_name|
59
59
  child_value = send(child_node_name)
60
60
  if child_value.is_a?(Array)
@@ -88,12 +88,12 @@ module CXML
88
88
  value_element = Ox::Element.new(camelize(name))
89
89
  if value.is_a? Hash
90
90
  value.each do |value_key, value_val|
91
- next value_element << value_val if value_key == :content
91
+ next value_element << value_val.to_s if value_key == :content
92
92
 
93
93
  value_element[value_key] = value_val
94
94
  end
95
95
  else
96
- value_element << value
96
+ value_element << value.to_s
97
97
  end
98
98
  element << value_element
99
99
  element
@@ -108,7 +108,7 @@ module CXML
108
108
  string_attr = if attr.to_sym == :xml_lang
109
109
  'xml:lang'
110
110
  else
111
- camelize(attr, false)
111
+ camelize(attr, uppercase_first_letter: false)
112
112
  end
113
113
  obj[string_attr] = value
114
114
  end
@@ -138,7 +138,7 @@ module CXML
138
138
  end
139
139
  end
140
140
 
141
- def camelize(string, uppercase_first_letter = true)
141
+ def camelize(string, uppercase_first_letter: true)
142
142
  string = if uppercase_first_letter
143
143
  string.to_s.sub(/^[a-z\d]*/, &:capitalize)
144
144
  else
@@ -14,28 +14,28 @@ module CXML
14
14
  reference_date
15
15
  ]
16
16
  accessible_nodes %i[
17
- comments
18
- distribution
19
- extrinsics
17
+ unit_of_measure
18
+ unit_price
19
+ invoice_detail_item_reference
20
+ subtotal_amount
21
+ tax
22
+ invoice_detail_line_special_handling
23
+ invoice_detail_line_shipping
20
24
  gross_amount
21
25
  invoice_detail_discount
26
+ net_amount
27
+ distribution
28
+ comments
29
+ extrinsics
22
30
  invoice_detail_item_industry
23
- invoice_detail_item_reference
24
- invoice_detail_line_shipping
25
- invoice_detail_line_special_handling
26
31
  invoice_item_modifications
27
- net_amount
28
32
  packaging
29
33
  price_basis_quantity
30
34
  ship_notice_id_info
31
35
  ship_notice_line_item_reference
32
- subtotal_amount
33
- tax
34
36
  total_allowances
35
37
  total_amount_without_tax
36
38
  total_charges
37
- unit_of_measure
38
- unit_price
39
39
  ]
40
40
 
41
41
  def initialize_extrinsic(value)
@@ -6,12 +6,14 @@ module CXML
6
6
  line_number
7
7
  ]
8
8
  accessible_nodes %i[
9
- description
10
9
  item_id
10
+ description
11
11
  classification
12
12
  manufacturer_part_id
13
13
  manufacturer_name
14
14
  country
15
+ serial_number
16
+ supplier_batch_id
15
17
  ]
16
18
  end
17
19
  end
@@ -11,16 +11,16 @@ module CXML
11
11
  purpose
12
12
  ]
13
13
  accessible_nodes %i[
14
- comments
15
- document_reference
16
- extrinsics
17
14
  invoice_detail_header_indicator
18
15
  invoice_detail_line_indicator
19
- invoice_detail_shipping
20
- invoice_id_info
21
16
  invoice_partners
17
+ document_reference
18
+ invoice_id_info
19
+ invoice_detail_shipping
22
20
  payment_term
23
21
  period
22
+ comments
23
+ extrinsics
24
24
  ]
25
25
 
26
26
  def initialize_invoice_partner(value)
@@ -3,13 +3,15 @@
3
3
  module CXML
4
4
  class InvoiceDetailSummary < DocumentNode
5
5
  accessible_nodes %i[
6
+ subtotal_amount
7
+ tax
8
+ special_handling_amount
9
+ shipping_amount
6
10
  gross_amount
7
11
  invoice_detail_discount
8
12
  net_amount
9
- shipping_amount
10
- special_handling_amount
11
- subtotal_amount
12
- tax
13
+ deposit_amount
14
+ due_amount
13
15
  total_allowances
14
16
  total_amount_without_tax
15
17
  total_charges
@@ -3,10 +3,14 @@
3
3
  module CXML
4
4
  class ItemDetail < DocumentNode
5
5
  accessible_nodes %i[
6
+ unit_price
6
7
  description
7
8
  unit_of_measure
8
- unit_price
9
9
  classification
10
+ manufacturer_part_id
11
+ manufacturer_name
12
+ url
13
+ lead_time
10
14
  extrinsics
11
15
  ]
12
16
 
@@ -23,26 +23,27 @@ module CXML
23
23
  type
24
24
  ]
25
25
  accessible_nodes %i[
26
+ total
27
+ ship_to
26
28
  bill_to
27
- comments
29
+ shipping
30
+ tax
31
+ payment
32
+ payment_term
28
33
  contact
29
- control_keys
30
- delivery_period
34
+ comments
35
+ followup
31
36
  document_reference
37
+ supplier_order_info
32
38
  extrinsics
39
+ control_keys
40
+ delivery_period
33
41
  followup
34
42
  id_reference
35
43
  legal_identity
36
44
  order_request_header_industry
37
45
  organizational_unit
38
- payment
39
- payment_term
40
- ship_to
41
- shipping
42
- supplier_order_info
43
- tax
44
46
  terms_of_delivery
45
- total
46
47
  ]
47
48
 
48
49
  def type
@@ -11,28 +11,55 @@ module CXML
11
11
 
12
12
  def parse
13
13
  @parsed_data = node_to_hash document
14
+ if dtd_url
15
+ @parsed_data[:version] = version
16
+ @parsed_data[:dtd] = dtd
17
+ end
18
+ @parsed_data
14
19
  end
15
20
 
16
21
  def document
17
22
  doc = Ox.load(data)
23
+ @doc_type_string = doc.nodes.detect do |node|
24
+ node.value&.match?(/^cXML /)
25
+ end&.value
18
26
  doc.nodes.detect do |node|
19
27
  node.value&.match?(/^cxml$/i)
20
28
  end || doc
21
29
  end
22
30
 
31
+ def version
32
+ dtd_url&.match(%r{cXML/(.*)/.*\.dtd})&.to_a&.last
33
+ end
34
+
35
+ def dtd
36
+ dtd_url&.match(%r{cXML/.*/(.*)\.dtd})&.to_a&.last
37
+ end
38
+
39
+ def dtd_url
40
+ return nil unless @doc_type_string
41
+
42
+ @doc_type_string.match(/http.*\.dtd/)&.to_a&.first
43
+ end
44
+
23
45
  private
24
46
 
25
- def node_to_hash(node) # rubocop:disable Metrics/AbcSize
47
+ def node_to_hash(node)
48
+ return node.value if node.is_a?(Ox::CData)
26
49
  return node if node.is_a? String
27
50
  return node.nodes.first if node.nodes.all?(String) && node.attributes.empty?
28
51
 
52
+ transform_node_to_hash node
53
+ end
54
+
55
+ def transform_node_to_hash(node)
29
56
  hash = node.attributes
30
57
  hash.transform_keys!(&method(:underscore_key))
31
58
  node.nodes.reduce(hash) do |acc, child_node|
32
59
  next acc if child_node.is_a?(Ox::Comment)
33
60
 
34
61
  node_hash = {}
35
- name = child_node.is_a?(String) ? :content : child_node.value
62
+ name = child_node.is_a?(String) || child_node.is_a?(Ox::CData) ? :content : child_node.value
36
63
  node_hash[underscore_key(name)] = node_to_hash(child_node)
37
64
  acc.merge(node_hash) do |_key, val1, val2|
38
65
  [val1, val2].flatten