my_data 0.1.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +37 -0
  3. data/.rubocop.yml +12 -2
  4. data/Gemfile +9 -4
  5. data/Guardfile +7 -0
  6. data/README.md +55 -8
  7. data/lib/my_data.rb +9 -10
  8. data/lib/my_data/client.rb +34 -11
  9. data/lib/my_data/resource.rb +43 -29
  10. data/lib/my_data/resources/continuation_token_type.rb +7 -0
  11. data/lib/my_data/resources/ecls/expenses_classification.rb +7 -0
  12. data/lib/my_data/resources/ecls/expenses_classification_type.rb +1 -1
  13. data/lib/my_data/resources/ecls/invoice_expenses_classification_type.rb +1 -1
  14. data/lib/my_data/resources/ecls/invoices_expenses_classification_detail_type.rb +1 -1
  15. data/lib/my_data/resources/error_type.rb +1 -2
  16. data/lib/my_data/resources/icls/income_classification.rb +7 -0
  17. data/lib/my_data/resources/icls/income_classification_type.rb +1 -1
  18. data/lib/my_data/resources/icls/invoice_income_classification_type.rb +1 -1
  19. data/lib/my_data/resources/icls/invoices_income_classification_detail_type.rb +1 -1
  20. data/lib/my_data/resources/inv/aade_book_invoice_type.rb +1 -1
  21. data/lib/my_data/resources/inv/address_type.rb +1 -1
  22. data/lib/my_data/resources/inv/cancelled_invoice_type.rb +7 -0
  23. data/lib/my_data/resources/inv/continuation_token_type.rb +7 -0
  24. data/lib/my_data/resources/inv/invoice_header_type.rb +1 -1
  25. data/lib/my_data/resources/inv/invoice_row_type.rb +1 -1
  26. data/lib/my_data/resources/inv/invoice_summary_type.rb +1 -1
  27. data/lib/my_data/resources/inv/invoices_doc.rb +1 -11
  28. data/lib/my_data/resources/inv/party_type.rb +1 -1
  29. data/lib/my_data/resources/inv/payment_method_detail_type.rb +1 -1
  30. data/lib/my_data/resources/inv/request_doc.rb +7 -0
  31. data/lib/my_data/resources/inv/requested_invoices_doc.rb +7 -0
  32. data/lib/my_data/resources/inv/ship_type.rb +1 -1
  33. data/lib/my_data/resources/inv/tax_totals_type.rb +1 -1
  34. data/lib/my_data/resources/invoice_provider_type.rb +7 -0
  35. data/lib/my_data/resources/requested_provider_doc.rb +7 -0
  36. data/lib/my_data/resources/response.rb +7 -0
  37. data/lib/my_data/resources/response_type.rb +1 -13
  38. data/lib/my_data/response_parser.rb +42 -0
  39. data/lib/my_data/type_caster.rb +5 -4
  40. data/lib/my_data/version.rb +1 -1
  41. data/lib/my_data/xml_generator.rb +29 -17
  42. data/lib/my_data/xml_parser.rb +37 -76
  43. data/lib/my_data/xsd/complex_type.rb +11 -3
  44. data/lib/my_data/xsd/doc.rb +77 -0
  45. data/lib/my_data/xsd/element.rb +20 -8
  46. data/lib/my_data/xsd/resource_generator.rb +26 -13
  47. data/lib/my_data/xsd/structure.rb +41 -35
  48. data/my_data.gemspec +4 -3
  49. metadata +41 -19
  50. data/lib/my_data/resources.rb +0 -10
  51. data/lib/my_data/resources/ecls.rb +0 -7
  52. data/lib/my_data/resources/icls.rb +0 -7
  53. data/lib/my_data/resources/inv.rb +0 -14
  54. data/lib/my_data/resources/responses_doc.rb +0 -8
  55. data/lib/my_data/xsd.rb +0 -7
@@ -3,17 +3,17 @@
3
3
  class MyData::Xsd::ComplexType
4
4
  attr_reader :doc, :namespace
5
5
 
6
- def initialize(doc, namespace:)
6
+ def initialize(doc, namespace: nil)
7
7
  @doc = doc
8
8
  @namespace = namespace
9
9
  end
10
10
 
11
11
  def name
12
- @name ||= doc.attributes["name"].value
12
+ @name ||= doc.attributes["name"].value.camelize
13
13
  end
