shale 0.2.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|