shale 0.2.2 → 0.4.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/CHANGELOG.md +33 -0
- data/README.md +366 -8
- data/exe/shaleb +123 -0
- data/lib/shale/adapter/json.rb +7 -2
- data/lib/shale/adapter/nokogiri.rb +48 -12
- data/lib/shale/adapter/ox.rb +28 -4
- data/lib/shale/adapter/rexml.rb +56 -13
- data/lib/shale/attribute.rb +7 -1
- data/lib/shale/error.rb +12 -0
- data/lib/shale/mapper.rb +17 -15
- data/lib/shale/mapping/descriptor/dict.rb +57 -0
- data/lib/shale/mapping/descriptor/xml.rb +43 -0
- data/lib/shale/mapping/descriptor/xml_namespace.rb +37 -0
- data/lib/shale/mapping/{key_value.rb → dict.rb} +8 -6
- data/lib/shale/mapping/validator.rb +51 -0
- data/lib/shale/mapping/xml.rb +86 -15
- data/lib/shale/schema/json_compiler/boolean.rb +21 -0
- data/lib/shale/schema/json_compiler/date.rb +21 -0
- data/lib/shale/schema/json_compiler/float.rb +21 -0
- data/lib/shale/schema/json_compiler/integer.rb +21 -0
- data/lib/shale/schema/json_compiler/object.rb +85 -0
- data/lib/shale/schema/json_compiler/property.rb +70 -0
- data/lib/shale/schema/json_compiler/string.rb +21 -0
- data/lib/shale/schema/json_compiler/time.rb +21 -0
- data/lib/shale/schema/json_compiler/utils.rb +52 -0
- data/lib/shale/schema/json_compiler/value.rb +13 -0
- data/lib/shale/schema/json_compiler.rb +333 -0
- data/lib/shale/schema/json_generator/base.rb +41 -0
- data/lib/shale/schema/json_generator/boolean.rb +23 -0
- data/lib/shale/schema/json_generator/collection.rb +39 -0
- data/lib/shale/schema/json_generator/date.rb +23 -0
- data/lib/shale/schema/json_generator/float.rb +23 -0
- data/lib/shale/schema/json_generator/integer.rb +23 -0
- data/lib/shale/schema/json_generator/object.rb +40 -0
- data/lib/shale/schema/json_generator/ref.rb +28 -0
- data/lib/shale/schema/json_generator/schema.rb +59 -0
- data/lib/shale/schema/json_generator/string.rb +23 -0
- data/lib/shale/schema/json_generator/time.rb +23 -0
- data/lib/shale/schema/json_generator/value.rb +23 -0
- data/lib/shale/schema/json_generator.rb +165 -0
- data/lib/shale/schema/xml_generator/attribute.rb +41 -0
- data/lib/shale/schema/xml_generator/complex_type.rb +70 -0
- data/lib/shale/schema/xml_generator/element.rb +55 -0
- data/lib/shale/schema/xml_generator/import.rb +46 -0
- data/lib/shale/schema/xml_generator/ref_attribute.rb +37 -0
- data/lib/shale/schema/xml_generator/ref_element.rb +39 -0
- data/lib/shale/schema/xml_generator/schema.rb +121 -0
- data/lib/shale/schema/xml_generator/typed_attribute.rb +46 -0
- data/lib/shale/schema/xml_generator/typed_element.rb +46 -0
- data/lib/shale/schema/xml_generator.rb +315 -0
- data/lib/shale/schema.rb +70 -0
- data/lib/shale/type/boolean.rb +2 -2
- data/lib/shale/type/composite.rb +78 -72
- data/lib/shale/type/date.rb +35 -2
- data/lib/shale/type/float.rb +2 -2
- data/lib/shale/type/integer.rb +2 -2
- data/lib/shale/type/string.rb +2 -2
- data/lib/shale/type/time.rb +35 -2
- data/lib/shale/type/{base.rb → value.rb} +18 -7
- data/lib/shale/utils.rb +18 -2
- data/lib/shale/version.rb +1 -1
- data/lib/shale.rb +10 -10
- data/shale.gemspec +6 -2
- metadata +53 -13
- data/lib/shale/mapping/base.rb +0 -32
@@ -26,12 +26,29 @@ module Shale
|
|
26
26
|
# Serialize Nokogiri document into XML
|
27
27
|
#
|
28
28
|
# @param [::Nokogiri::XML::Document] doc Nokogiri document
|
29
|
+
# @param [Array<Symbol>] options
|
29
30
|
#
|
30
31
|
# @return [String]
|
31
32
|
#
|
32
33
|
# @api private
|
33
|
-
def self.dump(doc)
|
34
|
-
|
34
|
+
def self.dump(doc, *options)
|
35
|
+
save_with = ::Nokogiri::XML::Node::SaveOptions::AS_XML
|
36
|
+
|
37
|
+
if options.include?(:pretty)
|
38
|
+
save_with |= ::Nokogiri::XML::Node::SaveOptions::FORMAT
|
39
|
+
end
|
40
|
+
|
41
|
+
unless options.include?(:declaration)
|
42
|
+
save_with |= ::Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
|
43
|
+
end
|
44
|
+
|
45
|
+
result = doc.to_xml(save_with: save_with)
|
46
|
+
|
47
|
+
unless options.include?(:pretty)
|
48
|
+
result = result.sub(/\n/, '')
|
49
|
+
end
|
50
|
+
|
51
|
+
result
|
35
52
|
end
|
36
53
|
|
37
54
|
# Create Shale::Adapter::Nokogiri::Document instance
|
@@ -45,18 +62,27 @@ module Shale
|
|
45
62
|
#
|
46
63
|
# @api private
|
47
64
|
class Document
|
65
|
+
# Initialize object
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
def initialize
|
69
|
+
@doc = ::Nokogiri::XML::Document.new
|
70
|
+
@namespaces = {}
|
71
|
+
end
|
72
|
+
|
48
73
|
# Return Nokogiri document
|
49
74
|
#
|
50
75
|
# @return [::Nokogiri::XML::Document]
|
51
76
|
#
|
52
77
|
# @api private
|
53
|
-
|
78
|
+
def doc
|
79
|
+
if @doc.root
|
80
|
+
@namespaces.each do |prefix, namespace|
|
81
|
+
@doc.root.add_namespace(prefix, namespace)
|
82
|
+
end
|
83
|
+
end
|
54
84
|
|
55
|
-
|
56
|
-
#
|
57
|
-
# @api private
|
58
|
-
def initialize
|
59
|
-
@doc = ::Nokogiri::XML::Document.new
|
85
|
+
@doc
|
60
86
|
end
|
61
87
|
|
62
88
|
# Create Nokogiri element
|
@@ -70,6 +96,16 @@ module Shale
|
|
70
96
|
::Nokogiri::XML::Element.new(name, @doc)
|
71
97
|
end
|
72
98
|
|
99
|
+
# Add XML namespace to document
|
100
|
+
#
|
101
|
+
# @param [String] prefix
|
102
|
+
# @param [String] namespace
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
def add_namespace(prefix, namespace)
|
106
|
+
@namespaces[prefix] = namespace if prefix && namespace
|
107
|
+
end
|
108
|
+
|
73
109
|
# Add attribute to Nokogiri element
|
74
110
|
#
|
75
111
|
# @param [::Nokogiri::XML::Element] element Nokogiri element
|
@@ -115,7 +151,7 @@ module Shale
|
|
115
151
|
@node = node
|
116
152
|
end
|
117
153
|
|
118
|
-
# Return
|
154
|
+
# Return name of the node in the format of
|
119
155
|
# namespace:name when the node is namespaced or just name when it's not
|
120
156
|
#
|
121
157
|
# @return [String]
|
@@ -124,11 +160,11 @@ module Shale
|
|
124
160
|
# node.name # => Bar
|
125
161
|
#
|
126
162
|
# @example with namespace
|
127
|
-
# node.name # => foo:Bar
|
163
|
+
# node.name # => http://foo:Bar
|
128
164
|
#
|
129
165
|
# @api private
|
130
166
|
def name
|
131
|
-
[@node.namespace&.
|
167
|
+
[@node.namespace&.href, @node.name].compact.join(':')
|
132
168
|
end
|
133
169
|
|
134
170
|
# Return all attributes associated with the node
|
@@ -138,7 +174,7 @@ module Shale
|
|
138
174
|
# @api private
|
139
175
|
def attributes
|
140
176
|
@node.attribute_nodes.each_with_object({}) do |node, hash|
|
141
|
-
name = [node.namespace&.
|
177
|
+
name = [node.namespace&.href, node.name].compact.join(':')
|
142
178
|
hash[name] = node.value
|
143
179
|
end
|
144
180
|
end
|
data/lib/shale/adapter/ox.rb
CHANGED
@@ -22,12 +22,24 @@ module Shale
|
|
22
22
|
# Serialize Ox document into XML
|
23
23
|
#
|
24
24
|
# @param [::Ox::Document, ::Ox::Element] doc Ox document
|
25
|
+
# @param [Array<Symbol>] options
|
25
26
|
#
|
26
27
|
# @return [String]
|
27
28
|
#
|
28
29
|
# @api private
|
29
|
-
def self.dump(doc)
|
30
|
-
|
30
|
+
def self.dump(doc, *options)
|
31
|
+
opts = { indent: -1, with_xml: false }
|
32
|
+
|
33
|
+
if options.include?(:pretty)
|
34
|
+
opts[:indent] = 2
|
35
|
+
end
|
36
|
+
|
37
|
+
if options.include?(:declaration)
|
38
|
+
doc[:version] = '1.0'
|
39
|
+
opts[:with_xml] = true
|
40
|
+
end
|
41
|
+
|
42
|
+
::Ox.dump(doc, opts).sub(/\A\n/, '')
|
31
43
|
end
|
32
44
|
|
33
45
|
# Create Shale::Adapter::Ox::Document instance
|
@@ -66,6 +78,18 @@ module Shale
|
|
66
78
|
::Ox::Element.new(name)
|
67
79
|
end
|
68
80
|
|
81
|
+
# Add XML namespace to document
|
82
|
+
#
|
83
|
+
# Ox doesn't support XML namespaces so this method does nothing.
|
84
|
+
#
|
85
|
+
# @param [String] prefix
|
86
|
+
# @param [String] namespace
|
87
|
+
#
|
88
|
+
# @api private
|
89
|
+
def add_namespace(prefix, namespace)
|
90
|
+
# :noop:
|
91
|
+
end
|
92
|
+
|
69
93
|
# Add attribute to Ox element
|
70
94
|
#
|
71
95
|
# @param [::Ox::Element] element Ox element
|
@@ -111,8 +135,8 @@ module Shale
|
|
111
135
|
@node = node
|
112
136
|
end
|
113
137
|
|
114
|
-
# Return
|
115
|
-
#
|
138
|
+
# Return name of the node in the format of
|
139
|
+
# prefix:name when the node is namespaced or just name when it's not
|
116
140
|
#
|
117
141
|
# @return [String]
|
118
142
|
#
|
data/lib/shale/adapter/rexml.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rexml/document'
|
4
|
+
require_relative '../utils'
|
4
5
|
|
5
6
|
module Shale
|
6
7
|
module Adapter
|
@@ -23,12 +24,27 @@ module Shale
|
|
23
24
|
# Serialize REXML document into XML
|
24
25
|
#
|
25
26
|
# @param [::REXML::Document] doc REXML document
|
27
|
+
# @param [Array<Symbol>] options
|
26
28
|
#
|
27
29
|
# @return [String]
|
28
30
|
#
|
29
31
|
# @api private
|
30
|
-
def self.dump(doc)
|
31
|
-
|
32
|
+
def self.dump(doc, *options)
|
33
|
+
if options.include?(:declaration)
|
34
|
+
doc.add(::REXML::XMLDecl.new)
|
35
|
+
end
|
36
|
+
|
37
|
+
io = StringIO.new
|
38
|
+
|
39
|
+
if options.include?(:pretty)
|
40
|
+
formatter = ::REXML::Formatters::Pretty.new
|
41
|
+
formatter.compact = true
|
42
|
+
else
|
43
|
+
formatter = ::REXML::Formatters::Default.new
|
44
|
+
end
|
45
|
+
|
46
|
+
formatter.write(doc, io)
|
47
|
+
io.string
|
32
48
|
end
|
33
49
|
|
34
50
|
# Create Shale::Adapter::REXML::Document instance
|
@@ -42,18 +58,28 @@ module Shale
|
|
42
58
|
#
|
43
59
|
# @api private
|
44
60
|
class Document
|
61
|
+
# Initialize object
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
def initialize
|
65
|
+
context = { attribute_quote: :quote, prologue_quote: :quote }
|
66
|
+
@doc = ::REXML::Document.new(nil, context)
|
67
|
+
@namespaces = {}
|
68
|
+
end
|
69
|
+
|
45
70
|
# Return REXML document
|
46
71
|
#
|
47
72
|
# @return [::REXML::Document]
|
48
73
|
#
|
49
74
|
# @api private
|
50
|
-
|
75
|
+
def doc
|
76
|
+
if @doc.root
|
77
|
+
@namespaces.each do |prefix, namespace|
|
78
|
+
@doc.root.add_namespace(prefix, namespace)
|
79
|
+
end
|
80
|
+
end
|
51
81
|
|
52
|
-
|
53
|
-
#
|
54
|
-
# @api private
|
55
|
-
def initialize
|
56
|
-
@doc = ::REXML::Document.new
|
82
|
+
@doc
|
57
83
|
end
|
58
84
|
|
59
85
|
# Create REXML element
|
@@ -64,7 +90,17 @@ module Shale
|
|
64
90
|
#
|
65
91
|
# @api private
|
66
92
|
def create_element(name)
|
67
|
-
::REXML::Element.new(name)
|
93
|
+
::REXML::Element.new(name, nil, attribute_quote: :quote)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Add XML namespace to document
|
97
|
+
#
|
98
|
+
# @param [String] prefix
|
99
|
+
# @param [String] namespace
|
100
|
+
#
|
101
|
+
# @api private
|
102
|
+
def add_namespace(prefix, namespace)
|
103
|
+
@namespaces[prefix] = namespace if prefix && namespace
|
68
104
|
end
|
69
105
|
|
70
106
|
# Add attribute to REXML element
|
@@ -112,7 +148,7 @@ module Shale
|
|
112
148
|
@node = node
|
113
149
|
end
|
114
150
|
|
115
|
-
# Return
|
151
|
+
# Return name of the node in the format of
|
116
152
|
# namespace:name when the node is namespaced or just name when it's not
|
117
153
|
#
|
118
154
|
# @return [String]
|
@@ -121,11 +157,11 @@ module Shale
|
|
121
157
|
# node.name # => Bar
|
122
158
|
#
|
123
159
|
# @example with namespace
|
124
|
-
# node.name # => foo:Bar
|
160
|
+
# node.name # => http://foo:Bar
|
125
161
|
#
|
126
162
|
# @api private
|
127
163
|
def name
|
128
|
-
@node.
|
164
|
+
[Utils.presence(@node.namespace), @node.name].compact.join(':')
|
129
165
|
end
|
130
166
|
|
131
167
|
# Return all attributes associated with the node
|
@@ -134,7 +170,14 @@ module Shale
|
|
134
170
|
#
|
135
171
|
# @api private
|
136
172
|
def attributes
|
137
|
-
@node.attributes
|
173
|
+
attributes = @node.attributes.values.map do |attribute|
|
174
|
+
attribute.is_a?(Hash) ? attribute.values : attribute
|
175
|
+
end.flatten
|
176
|
+
|
177
|
+
attributes.each_with_object({}) do |attribute, hash|
|
178
|
+
name = [Utils.presence(attribute.namespace), attribute.name].compact.join(':')
|
179
|
+
hash[name] = attribute.value
|
180
|
+
end
|
138
181
|
end
|
139
182
|
|
140
183
|
# Return node's element children
|
data/lib/shale/attribute.rb
CHANGED
@@ -20,16 +20,22 @@ module Shale
|
|
20
20
|
# @api private
|
21
21
|
attr_reader :default
|
22
22
|
|
23
|
+
# Return setter name
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
attr_reader :setter
|
27
|
+
|
23
28
|
# Initialize Attribute object
|
24
29
|
#
|
25
30
|
# @param [Symbol] name Name of the attribute
|
26
|
-
# @param [Shale::Type::
|
31
|
+
# @param [Shale::Type::Value] type Type of the attribute
|
27
32
|
# @param [Boolean] collection Is this attribute a collection
|
28
33
|
# @param [Proc] default Default value
|
29
34
|
#
|
30
35
|
# @api private
|
31
36
|
def initialize(name, type, collection, default)
|
32
37
|
@name = name
|
38
|
+
@setter = "#{name}="
|
33
39
|
@type = type
|
34
40
|
@collection = collection
|
35
41
|
@default = collection ? -> { [] } : default
|
data/lib/shale/error.rb
CHANGED
@@ -36,4 +36,16 @@ module Shale
|
|
36
36
|
# @api private
|
37
37
|
class IncorrectMappingArgumentsError < StandardError
|
38
38
|
end
|
39
|
+
|
40
|
+
# Error for passing incorrect arguments to schema generation function
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
class NotAShaleMapperError < StandardError
|
44
|
+
end
|
45
|
+
|
46
|
+
# JSON Schema compilation error
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
class JSONSchemaError < StandardError
|
50
|
+
end
|
39
51
|
end
|
data/lib/shale/mapper.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require_relative 'attribute'
|
4
4
|
require_relative 'error'
|
5
5
|
require_relative 'utils'
|
6
|
-
require_relative 'mapping/
|
6
|
+
require_relative 'mapping/dict'
|
7
7
|
require_relative 'mapping/xml'
|
8
8
|
require_relative 'type/composite'
|
9
9
|
|
@@ -44,9 +44,9 @@ module Shale
|
|
44
44
|
# @api public
|
45
45
|
class Mapper < Type::Composite
|
46
46
|
@attributes = {}
|
47
|
-
@hash_mapping = Mapping::
|
48
|
-
@json_mapping = Mapping::
|
49
|
-
@yaml_mapping = Mapping::
|
47
|
+
@hash_mapping = Mapping::Dict.new
|
48
|
+
@json_mapping = Mapping::Dict.new
|
49
|
+
@yaml_mapping = Mapping::Dict.new
|
50
50
|
@xml_mapping = Mapping::Xml.new
|
51
51
|
|
52
52
|
class << self
|
@@ -59,21 +59,21 @@ module Shale
|
|
59
59
|
|
60
60
|
# Return Hash mapping object
|
61
61
|
#
|
62
|
-
# @return [Shale::Mapping::
|
62
|
+
# @return [Shale::Mapping::Dict]
|
63
63
|
#
|
64
64
|
# @api public
|
65
65
|
attr_reader :hash_mapping
|
66
66
|
|
67
67
|
# Return JSON mapping object
|
68
68
|
#
|
69
|
-
# @return [Shale::Mapping::
|
69
|
+
# @return [Shale::Mapping::Dict]
|
70
70
|
#
|
71
71
|
# @api public
|
72
72
|
attr_reader :json_mapping
|
73
73
|
|
74
74
|
# Return YAML mapping object
|
75
75
|
#
|
76
|
-
# @return [Shale::Mapping::
|
76
|
+
# @return [Shale::Mapping::Dict]
|
77
77
|
#
|
78
78
|
# @api public
|
79
79
|
attr_reader :yaml_mapping
|
@@ -108,7 +108,7 @@ module Shale
|
|
108
108
|
# Define attribute on class
|
109
109
|
#
|
110
110
|
# @param [Symbol] name Name of the attribute
|
111
|
-
# @param [Shale::Type::
|
111
|
+
# @param [Shale::Type::Value] type Type of the attribute
|
112
112
|
# @param [Boolean] collection Is the attribute a collection
|
113
113
|
# @param [Proc] default Default value for the attribute
|
114
114
|
#
|
@@ -167,7 +167,7 @@ module Shale
|
|
167
167
|
# attribute :last_name, Shale::Type::String
|
168
168
|
# attribute :age, Shale::Type::Integer
|
169
169
|
#
|
170
|
-
#
|
170
|
+
# hsh do
|
171
171
|
# map 'firatName', to: :first_name
|
172
172
|
# map 'lastName', to: :last_name
|
173
173
|
# map 'age', to: :age
|
@@ -175,7 +175,7 @@ module Shale
|
|
175
175
|
# end
|
176
176
|
#
|
177
177
|
# @api public
|
178
|
-
def
|
178
|
+
def hsh(&block)
|
179
179
|
@hash_mapping = @__hash_mapping_init.dup
|
180
180
|
@hash_mapping.instance_eval(&block)
|
181
181
|
end
|
@@ -190,7 +190,7 @@ module Shale
|
|
190
190
|
# attribute :last_name, Shale::Type::String
|
191
191
|
# attribute :age, Shale::Type::Integer
|
192
192
|
#
|
193
|
-
#
|
193
|
+
# json do
|
194
194
|
# map 'firatName', to: :first_name
|
195
195
|
# map 'lastName', to: :last_name
|
196
196
|
# map 'age', to: :age
|
@@ -272,9 +272,11 @@ module Shale
|
|
272
272
|
def initialize(**props)
|
273
273
|
super()
|
274
274
|
|
275
|
-
props.
|
276
|
-
|
277
|
-
|
275
|
+
unless props.empty?
|
276
|
+
unknown_attributes = props.keys - self.class.attributes.keys
|
277
|
+
|
278
|
+
unless unknown_attributes.empty?
|
279
|
+
raise UnknownAttributeError.new(self.class.to_s, unknown_attributes[0].to_s)
|
278
280
|
end
|
279
281
|
end
|
280
282
|
|
@@ -285,7 +287,7 @@ module Shale
|
|
285
287
|
value = attribute.default.call
|
286
288
|
end
|
287
289
|
|
288
|
-
|
290
|
+
send(attribute.setter, value)
|
289
291
|
end
|
290
292
|
end
|
291
293
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shale
|
4
|
+
module Mapping
|
5
|
+
module Descriptor
|
6
|
+
# Class representing attribute mapping
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class Dict
|
10
|
+
# Return mapping name
|
11
|
+
#
|
12
|
+
# @return [String]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
attr_reader :name
|
16
|
+
|
17
|
+
# Return attribute name
|
18
|
+
#
|
19
|
+
# @return [Symbol]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
attr_reader :attribute
|
23
|
+
|
24
|
+
# Return method symbol
|
25
|
+
#
|
26
|
+
# @return [Symbol]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
attr_reader :method_from
|
30
|
+
|
31
|
+
# Return method symbol
|
32
|
+
#
|
33
|
+
# @return [Symbol]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
attr_reader :method_to
|
37
|
+
|
38
|
+
# Initialize instance
|
39
|
+
#
|
40
|
+
# @param [String] name
|
41
|
+
# @param [Symbol, nil] attribute
|
42
|
+
# @param [Hash, nil] methods
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
def initialize(name:, attribute:, methods:)
|
46
|
+
@name = name
|
47
|
+
@attribute = attribute
|
48
|
+
|
49
|
+
if methods
|
50
|
+
@method_from = methods[:from]
|
51
|
+
@method_to = methods[:to]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'dict'
|
4
|
+
|
5
|
+
module Shale
|
6
|
+
module Mapping
|
7
|
+
module Descriptor
|
8
|
+
# Class representing XML attribute mapping
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
class Xml < Dict
|
12
|
+
# Return namespace
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
attr_reader :namespace
|
18
|
+
|
19
|
+
# Initialize instance
|
20
|
+
#
|
21
|
+
# @param [String] name
|
22
|
+
# @param [Symbol, String] attribute
|
23
|
+
# @param [Hash, nil] methods
|
24
|
+
# @param [Shale::Mapping::XmlNamespace] namespace
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def initialize(name:, attribute:, methods:, namespace:)
|
28
|
+
super(name: name, attribute: attribute, methods: methods)
|
29
|
+
@namespace = namespace
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return name with XML prefix
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
def prefixed_name
|
38
|
+
[namespace.prefix, name].compact.join(':')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shale
|
4
|
+
module Mapping
|
5
|
+
module Descriptor
|
6
|
+
# Class representing XML namespace
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class XmlNamespace
|
10
|
+
# Return name
|
11
|
+
#
|
12
|
+
# @return [String]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
attr_accessor :name
|
16
|
+
|
17
|
+
# Return prefix
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
attr_accessor :prefix
|
23
|
+
|
24
|
+
# Initialize instance
|
25
|
+
#
|
26
|
+
# @param [String, nil] name
|
27
|
+
# @param [String, nil] prefix
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
def initialize(name = nil, prefix = nil)
|
31
|
+
@name = name
|
32
|
+
@prefix = prefix
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'descriptor/dict'
|
4
|
+
require_relative 'validator'
|
4
5
|
|
5
6
|
module Shale
|
6
7
|
module Mapping
|
7
|
-
# Mapping for
|
8
|
+
# Mapping for dictionary serialization formats (Hash/JSON/YAML)
|
8
9
|
#
|
9
10
|
# @api private
|
10
|
-
class
|
11
|
+
class Dict
|
11
12
|
# Return keys mapping hash
|
12
13
|
#
|
13
14
|
# @return [Hash]
|
@@ -26,14 +27,15 @@ module Shale
|
|
26
27
|
# Map key to attribute
|
27
28
|
#
|
28
29
|
# @param [String] key Document's key
|
29
|
-
# @param [Symbol] to Object's attribute
|
30
|
+
# @param [Symbol, nil] to Object's attribute
|
31
|
+
# @param [Hash, nil] using
|
30
32
|
#
|
31
33
|
# @raise [IncorrectMappingArgumentsError] when arguments are incorrect
|
32
34
|
#
|
33
35
|
# @api private
|
34
36
|
def map(key, to: nil, using: nil)
|
35
|
-
validate_arguments(key, to, using)
|
36
|
-
@keys[key] = to
|
37
|
+
Validator.validate_arguments(key, to, using)
|
38
|
+
@keys[key] = Descriptor::Dict.new(name: key, attribute: to, methods: using)
|
37
39
|
end
|
38
40
|
|
39
41
|
# @api private
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../error'
|
4
|
+
|
5
|
+
module Shale
|
6
|
+
module Mapping
|
7
|
+
module Validator
|
8
|
+
# Validate correctness of argument passed to map functions
|
9
|
+
#
|
10
|
+
# @param [String] key
|
11
|
+
# @param [Symbol] to
|
12
|
+
# @param [Hash] using
|
13
|
+
#
|
14
|
+
# @raise [IncorrectMappingArgumentsError] when arguments are incorrect
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def self.validate_arguments(key, to, using)
|
18
|
+
if to.nil? && using.nil?
|
19
|
+
msg = ":to or :using argument is required for mapping '#{key}'"
|
20
|
+
raise IncorrectMappingArgumentsError, msg
|
21
|
+
end
|
22
|
+
|
23
|
+
if !using.nil? && (using[:from].nil? || using[:to].nil?)
|
24
|
+
msg = ":using argument for mapping '#{key}' requires :to and :from keys"
|
25
|
+
raise IncorrectMappingArgumentsError, msg
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Validate correctness of namespace arguments
|
30
|
+
#
|
31
|
+
# @param [String] key
|
32
|
+
# @param [String, Symbol, nil] namespace
|
33
|
+
# @param [String, Symbol, nil] prefix
|
34
|
+
#
|
35
|
+
# @raise [IncorrectMappingArgumentsError] when arguments are incorrect
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
def self.validate_namespace(key, namespace, prefix)
|
39
|
+
return if namespace == :undefined && prefix == :undefined
|
40
|
+
|
41
|
+
nsp = namespace == :undefined ? nil : namespace
|
42
|
+
pfx = prefix == :undefined ? nil : prefix
|
43
|
+
|
44
|
+
if (nsp && !pfx) || (!nsp && pfx)
|
45
|
+
msg = "both :namespace and :prefix arguments are required for mapping '#{key}'"
|
46
|
+
raise IncorrectMappingArgumentsError, msg
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|