14
14
 
15
15
  def elements
16
- @elements ||= doc.xpath("xs:sequence/xs:element").map do |element|
16
+ @elements ||= extract_elements(doc).flatten.map do |element|
17
17
  MyData::Xsd::Element.new(element)
18
18
  end
19
19
  end
@@ -21,4 +21,12 @@ class MyData::Xsd::ComplexType
21
21
  def inspect
22
22
  "ComplexType: { name: #{name.to_json}, elements: #{elements} }"
23
23
  end
24
+
25
+ private
26
+
27
+ def extract_elements(node)
28
+ return node if node.name == "element"
29
+
30
+ node.element_children.map { |child| extract_elements(child) }
31
+ end
24
32
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Xsd::Doc
4
+ attr_reader :doc
5
+
6
+ DEFAULT_ATTRS = {
7
+ "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance"
8
+ }.freeze
9
+
10
+ def initialize(doc)
11
+ @doc = doc
12
+ end
13
+
14
+ def target_namespace
15
+ return @target_namespace if defined? @target_namespace
16
+
17
+ @target_namespace =
18
+ (doc.namespaces.find { |_k, v| v == target_namespace_value }.first.split(":").last if target_namespace_value)
19
+ end
20
+
21
+ def attributes
22
+ @attributes ||= DEFAULT_ATTRS
23
+ .merge(target_namespace_attributes)
24
+ .merge(namespace_attributes)
25
+ end
26
+
27
+ def elements
28
+ @elements ||=
29
+ begin
30
+ sequence = doc.child.xpath("xs:element/xs:complexType/xs:sequence").first
31
+ elements = sequence.xpath("xs:element")
32
+ collection = elements.count == 1 && sequence.attributes["maxOccurs"].present?
33
+
34
+ sequence.xpath("xs:element").map do |element|
35
+ MyData::Xsd::Element.new(element, force_collection: collection)
36
+ end
37
+ end
38
+ end
39
+
40
+ def complex_types
41
+ @complex_types ||= doc.xpath("//xs:schema/xs:complexType").map do |node|
42
+ MyData::Xsd::ComplexType.new(node, namespace: target_namespace)
43
+ end
44
+ end
45
+
46
+ def simple_types
47
+ @simple_types ||= doc.xpath("//xs:schema/xs:simpleType").map do |node|
48
+ MyData::Xsd::Element.new(node, namespace: target_namespace)
49
+ end
50
+ end
51
+
52
+ def inspect
53
+ "<Schema target_namespace: #{target_namespace.to_json}, attributes: #{attributes}>"
54
+ end
55
+
56
+ private
57
+
58
+ def target_namespace_value
59
+ doc.child.attributes["targetNamespace"]&.value
60
+ end
61
+
62
+ def target_namespace_attributes
63
+ return {} unless target_namespace_value
64
+
65
+ {
66
+ "xmlns" => target_namespace_value,
67
+ "xmlns:schema" => "#{target_namespace_value} schemaLocation.xsd"
68
+ }
69
+ end
70
+
71
+ def namespace_attributes
72
+ @namespace_attributes ||= doc
73
+ .namespaces
74
+ .reject { |k, _| k == "xmlns:xs" }
75
+ .reject { |_, v| v == target_namespace }
76
+ end
77
+ end
@@ -3,9 +3,10 @@
3
3
  class MyData::Xsd::Element
4
4
  attr_reader :element, :namespace
5
5
 
6
- def initialize(element, namespace: nil)
6
+ def initialize(element, namespace: nil, force_collection: nil)
7
7
  @element = element
8
8
  @namespace = namespace
9
+ force_collection && @collection = force_collection
9
10
  end
10
11
 
11
12
  def name
@@ -14,13 +15,14 @@ class MyData::Xsd::Element
14
15
 
15
16
  def type
16
17
  @type =
17
- if element.attributes["type"].present?
18
- element.attributes["type"]
19
- elsif element.xpath(".//xs:restriction[@base]").any?
20
- element.xpath(".//xs:restriction[@base]").first.attributes["base"]
21
- elsif element.xpath(".//xs:element[@type]").any?
22
- element.xpath(".//xs:element[@type]").first.attributes["type"]
23
- end.value
18
+ begin
19
+ extracted_type =
20
+ element.attributes["type"] ||
21
+ element.at_xpath(".//xs:element[@type]")&.attributes.try(:[], "type") ||
22
+ element.at_xpath(".//xs:restriction[@base]")&.attributes.try(:[], "base")
23
+
24
+ camelize_type(extracted_type.value)
25
+ end
24
26
  end
