shale 0.9.0 → 1.1.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.
data/lib/shale/mapper.rb CHANGED
@@ -151,7 +151,7 @@ module Shale
151
151
  # @raise [DefaultNotCallableError] when attribute's default is not callable
152
152
  #
153
153
  # @example
154
- # calss Person < Shale::Mapper
154
+ # class Person < Shale::Mapper
155
155
  # attribute :first_name, Shale::Type::String
156
156
  # attribute :last_name, Shale::Type::String
157
157
  # attribute :age, Shale::Type::Integer, default: -> { 1 }
@@ -200,7 +200,7 @@ module Shale
200
200
  # @param [Proc] block
201
201
  #
202
202
  # @example
203
- # calss Person < Shale::Mapper
203
+ # class Person < Shale::Mapper
204
204
  # attribute :first_name, Shale::Type::String
205
205
  # attribute :last_name, Shale::Type::String
206
206
  # attribute :age, Shale::Type::Integer
@@ -224,7 +224,7 @@ module Shale
224
224
  # @param [Proc] block
225
225
  #
226
226
  # @example
227
- # calss Person < Shale::Mapper
227
+ # class Person < Shale::Mapper
228
228
  # attribute :first_name, Shale::Type::String
229
229
  # attribute :last_name, Shale::Type::String
230
230
  # attribute :age, Shale::Type::Integer
@@ -248,7 +248,7 @@ module Shale
248
248
  # @param [Proc] block
249
249
  #
250
250
  # @example
251
- # calss Person < Shale::Mapper
251
+ # class Person < Shale::Mapper
252
252
  # attribute :first_name, Shale::Type::String
253
253
  # attribute :last_name, Shale::Type::String
254
254
  # attribute :age, Shale::Type::Integer
@@ -272,7 +272,7 @@ module Shale
272
272
  # @param [Proc] block
273
273
  #
274
274
  # @example
275
- # calss Person < Shale::Mapper
275
+ # class Person < Shale::Mapper
276
276
  # attribute :first_name, Shale::Type::String
277
277
  # attribute :last_name, Shale::Type::String
278
278
  # attribute :age, Shale::Type::Integer
@@ -296,7 +296,7 @@ module Shale
296
296
  # @param [Proc] block
297
297
  #
298
298
  # @example
299
- # calss Person < Shale::Mapper
299
+ # class Person < Shale::Mapper
300
300
  # attribute :first_name, Shale::Type::String
301
301
  # attribute :last_name, Shale::Type::String
302
302
  # attribute :age, Shale::Type::Integer
@@ -320,7 +320,7 @@ module Shale
320
320
  # @param [Proc] block
321
321
  #
322
322
  # @example
323
- # calss Person < Shale::Mapper
323
+ # class Person < Shale::Mapper
324
324
  # attribute :first_name, Shale::Type::String
325
325
  # attribute :last_name, Shale::Type::String