25
27
 
26
28
  def collection?
@@ -46,4 +48,14 @@ class MyData::Xsd::Element
46
48
  def inspect
47
49
  "Element: { name: #{name.to_json}, type: #{type.to_json}, collection: #{collection?} }"
48
50
  end
51
+
52
+ private
53
+
54
+ def camelize_type(extracted_type)
55
+ return extracted_type if extracted_type.starts_with?("xs:")
56
+
57
+ ns, name = extracted_type.include?(":") ? extracted_type.split(":") : [nil, extracted_type]
58
+
59
+ [ns, name.camelize].compact.join(":")
60
+ end
49
61
  end
@@ -4,32 +4,45 @@ require "fileutils"
4
4
 
5
5
  # This class is for development reason only, to generate resources
6
6
  module MyData::Xsd::ResourceGenerator
7
- module_function
7
+ extend self
8
8
 
9
- def generate
10
- MyData::Xsd::Structure.complex_types.each do |_, type|
11
- folder_name = File.join(MyData.root, "lib/my_data/resources", type.namespace.to_s)
12
- FileUtils.mkdir_p(folder_name)
13
-
14
- class_name = "#{type.namespace.capitalize}::#{type.name}"
9
+ def generate_docs
10
+ MyData::Xsd::Structure.docs.each do |name, doc|
11
+ generate_file(name: name, namespace: doc.target_namespace, xsd_mode: "xsd_doc")
12
+ end
15
13
 
16
- puts "Create file: #{folder_name} #{type.name}"
14
+ "done"
15
+ end
17
16
 
18
- file = File.new(File.join(folder_name, "#{type.name.underscore}.rb"), "w")
19
- file.write(class_string(class_name))
20
- file.close
17
+ def generate_types
18
+ MyData::Xsd::Structure.complex_types.each do |_, type|
19
+ generate_file(name: type.name, namespace: type.namespace, xsd_mode: "xsd_complex_type")
21
20
  end
22
21
 
23
22
  "done"
24
23
  end
25
24
 
26
- def class_string(class_name)
25
+ private
26
+
27
+ def generate_file(name:, namespace:, xsd_mode:)
28
+ folder_name = File.join(MyData.root, "lib/my_data/resources", namespace.to_s)
29
+ FileUtils.mkdir_p(folder_name)
30
+
31
+ class_name = [namespace&.camelize, name.camelize].compact.join("::")
32
+ puts "Create file: #{folder_name}, #{name}"
33
+
34
+ file = File.new(File.join(folder_name, "#{name.underscore}.rb"), "w")
35
+ file.write(class_string(class_name, xsd_mode))
36
+ file.close
37
+ end
38
+
39
+ def class_string(class_name, xsd_mode)
27
40
  string = "# frozen_string_literal: true\n"
28
41
  string += "\n"
29
42
  string += "class MyData::Resources::#{class_name}\n"
30
43
  string += " include MyData::Resource\n"
31
44
  string += "\n"
32
- string += " xsd_structure\n"
45
+ string += " #{xsd_mode}\n"
33
46
  string += "end\n"
34
47
 
35
48
  string
@@ -5,51 +5,65 @@ module MyData::Xsd::Structure
5
5
 
6
6
  PATH = File.join(MyData.root, "lib/my_data/xsd/docs")
7
7
 
8
- def resource_attributes(class_name)
8
+ def doc(class_name)
9
+ name = class_name.split("::").last
10
+ [name, docs[name]]
11
+ end
12
+
13
+ def resource_attributes(class_name, type)
9
14
  namespace, name = class_name.split("::").last(2)
15
+ key = namespace == "Resources" ? name : [namespace.downcase, name].join(":")
10
16
 
11
- complex_types["#{namespace.downcase}:#{name}"].elements.map do |element|
12
- type = type_mapping(element.type)
13
-
14
- [
15
- element.name.underscore,
16
- type,
17
- {
18
- collection: element.collection?,
19
- collection_element_name: element.collection_element_name,
20
- class_name: type == :resource ? classify(element.type) : nil,
21
- required: element.required?
22
- }
23
- ]
24
- end
17
+ current_doc = type == :complex_type ? complex_types[key] : docs[name]
18
+
19
+ current_doc.elements.map { |element| element_attributes(element) }
25
20
  end
26
21
 
27
- def complex_types
28
- @complex_types ||= docs.each_with_object({}) do |(namespace, doc), types|
29
- doc.xpath("//xs:schema/xs:complexType").each do |node|
30
- type = MyData::Xsd::ComplexType.new(node, namespace: namespace)
22
+ def docs
23
+ @docs ||= Dir.glob("*.xsd", base: PATH).map do |file_name|
24
+ [file_name.sub(/-.+$/, "").camelize, MyData::Xsd::Doc.new(read_xsd(file_name))]
25
+ end.to_h
26
+ end
31
27
 
32
- types["#{type.namespace}:#{type.name}"] = type
28
+ def complex_types
29
+ @complex_types ||= docs.values.each_with_object({}) do |document, types|
30
+ document.complex_types.each do |type|
31
+ name = [type.namespace, type.name].compact.join(":")
32
+ types[name] = type
33
33
  end
34
34
  end
35
35
  end
36
36
 
37
37
  def simple_types
38
- @simple_types ||= docs.each_with_object({}) do |(namespace, doc), types|
39
- doc.xpath("//xs:schema/xs:simpleType").each do |node|
40
- type = MyData::Xsd::Element.new(node, namespace: namespace)
41
-
42
- types["#{type.namespace}:#{type.name}"] = type
38
+ @simple_types ||= docs.values.each_with_object({}) do |document, types|
39
+ document.simple_types.each do |type|
40
+ name = [type.namespace, type.name].compact.join(":")
41
+ types[name] = type
43
42
  end
44
43
  end
45
44
  end
46
45
 
47
46
  private
48
47
 
48
+ def element_attributes(element)
49
+ type = type_mapping(element.type)
50
+
51
+ [
52
+ element.name.underscore,
53
+ type,
54
+ {
55
+ collection: element.collection?,
56
+ collection_element_name: element.collection_element_name,
57
+ class_name: type == :resource ? classify(element.type) : nil,
58
+ required: element.required?
59
+ }
60
+ ]
61
+ end
62
+
49
63
  def classify(type)
50
- namespace, name = type.split(":")
64
+ namespace, name = type.split(":").map(&:camelize)
51
65
 
52
- "#{namespace.capitalize}::#{name}"
66
+ "#{namespace}::#{name}"
53
67
  end
54
68
 
55
69
  def type_mapping(type)
@@ -66,14 +80,6 @@ module MyData::Xsd::Structure
66
80
  end
67
81
  end
68
82
 
69
- def docs
70
- @docs ||= {
71
- inv: read_xsd("InvoicesDoc-v1.0.2.xsd"),
72
- icls: read_xsd("incomeClassification-v1.0.2.xsd"),
73
- ecls: read_xsd("expensesClassification-v1.0.2.xsd")
74
- }
75
- end
76
-
77
83
  def read_xsd(name)
78
84
  Nokogiri::XML(File.read(File.join(PATH, name)))
79
85
  end
data/my_data.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "Api client for AADE myData"
13
13
  spec.homepage = "https://github.com/mikezaby/my_data"
14
14
  spec.license = "MIT"
15
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
18
18
  spec.metadata["source_code_uri"] = spec.homepage
@@ -26,10 +26,11 @@ Gem::Specification.new do |spec|
26
26
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ["lib"]
28
28
 
29
- spec.add_dependency "faraday", "~> 1.0"
30
- spec.add_dependency "activesupport", ">= 3.2"
31
29
  spec.add_dependency "activemodel", ">= 3.2"
30
+ spec.add_dependency "activesupport", ">= 3.2"
31
+ spec.add_dependency "faraday", "~> 1.0"
32
32
  spec.add_dependency "nokogiri", ">= 1.10"
33
+ spec.add_dependency "zeitwerk", ">= 2.4"
33
34
 
34
35
  # For more information and examples about making a new gem, checkout our
35
36
  # guide at: https://bundler.io/guides/creating_gem.html
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: my_data
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michalis Zamparas
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-12 00:00:00.000000000 Z
11
+ date: 2021-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: faraday
14
+ name: activemodel
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '3.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '3.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -39,19 +39,19 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.2'
41
41
  - !ruby/object:Gem::Dependency