326
326
  # attribute :age, Shale::Type::Integer
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shale
4
+ module Mapping
5
+ # Class for handling attribute delegation
6
+ #
7
+ # @api private
8
+ class Delegates
9
+ # Class representing individual delegation
10
+ #
11
+ # @api private
12
+ class Delegate
13
+ # Return receiver_attribute
14
+ #
15
+ # @return [Shale::Attribute]
16
+ #
17
+ # @api private
18
+ attr_reader :receiver_attribute
19
+
20
+ # Return attribute setter on a delegate
21
+ #
22
+ # @return [String]
23
+ #
24
+ # @api private
25
+ attr_reader :setter
26
+
27
+ # Return value to set on a delegate
28
+ #
29
+ # @return [any]
30
+ #
31
+ # @api private
32
+ attr_reader :value
33
+
34
+ # Initialize instance
35
+ #
36
+ # @param [Shale::Attribute] receiver_attribute
37
+ # @param [String] setter
38
+ # @param [any] value
39
+ #
40
+ # @api private
41
+ def initialize(receiver_attribute, setter, value)
42
+ @receiver_attribute = receiver_attribute
43
+ @setter = setter
44
+ @value = value
45
+ end
46
+ end
47
+
48
+ # Initialize instance
49
+ #
50
+ # @api private
51
+ def initialize
52
+ @delegates = []
53
+ end
54
+
55
+ # Add single value to delegate
56
+ #
57
+ # @param [Shale::Attribute] receiver_attribute
58
+ # @param [String] setter
59
+ # @param [any] value
60
+ #
61
+ # @api private
62
+ def add(receiver_attribute, setter, value)
63
+ @delegates << Delegate.new(receiver_attribute, setter, value)
64
+ end
65
+
66
+ # Add collection to delegate
67
+ #
68
+ # @param [Shale::Attribute] receiver_attribute
69
+ # @param [String] setter
70
+ # @param [any] value
71
+ #
72
+ # @api private
73
+ def add_collection(receiver_attribute, setter, value)
74
+ delegate = @delegates.find do |e|
75
+ e.receiver_attribute == receiver_attribute && e.setter == setter
76
+ end
77
+
78
+ if delegate
79
+ delegate.value << value
80
+ else
81
+ @delegates << Delegate.new(receiver_attribute, setter, [value])
82
+ end
83
+ end
84
+
85
+ # Iterate over delegates and yield a block
86
+ #
87
+ # @param [Proc] block
88
+ #
89
+ # @api private
90
+ def each(&block)
91
+ @delegates.each(&block)
92
+ end
93
+ end
94
+ end
95
+ end
@@ -21,6 +21,13 @@ module Shale
21
21
  # @api private
22
22
  attr_reader :attribute
23
23
 
24
+ # Return receiver name
25
+ #
26
+ # @return [Symbol]
27
+ #
28
+ # @api private
29
+ attr_reader :receiver
30
+
24
31
  # Return method symbol
25
32
  #
26
33
  # @return [Symbol]
@@ -42,20 +49,31 @@ module Shale
42
49
  # @api private
43
50
  attr_reader :group
44
51
 
52
+ # Return schema hash
53
+ #
54
+ # @return [Hash]
55
+ #
56
+ # @api private
57
+ attr_reader :schema
58
+
45
59
  # Initialize instance
46
60
  #
47
61
  # @param [String] name
48
62
  # @param [Symbol, nil] attribute
63
+ # @param [Symbol, nil] receiver
49
64
  # @param [Hash, nil] methods
50
65
  # @param [String, nil] group
51
66
  # @param [true, false] render_nil
67
+ # @param [Hash, nil] schema
52
68
  #
53
69
  # @api private
54
- def initialize(name:, attribute:, methods:, group:, render_nil:)
70
+ def initialize(name:, attribute:, receiver:, methods:, group:, render_nil:, schema: nil)
55
71
  @name = name
56
72
  @attribute = attribute
73
+ @receiver = receiver
57
74
  @group = group
58
75
  @render_nil = render_nil
76
+ @schema = schema
59
77
 
60
78
  if methods
61
79
  @method_from = methods[:from]
@@ -26,7 +26,8 @@ module Shale
26
26
  # Initialize instance
27
27
  #
28
28
  # @param [String] name
29
- # @param [Symbol, String] attribute
29
+ # @param [Symbol, nil] attribute
30
+ # @param [Symbol, nil] receiver
30
31
  # @param [Hash, nil] methods
31
32
  # @param [String, nil] group
32
33
  # @param [Shale::Mapping::XmlNamespace] namespace
@@ -34,10 +35,20 @@ module Shale
34
35
  # @param [true, false] render_nil
35
36
  #
36
37
  # @api private