42
- name: activemodel
42
+ name: faraday
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.2'
47
+ version: '1.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.2'
54
+ version: '1.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: nokogiri
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: zeitwerk
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '2.4'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '2.4'
69
83
  description: Api client for AADE myData
70
84
  email:
71
85
  - mikezaby@gmail.com
@@ -73,10 +87,12 @@ executables: []
73
87
  extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
90
+ - ".github/workflows/lint.yml"
76
91
  - ".gitignore"
77
92
  - ".rspec"
78
93
  - ".rubocop.yml"
79
94
  - Gemfile
95
+ - Guardfile
80
96
  - LICENSE.txt
81
97
  - README.md
82
98
  - Rakefile
@@ -85,35 +101,41 @@ files:
85
101
  - lib/my_data.rb
86
102
  - lib/my_data/client.rb
87
103
  - lib/my_data/resource.rb
88
- - lib/my_data/resources.rb
89
- - lib/my_data/resources/ecls.rb
104
+ - lib/my_data/resources/continuation_token_type.rb
105
+ - lib/my_data/resources/ecls/expenses_classification.rb
90
106
  - lib/my_data/resources/ecls/expenses_classification_type.rb
91
107
  - lib/my_data/resources/ecls/invoice_expenses_classification_type.rb
92
108
  - lib/my_data/resources/ecls/invoices_expenses_classification_detail_type.rb
93
109
  - lib/my_data/resources/error_type.rb
94
- - lib/my_data/resources/icls.rb
110
+ - lib/my_data/resources/icls/income_classification.rb
95
111
  - lib/my_data/resources/icls/income_classification_type.rb
96
112
  - lib/my_data/resources/icls/invoice_income_classification_type.rb
97
113
  - lib/my_data/resources/icls/invoices_income_classification_detail_type.rb
98
- - lib/my_data/resources/inv.rb
99
114
  - lib/my_data/resources/inv/aade_book_invoice_type.rb
100
115
  - lib/my_data/resources/inv/address_type.rb
116
+ - lib/my_data/resources/inv/cancelled_invoice_type.rb
117
+ - lib/my_data/resources/inv/continuation_token_type.rb
101
118
  - lib/my_data/resources/inv/invoice_header_type.rb
102
119
  - lib/my_data/resources/inv/invoice_row_type.rb
103
120
  - lib/my_data/resources/inv/invoice_summary_type.rb
104
121
  - lib/my_data/resources/inv/invoices_doc.rb
105
122
  - lib/my_data/resources/inv/party_type.rb
106
123
  - lib/my_data/resources/inv/payment_method_detail_type.rb
124
+ - lib/my_data/resources/inv/request_doc.rb
125
+ - lib/my_data/resources/inv/requested_invoices_doc.rb
107
126
  - lib/my_data/resources/inv/ship_type.rb
108
127
  - lib/my_data/resources/inv/tax_totals_type.rb
128
+ - lib/my_data/resources/invoice_provider_type.rb
129
+ - lib/my_data/resources/requested_provider_doc.rb
130
+ - lib/my_data/resources/response.rb
109
131
  - lib/my_data/resources/response_type.rb
110
- - lib/my_data/resources/responses_doc.rb
132
+ - lib/my_data/response_parser.rb
111
133
  - lib/my_data/type_caster.rb
112
134
  - lib/my_data/version.rb
113
135
  - lib/my_data/xml_generator.rb
114
136
  - lib/my_data/xml_parser.rb
115
- - lib/my_data/xsd.rb
116
137
  - lib/my_data/xsd/complex_type.rb
138
+ - lib/my_data/xsd/doc.rb
117
139
  - lib/my_data/xsd/docs/InvoicesDoc-v1.0.2.xsd
118
140
  - lib/my_data/xsd/docs/RequestedProviderDoc-v1.0.2.xsd
119
141
  - lib/my_data/xsd/docs/expensesClassification-v1.0.2.xsd
@@ -139,7 +161,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
139
161
  requirements:
140
162
  - - ">="
141
163
  - !ruby/object:Gem::Version
142
- version: 2.3.0
164
+ version: 2.4.0
143
165
  required_rubygems_version: !ruby/object:Gem::Requirement
144
166
  requirements:
145
167
  - - ">="