37
- def initialize(name:, attribute:, methods:, group:, namespace:, cdata:, render_nil:)
38
+ def initialize(
39
+ name:,
40
+ attribute:,
41
+ receiver:,
42
+ methods:,
43
+ group:,
44
+ namespace:,
45
+ cdata:,
46
+ render_nil:
47
+ )
38
48
  super(
39
49
  name: name,
40
50
  attribute: attribute,
51
+ receiver: receiver,
41
52
  methods: methods,
42
53
  group: group,
43
54
  render_nil: render_nil
@@ -5,22 +5,33 @@ require_relative 'dict_group'
5
5
 
6
6
  module Shale
7
7
  module Mapping
8
- # Mapping for dictionary serialization formats (Hash/JSON/YAML)
8
+ # Mapping for dictionary serialization formats (Hash/JSON/YAML/TOML/CSV)
9
9
  #
10
10
  # @api private
11
11
  class Dict < DictBase
12
12
  # Map key to attribute
13
13
  #
14
14
  # @param [String] key Document's key
15
- # @param [Symbol, nil] to Object's attribute
15
+ # @param [Symbol, nil] to
16
+ # @param [Symbol, nil] receiver
16
17
  # @param [Hash, nil] using
17
18
  # @param [true, false, nil] render_nil
19
+ # @param [Hash, nil] schema
18
20
  #
19
21
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
20
22
  #
23
+ # @api public
24
+ def map(key, to: nil, receiver: nil, using: nil, render_nil: nil, schema: nil)
25
+ super(key, to: to, receiver: receiver, using: using, render_nil: render_nil, schema: schema)
26
+ end
27
+
28
+ # Set render_nil default
29
+ #
30
+ # @param [true, false] val
31
+ #
21
32
  # @api private
22
- def map(key, to: nil, using: nil, render_nil: nil)
23
- super(key, to: to, using: using, render_nil: render_nil)
33
+ def render_nil(val)
34
+ @render_nil_default = val
24
35
  end
25
36
 
26
37
  # Map group of keys to mapping methods
@@ -5,7 +5,7 @@ require_relative 'validator'
5
5
 
6
6
  module Shale
7
7
  module Mapping
8
- # Base class for Mapping dictionary serialization formats (Hash/JSON/YAML)
8
+ # Base class for Mapping dictionary serialization formats (Hash/JSON/YAML/TOML/CSV)
9
9
  #
10
10
  # @api private
11
11
  class DictBase
@@ -16,6 +16,13 @@ module Shale
16
16
  # @api private
17
17
  attr_reader :keys
18
18
 
19
+ # Return hash for hash with properties for root Object
20
+ #
21
+ # @return [Hash]
22
+ #
23
+ # @api private
24
+ attr_reader :root
25
+
19
26
  # Initialize instance
20
27
  #
21
28
  # @param [true, false] render_nil_default
@@ -23,6 +30,7 @@ module Shale
23
30
  # @api private
24
31
  def initialize(render_nil_default: false)
25
32
  @keys = {}
33
+ @root = {}
26
34
  @finalized = false
27
35
  @render_nil_default = render_nil_default
28
36
  end
@@ -31,24 +39,44 @@ module Shale
31
39
  #
32
40
  # @param [String] key
33
41
  # @param [Symbol, nil] to
42
+ # @param [Symbol, nil] receiver
34
43
  # @param [Hash, nil] using
35
44
  # @param [String, nil] group
36
45
  # @param [true, false, nil] render_nil
46
+ # @param [Hash, nil] schema
37
47
  #
38
48
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
39
49
  #
40
50
  # @api private
41
- def map(key, to: nil, using: nil, group: nil, render_nil: nil)
42
- Validator.validate_arguments(key, to, using)
51
+ def map(key, to: nil, receiver: nil, using: nil, group: nil, render_nil: nil, schema: nil)
52
+ Validator.validate_arguments(key, to, receiver, using)
53
+
43
54
  @keys[key] = Descriptor::Dict.new(
44
55
  name: key,
45
56
  attribute: to,
57
+ receiver: receiver,
46
58
  methods: using,
47
59
  group: group,
48
- render_nil: render_nil.nil? ? @render_nil_default : render_nil
60
+ render_nil: render_nil.nil? ? @render_nil_default : render_nil,
61
+ schema: schema
49
62
  )
50
63
  end
51
64
 
65
+ # Allow schema properties to be set on the object
66
+ #
67
+ # @param [Integer] min_properties
68
+ # @param [Integer] max_properties
69
+ # @param [Hash] dependent_required
70
+ #
71
+ # @api public
72
+ def properties(min_properties: nil, max_properties: nil, dependent_required: nil)
73
+ @root = {
74
+ min_properties: min_properties,
75
+ max_properties: max_properties,
76
+ dependent_required: dependent_required,
77
+ }
78
+ end
79
+
52
80
  # Set the "finalized" instance variable to true
53
81
  #
54
82
  # @api private
@@ -4,7 +4,7 @@ require_relative 'dict_base'
4
4
 
5
5
  module Shale
6
6
  module Mapping
7
- # Group for dictionary serialization formats (Hash/JSON/YAML)
7
+ # Group for dictionary serialization formats (Hash/JSON/YAML/TOML/CSV)
8
8
  #
9
9
  # @api private
10
10
  class DictGroup < DictBase
@@ -8,18 +8,25 @@ module Shale
8
8
  # Validate correctness of argument passed to map functions
9
9
  #
10
10
  # @param [String] key
11
- # @param [Symbol] to
12
- # @param [Hash] using
11
+ # @param [Symbol, nil] to
12
+ # @param [Symbol, nil] receiver
13
+ # @param [Hash, nil] using
13
14
  #
14
15
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
15
16
  #
16
17
  # @api private
17
- def self.validate_arguments(key, to, using)
18
+ def self.validate_arguments(key, to, receiver, using)
18
19
  if to.nil? && using.nil?
19
20
  msg = ":to or :using argument is required for mapping '#{key}'"
20
21
  raise IncorrectMappingArgumentsError, msg
21
22
  end
22
23
 
24
+ if to.nil? && !receiver.nil?
25
+ msg = ":receiver argument for mapping '#{key}' " \
26
+ 'can only be used together with :to argument'
27
+ raise IncorrectMappingArgumentsError, msg
28
+ end
29
+
23
30
  if !using.nil? && (using[:from].nil? || using[:to].nil?)
24
31
  msg = ":using argument for mapping '#{key}' requires :to and :from keys"
25
32
  raise IncorrectMappingArgumentsError, msg
@@ -13,25 +13,28 @@ module Shale
13
13
  #
14
14
  # @param [String] element
15
15
  # @param [Symbol, nil] to
16
+ # @param [Symbol, nil] receiver
16
17
  # @param [Hash, nil] using
17
18
  # @param [String, nil] namespace
18
19
  # @param [String, nil] prefix
19
20
  # @param [true, false] cdata
20
- # @param [true, false] render_nil
21
+ # @param [true, false, nil] render_nil
21
22
  #
22
23
  # @api private
23
24
  def map_element(
24
25
  element,
25
26
  to: nil,
27
+ receiver: nil,
26
28
  using: nil,
27
29
  namespace: :undefined,
28
30
  prefix: :undefined,
29
31
  cdata: false,
30
- render_nil: false
32
+ render_nil: nil
31
33
  )
32
34
  super(
33
35
  element,
34
36
  to: to,
37
+ receiver: receiver,
35
38
  using: using,
36
39
  namespace: namespace,
37
40
  prefix: prefix,
@@ -44,23 +47,26 @@ module Shale
44
47
  #
45
48
  # @param [String] attribute
46
49
  # @param [Symbol, nil] to
50
+ # @param [Symbol, nil] receiver
47
51
  # @param [Hash, nil] using
48
52
  # @param [String, nil] namespace
49
53
  # @param [String, nil] prefix
50
- # @param [true, false] render_nil
54
+ # @param [true, false, nil] render_nil
51
55
  #
52
56
  # @api private
53
57
  def map_attribute(
54
58
  attribute,
55
59
  to: nil,
60
+ receiver: nil,
56
61
  using: nil,
57
62
  namespace: nil,
58
63
  prefix: nil,
59
- render_nil: false
64
+ render_nil: nil
60
65
  )
61
66
  super(
62
67
  attribute,
63
68
  to: to,
69
+ receiver: receiver,
64
70
  using: using,
65
71
  namespace: namespace,
66
72
  prefix: prefix,
@@ -71,12 +77,22 @@ module Shale
71
77
  # Map document's content to object's attribute
72
78
  #
73
79
  # @param [Symbol] to
80
+ # @param [Symbol, nil] receiver
74
81
  # @param [Hash, nil] using
75
82
  # @param [true, false] cdata
76
83
  #
77
84
  # @api private
78
- def map_content(to: nil, using: nil, cdata: false)
79
- super(to: to, using: using, cdata: cdata)
85
+ def map_content(to: nil, receiver: nil, using: nil, cdata: false)
86
+ super(to: to, receiver: receiver, using: using, cdata: cdata)
87
+ end
88
+
89
+ # Set render_nil default
90
+ #
91
+ # @param [true, false] val
92
+ #
93
+ # @api private
94
+ def render_nil(val)
95
+ @render_nil_default = val
80
96
  end
81
97
 
82
98
  # Map group of nodes to mapping methods
@@ -67,18 +67,20 @@ module Shale
67
67
  @root = ''
68
68
  @default_namespace = Descriptor::XmlNamespace.new
69
69
  @finalized = false
70
+ @render_nil_default = false
70
71
  end
71
72
 
72
73
  # Map element to attribute
73
74
  #
74
75
  # @param [String] element
75
76
  # @param [Symbol, nil] to
77
+ # @param [Symbol, nil] receiver
76
78
  # @param [Hash, nil] using
77
79
  # @param [String, nil] group
78
80
  # @param [String, nil] namespace
79
81
  # @param [String, nil] prefix
80
82
  # @param [true, false] cdata
81
- # @param [true, false] render_nil
83
+ # @param [true, false, nil] render_nil
82
84
  #
83
85
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
84
86
  #
@@ -86,14 +88,15 @@ module Shale
86
88
  def map_element(
87
89
  element,
88
90
  to: nil,
91
+ receiver: nil,
89
92
  using: nil,
90
93
  group: nil,
91
94
  namespace: :undefined,
92
95
  prefix: :undefined,
93
96
  cdata: false,
94
- render_nil: false
97
+ render_nil: nil
95
98
  )
96
- Validator.validate_arguments(element, to, using)
99
+ Validator.validate_arguments(element, to, receiver, using)
97
100
  Validator.validate_namespace(element, namespace, prefix)
98
101
 
99
102
  if namespace == :undefined && prefix == :undefined
@@ -109,11 +112,12 @@ module Shale
109
112
  @elements[namespaced_element] = Descriptor::Xml.new(
110
113
  name: element,
111
114
  attribute: to,
115
+ receiver: receiver,
112
116
  methods: using,
113
117
  group: group,
114
118
  namespace: Descriptor::XmlNamespace.new(nsp, pfx),
115
119
  cdata: cdata,
116
- render_nil: render_nil
120
+ render_nil: render_nil.nil? ? @render_nil_default : render_nil
117
121
  )
118
122
  end
119
123
 
@@ -121,10 +125,12 @@ module Shale
121
125
  #
122
126
  # @param [String] attribute
123
127
  # @param [Symbol, nil] to
128
+ # @param [Symbol, nil] receiver
124
129
  # @param [Hash, nil] using
130
+ # @param [String, nil] group
125
131
  # @param [String, nil] namespace
126
132
  # @param [String, nil] prefix
127
- # @param [true, false] render_nil
133
+ # @param [true, false, nil] render_nil
128
134
  #
129
135
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
130
136
  #
@@ -132,13 +138,14 @@ module Shale
132
138
  def map_attribute(
133
139
  attribute,
134
140
  to: nil,
141
+ receiver: nil,
135
142
  using: nil,
136
143
  group: nil,
137
144
  namespace: nil,
138
145
  prefix: nil,
139
- render_nil: false
146
+ render_nil: nil
140
147
  )
141
- Validator.validate_arguments(attribute, to, using)
148
+ Validator.validate_arguments(attribute, to, receiver, using)
142
149
  Validator.validate_namespace(attribute, namespace, prefix)
143
150
 
144
151
  namespaced_attribute = [namespace, attribute].compact.join(':')
@@ -146,27 +153,31 @@ module Shale
146
153
  @attributes[namespaced_attribute] = Descriptor::Xml.new(
147
154
  name: attribute,
148
155
  attribute: to,
156
+ receiver: receiver,
149
157
  methods: using,
150
158
  namespace: Descriptor::XmlNamespace.new(namespace, prefix),
151
159
  cdata: false,
152
160
  group: group,
153
- render_nil: render_nil
161
+ render_nil: render_nil.nil? ? @render_nil_default : render_nil
154
162
  )
155
163
  end
156
164
 
157
165
  # Map document's content to object's attribute
158
166
  #
159
167
  # @param [Symbol] to
168
+ # @param [Symbol, nil] receiver
160
169
  # @param [Hash, nil] using
170
+ # @param [String, nil] group
161
171
  # @param [true, false] cdata
162
172
  #
163
173
  # @api private
164
- def map_content(to: nil, using: nil, group: nil, cdata: false)
165
- Validator.validate_arguments('content', to, using)
174
+ def map_content(to: nil, receiver: nil, using: nil, group: nil, cdata: false)
175
+ Validator.validate_arguments('content', to, receiver, using)
166
176
 
167
177
  @content = Descriptor::Xml.new(
168
178
  name: nil,
169
179
  attribute: to,
180
+ receiver: receiver,
170
181
  methods: using,
171
182
  namespace: Descriptor::XmlNamespace.new(nil, nil),
172
183
  cdata: cdata,
@@ -215,8 +226,6 @@ module Shale
215
226
  def initialize_dup(other)
216
227
  @elements = other.instance_variable_get('@elements').dup
217
228
  @attributes = other.instance_variable_get('@attributes').dup
218
- @content = other.instance_variable_get('@content').dup
219
- @root = other.instance_variable_get('@root').dup
220
229
  @default_namespace = other.instance_variable_get('@default_namespace').dup
221
230
  @finalized = false
222
231
 
@@ -23,32 +23,52 @@ module Shale
23
23
  # @api private
24
24
  attr_reader :properties
25
25
 
26
- # Name setter
26
+ # Root name setter
27
27
  #
28
28
  # @param [String] val
29
29
  #
30
30
  # @api private
31
- attr_writer :name
31
+ attr_writer :root_name
32
32
 
33
33
  # Initialize object
34
34
  #
35
35
  # @param [String] id
36
- # @param [String] name
36
+ # @param [String] root_name
37
+ # @param [String, nil] package
37
38
  #
38
39
  # @api private
39
- def initialize(id, name)
40
+ def initialize(id, root_name, package)
40
41
  @id = id
41
- @name = name
42
+ @root_name = root_name
43
+ @package = package ? Utils.classify(package) : nil
42
44
  @properties = []
43
45
  end
44
46
 
45
- # Return name
47
+ # Return base name
48
+ #
49
+ # @return [String]
50
+ #
51
+ # @api private
52
+ def root_name
53
+ Utils.classify(@root_name)
54
+ end
55
+
56
+ # Return namespaced name
46
57
  #
47
58
  # @return [String]
48
59
  #
49
60
  # @api private
50
61
  def name
51
- Utils.classify(@name)
62
+ Utils.classify([@package, @root_name].compact.join('::'))
63
+ end
64
+
65
+ # Return module names
66
+ #
67
+ # @return [Array<String>]
68
+ #
69
+ # @api private
70
+ def modules
71
+ (@package || '').split('::')
52
72
  end
53
73
 
54
74
  # Return file name
@@ -57,7 +77,31 @@ module Shale
57
77
  #
58
78
  # @api private
59
79
  def file_name
60
- Utils.snake_case(@name)
80
+ Utils.snake_case(name)
81
+ end
82
+
83
+ # Return relative path to target
84
+ #
85
+ # @param [String] target
86
+ #
87
+ # @return [String]
88
+ #
89
+ # @api private
90
+ def relative_path(target)
91
+ base_paths = file_name.split('/')
92
+ target_paths = target.split('/')
93
+
94
+ common_paths_length = 0
95
+
96
+ base_paths.length.times do |i|
97
+ break if base_paths[i] != target_paths[i]
98
+ common_paths_length += 1
99
+ end
100
+
101
+ unique_base_paths = base_paths[common_paths_length..-1]
102
+ unique_target_paths = target_paths[common_paths_length..-1]
103
+
104
+ ((0...unique_base_paths.length - 1).map { '..' } + unique_target_paths).join('/')
61
105
  end
62
106
 
63
107
  # Return references