shale 0.5.0 → 0.7.1

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.
@@ -30,19 +30,20 @@ module Shale
30
30
  # Serialize Ox document into XML
31
31
  #
32
32
  # @param [::Ox::Document, ::Ox::Element] doc Ox document
33
- # @param [Array<Symbol>] options
33
+ # @param [true, false] pretty
34
+ # @param [true, false] declaration
34
35
  #
35
36
  # @return [String]
36
37
  #
37
38
  # @api private
38
- def self.dump(doc, *options)
39
+ def self.dump(doc, pretty: false, declaration: false)
39
40
  opts = { indent: -1, with_xml: false }
40
41
 
41
- if options.include?(:pretty)
42
+ if pretty
42
43
  opts[:indent] = 2
43
44
  end
44
45
 
45
- if options.include?(:declaration)
46
+ if declaration
46
47
  doc[:version] = '1.0'
47
48
  opts[:with_xml] = true
48
49
  end
@@ -42,6 +42,16 @@ module Shale
42
42
  ::REXML::Element.new(name, nil, attribute_quote: :quote)
43
43
  end
44
44
 
45
+ # Create CDATA node and add it to parent
46
+ #
47
+ # @param [String] text
48
+ # @param [::REXML::Element] parent
49
+ #
50
+ # @api private
51
+ def create_cdata(text, parent)
52
+ ::REXML::CData.new(text, true, parent)
53
+ end
54
+
45
55
  # Add XML namespace to document
46
56
  #
47
57
  # @param [String] prefix
@@ -60,7 +70,7 @@ module Shale
60
70
  #
61
71
  # @api private
62
72
  def add_attribute(element, name, value)
63
- element.add_attribute(name, value)
73
+ element.add_attribute(name, value || '')
64
74
  end
65
75
 
66
76
  # Add child element to REXML element
@@ -31,19 +31,20 @@ module Shale
31
31
  # Serialize REXML document into XML
32
32
  #
33
33
  # @param [::REXML::Document] doc REXML document
34
- # @param [Array<Symbol>] options
34
+ # @param [true, false] pretty
35
+ # @param [true, false] declaration
35
36
  #
36
37
  # @return [String]
37
38
  #
38
39
  # @api private
39
- def self.dump(doc, *options)
40
- if options.include?(:declaration)
40
+ def self.dump(doc, pretty: false, declaration: false)
41
+ if declaration
41
42
  doc.add(::REXML::XMLDecl.new)
42
43
  end
43
44
 
44
45
  io = StringIO.new
45
46
 
46
- if options.include?(:pretty)
47
+ if pretty
47
48
  formatter = ::REXML::Formatters::Pretty.new
48
49
  formatter.compact = true
49
50
  else
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'toml-rb'
4
+
5
+ module Shale
6
+ module Adapter
7
+ # TOML adapter
8
+ #
9
+ # @api public
10
+ class TomlRB
11
+ # Parse TOML into Hash
12
+ #
13
+ # @param [String] toml TOML document
14
+ #
15
+ # @return [Hash]
16
+ #
17
+ # @api private
18
+ def self.load(toml)
19
+ ::TomlRB.parse(toml)
20
+ end
21
+
22
+ # Serialize Hash into TOML
23
+ #
24
+ # @param [Hash] obj Hash object
25
+ #
26
+ # @return [String]
27
+ #
28
+ # @api private
29
+ def self.dump(obj)
30
+ ::TomlRB.dump(obj)
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/shale/error.rb CHANGED
@@ -1,22 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Shale
4
- # Error message displayed when adapter is not set
4
+ # Error message displayed when TOML adapter is not set
5
5
  # @api private
6
- ADAPTER_NOT_SET_MESSAGE = <<~MSG
6
+ TOML_ADAPTER_NOT_SET_MESSAGE = <<~MSG
7
+ TOML Adapter is not set.
8
+ To use Shale with TOML documents you have to install parser and set adapter.
9
+
10
+ # To use Tomlib:
11
+ # Make sure tomlib is installed eg. execute: gem install tomlib
12
+ Shale.toml_adapter = Tomlib
13
+
14
+ # To use toml-rb:
15
+ # Make sure toml-rb is installed eg. execute: gem install toml-rb
16
+ require 'shale/adapter/toml_rb'
17
+ Shale.toml_adapter = Shale::Adapter::TomlRB
18
+ MSG
19
+
20
+ # Error message displayed when XML adapter is not set
21
+ # @api private
22
+ XML_ADAPTER_NOT_SET_MESSAGE = <<~MSG
7
23
  XML Adapter is not set.
8
24
  To use Shale with XML documents you have to install parser and set adapter.
9
25
 
10
- To use REXML:
26
+ # To use REXML:
11
27
  require 'shale/adapter/rexml'
12
28
  Shale.xml_adapter = Shale::Adapter::REXML
13
29
 
14
- To use Nokogiri:
30
+ # To use Nokogiri:
15
31
  # Make sure Nokogiri is installed eg. execute: gem install nokogiri
16
32
  require 'shale/adapter/nokogiri'
17
33
  Shale.xml_adapter = Shale::Adapter::Nokogiri
18
34
 
19
- To use OX:
35
+ # To use OX:
20
36
  # Make sure Ox is installed eg. execute: gem install ox
21
37
  require 'shale/adapter/ox'
22
38
  Shale.xml_adapter = Shale::Adapter::Ox
@@ -52,6 +68,12 @@ module Shale
52
68
  end
53
69
  end
54
70
 
71
+ # Error for passing incorrect model type
72
+ #
73
+ # @api private
74
+ class IncorrectModelError < StandardError
75
+ end
76
+
55
77
  # Error for passing incorrect arguments to map functions
56
78
  #
57
79
  # @api private
data/lib/shale/mapper.rb CHANGED
@@ -43,10 +43,12 @@ module Shale
43
43
  #
44
44
  # @api public
45
45
  class Mapper < Type::Complex
46
+ @model = nil
46
47
  @attributes = {}
47
48
  @hash_mapping = Mapping::Dict.new
48
49
  @json_mapping = Mapping::Dict.new
49
50
  @yaml_mapping = Mapping::Dict.new
51
+ @toml_mapping = Mapping::Dict.new
50
52
  @xml_mapping = Mapping::Xml.new
51
53
 
52
54
  class << self
@@ -78,6 +80,13 @@ module Shale
78
80
  # @api public
79
81
  attr_reader :yaml_mapping
80
82
 
83
+ # Return TOML mapping object
84
+ #
85
+ # @return [Shale::Mapping::Dict]
86
+ #
87
+ # @api public
88
+ attr_reader :toml_mapping
89
+
81
90
  # Return XML mapping object
82
91
  #
83
92
  # @return [Shale::Mapping::XML]
@@ -88,16 +97,20 @@ module Shale
88
97
  # @api private
89
98
  def inherited(subclass)
90
99
  super
100
+
101
+ subclass.instance_variable_set('@model', subclass)
91
102
  subclass.instance_variable_set('@attributes', @attributes.dup)
92
103
 
93
104
  subclass.instance_variable_set('@__hash_mapping_init', @hash_mapping.dup)
94
105
  subclass.instance_variable_set('@__json_mapping_init', @json_mapping.dup)
95
106
  subclass.instance_variable_set('@__yaml_mapping_init', @yaml_mapping.dup)
107
+ subclass.instance_variable_set('@__toml_mapping_init', @toml_mapping.dup)
96
108
  subclass.instance_variable_set('@__xml_mapping_init', @xml_mapping.dup)
97
109
 
98
110
  subclass.instance_variable_set('@hash_mapping', @hash_mapping.dup)
99
111
  subclass.instance_variable_set('@json_mapping', @json_mapping.dup)
100
112
  subclass.instance_variable_set('@yaml_mapping', @yaml_mapping.dup)
113
+ subclass.instance_variable_set('@toml_mapping', @toml_mapping.dup)
101
114
 
102
115
  xml_mapping = @xml_mapping.dup
103
116
  xml_mapping.root(Utils.underscore(subclass.name || ''))
@@ -105,6 +118,15 @@ module Shale
105
118
  subclass.instance_variable_set('@xml_mapping', xml_mapping.dup)
106
119
  end
107
120
 
121
+ def model(klass = nil)
122
+ if klass
123
+ @model = klass
124
+ xml_mapping.root(Utils.underscore(@model.name))
125
+ else
126
+ @model
127
+ end
128
+ end
129
+
108
130
  # Define attribute on class
109
131
  #
110
132
  # @param [Symbol] name Name of the attribute
@@ -143,10 +165,11 @@ module Shale
143
165
 
144
166
  @attributes[name] = Attribute.new(name, type, collection, default)
145
167
 
146
- @hash_mapping.map(name.to_s, to: name)
147
- @json_mapping.map(name.to_s, to: name)
148
- @yaml_mapping.map(name.to_s, to: name)
149
- @xml_mapping.map_element(name.to_s, to: name)
168
+ @hash_mapping.map(name.to_s, to: name) unless @hash_mapping.finalized?
169
+ @json_mapping.map(name.to_s, to: name) unless @json_mapping.finalized?
170
+ @yaml_mapping.map(name.to_s, to: name) unless @yaml_mapping.finalized?
171
+ @toml_mapping.map(name.to_s, to: name) unless @toml_mapping.finalized?
172
+ @xml_mapping.map_element(name.to_s, to: name) unless @xml_mapping.finalized?
150
173
 
151
174
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
152
175
  attr_reader :#{name}
@@ -168,7 +191,7 @@ module Shale
168
191
  # attribute :age, Shale::Type::Integer
169
192
  #
170
193
  # hsh do
171
- # map 'firatName', to: :first_name
194
+ # map 'firstName', to: :first_name
172
195
  # map 'lastName', to: :last_name
173
196
  # map 'age', to: :age
174
197
  # end
@@ -177,6 +200,7 @@ module Shale
177
200
  # @api public
178
201
  def hsh(&block)
179
202
  @hash_mapping = @__hash_mapping_init.dup
203
+ @hash_mapping.finalize!
180
204
  @hash_mapping.instance_eval(&block)
181
205
  end
182
206
 
@@ -191,7 +215,7 @@ module Shale
191
215
  # attribute :age, Shale::Type::Integer
192
216
  #
193
217
  # json do
194
- # map 'firatName', to: :first_name
218
+ # map 'firstName', to: :first_name
195
219
  # map 'lastName', to: :last_name
196
220
  # map 'age', to: :age
197
221
  # end
@@ -200,6 +224,7 @@ module Shale
200
224
  # @api public
201
225
  def json(&block)
202
226
  @json_mapping = @__json_mapping_init.dup
227
+ @json_mapping.finalize!
203
228
  @json_mapping.instance_eval(&block)
204
229
  end
205
230
 
@@ -214,7 +239,7 @@ module Shale
214
239
  # attribute :age, Shale::Type::Integer
215
240
  #
216
241
  # yaml do
217
- # map 'firat_name', to: :first_name
242
+ # map 'first_name', to: :first_name
218
243
  # map 'last_name', to: :last_name
219
244
  # map 'age', to: :age
220
245
  # end
@@ -223,9 +248,34 @@ module Shale
223
248
  # @api public
224
249
  def yaml(&block)
225
250
  @yaml_mapping = @__yaml_mapping_init.dup
251
+ @yaml_mapping.finalize!
226
252
  @yaml_mapping.instance_eval(&block)
227
253
  end
228
254
 
255
+ # Define TOML mapping
256
+ #
257
+ # @param [Proc] block
258
+ #
259
+ # @example
260
+ # calss Person < Shale::Mapper
261
+ # attribute :first_name, Shale::Type::String
262
+ # attribute :last_name, Shale::Type::String
263
+ # attribute :age, Shale::Type::Integer
264
+ #
265
+ # toml do
266
+ # map 'first_name', to: :first_name
267
+ # map 'last_name', to: :last_name
268
+ # map 'age', to: :age
269
+ # end
270
+ # end
271
+ #
272
+ # @api public
273
+ def toml(&block)
274
+ @toml_mapping = @__toml_mapping_init.dup
275
+ @toml_mapping.finalize!
276
+ @toml_mapping.instance_eval(&block)
277
+ end
278
+
229
279
  # Define XML mapping
230
280
  #
231
281
  # @param [Proc] block
@@ -247,6 +297,8 @@ module Shale
247
297
  # @api public
248
298
  def xml(&block)
249
299
  @xml_mapping = @__xml_mapping_init.dup
300
+ @xml_mapping.finalize!
301
+ @xml_mapping.root('')
250
302
  @xml_mapping.instance_eval(&block)
251
303
  end
252
304
  end
@@ -40,17 +40,28 @@ module Shale
40
40
  # @param [String] name
41
41
  # @param [Symbol, nil] attribute
42
42
  # @param [Hash, nil] methods
43
+ # @param [true, false] render_nil
43
44
  #
44
45
  # @api private
45
- def initialize(name:, attribute:, methods:)
46
+ def initialize(name:, attribute:, methods:, render_nil:)
46
47
  @name = name
47
48
  @attribute = attribute
49
+ @render_nil = render_nil
48
50
 
49
51
  if methods
50
52
  @method_from = methods[:from]
51
53
  @method_to = methods[:to]
52
54
  end
53
55
  end
56
+
57
+ # Check render_nil
58
+ #
59
+ # @return [true, false]
60
+ #
61
+ # @api private
62
+ def render_nil?
63
+ @render_nil == true
64
+ end
54
65
  end
55
66
  end
56
67
  end
@@ -16,17 +16,27 @@ module Shale
16
16
  # @api private
17
17
  attr_reader :namespace
18
18
 
19
+ # Return cdata
20
+ #
21
+ # @return [true, false]
22
+ #
23
+ # @api private
24
+ attr_reader :cdata
25
+
19
26
  # Initialize instance
20
27
  #
21
28
  # @param [String] name
22
29
  # @param [Symbol, String] attribute
23
30
  # @param [Hash, nil] methods
24
31
  # @param [Shale::Mapping::XmlNamespace] namespace
32
+ # @param [true, false] cdata
33
+ # @param [true, false] render_nil
25
34
  #
26
35
  # @api private
27
- def initialize(name:, attribute:, methods:, namespace:)
28
- super(name: name, attribute: attribute, methods: methods)
36
+ def initialize(name:, attribute:, methods:, namespace:, cdata:, render_nil:)
37
+ super(name: name, attribute: attribute, methods: methods, render_nil: render_nil)
29
38
  @namespace = namespace
39
+ @cdata = cdata
30
40
  end
31
41
 
32
42
  # Return name with XML prefix
@@ -22,6 +22,7 @@ module Shale
22
22
  def initialize
23
23
  super
24
24
  @keys = {}
25
+ @finalized = false
25
26
  end
26
27
 
27
28
  # Map key to attribute
@@ -29,18 +30,41 @@ module Shale
29
30
  # @param [String] key Document's key
30
31
  # @param [Symbol, nil] to Object's attribute
31
32
  # @param [Hash, nil] using
33
+ # @param [true, false] render_nil
32
34
  #
33
35
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
34
36
  #
35
37
  # @api private
36
- def map(key, to: nil, using: nil)
38
+ def map(key, to: nil, using: nil, render_nil: false)
37
39
  Validator.validate_arguments(key, to, using)
38
- @keys[key] = Descriptor::Dict.new(name: key, attribute: to, methods: using)
40
+ @keys[key] = Descriptor::Dict.new(
41
+ name: key,
42
+ attribute: to,
43
+ methods: using,
44
+ render_nil: render_nil
45
+ )
46
+ end
47
+
48
+ # Set the "finalized" instance variable to true
49
+ #
50
+ # @api private
51
+ def finalize!
52
+ @finalized = true
53
+ end
54
+
55
+ # Query the "finalized" instance variable
56
+ #
57
+ # @return [truem false]
58
+ #
59
+ # @api private
60
+ def finalized?
61
+ @finalized
39
62
  end
40
63
 
41
64
  # @api private
42
65
  def initialize_dup(other)
43
66
  @keys = other.instance_variable_get('@keys').dup
67
+ @finalized = false
44
68
  super
45
69
  end
46
70
  end
@@ -63,6 +63,7 @@ module Shale
63
63
  @content = nil
64
64
  @root = ''
65
65
  @default_namespace = Descriptor::XmlNamespace.new
66
+ @finalized = false
66
67
  end
67
68
 
68
69
  # Map element to attribute
@@ -76,7 +77,15 @@ module Shale
76
77
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
77
78
  #
78
79
  # @api private
79
- def map_element(element, to: nil, using: nil, namespace: :undefined, prefix: :undefined)
80
+ def map_element(
81
+ element,
82
+ to: nil,
83
+ using: nil,
84
+ namespace: :undefined,
85
+ prefix: :undefined,
86
+ cdata: false,
87
+ render_nil: false
88
+ )
80
89
  Validator.validate_arguments(element, to, using)
81
90
  Validator.validate_namespace(element, namespace, prefix)
82
91
 
@@ -94,7 +103,9 @@ module Shale
94
103
  name: element,
95
104
  attribute: to,
96
105
  methods: using,
97
- namespace: Descriptor::XmlNamespace.new(nsp, pfx)
106
+ namespace: Descriptor::XmlNamespace.new(nsp, pfx),
107
+ cdata: cdata,
108
+ render_nil: render_nil
98
109
  )
99
110
  end
100
111
 
@@ -109,7 +120,14 @@ module Shale
109
120
  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
110
121
  #
111
122
  # @api private
112
- def map_attribute(attribute, to: nil, using: nil, namespace: nil, prefix: nil)
123
+ def map_attribute(
124
+ attribute,
125
+ to: nil,
126
+ using: nil,
127
+ namespace: nil,
128
+ prefix: nil,
129
+ render_nil: false
130
+ )
113
131
  Validator.validate_arguments(attribute, to, using)
114
132
  Validator.validate_namespace(attribute, namespace, prefix)
115
133
 
@@ -119,7 +137,9 @@ module Shale
119
137
  name: attribute,
120
138
  attribute: to,
121
139
  methods: using,
122
- namespace: Descriptor::XmlNamespace.new(namespace, prefix)
140
+ namespace: Descriptor::XmlNamespace.new(namespace, prefix),
141
+ cdata: false,
142
+ render_nil: render_nil
123
143
  )
124
144
  end
125
145
 
@@ -128,8 +148,17 @@ module Shale
128
148
  # @param [Symbol] to Object's attribute
129
149
  #
130
150
  # @api private
131
- def map_content(to:)
132
- @content = to
151
+ def map_content(to: nil, using: nil, cdata: false)
152
+ Validator.validate_arguments('content', to, using)
153
+
154
+ @content = Descriptor::Xml.new(
155
+ name: nil,
156
+ attribute: to,
157
+ methods: using,
158
+ namespace: nil,
159
+ cdata: cdata,
160
+ render_nil: false
161
+ )
133
162
  end
134
163
 
135
164
  # Set the name for root element
@@ -152,6 +181,22 @@ module Shale
152
181
  @default_namespace.prefix = prefix
153
182
  end
154
183
 
184
+ # Set the "finalized" instance variable to true
185
+ #
186
+ # @api private
187
+ def finalize!
188
+ @finalized = true
189
+ end
190
+
191
+ # Query the "finalized" instance variable
192
+ #
193
+ # @return [truem false]
194
+ #
195
+ # @api private
196
+ def finalized?
197
+ @finalized
198
+ end
199
+
155
200
  # @api private
156
201
  def initialize_dup(other)
157
202
  @elements = other.instance_variable_get('@elements').dup
@@ -159,6 +204,7 @@ module Shale
159
204
  @content = other.instance_variable_get('@content').dup
160
205
  @root = other.instance_variable_get('@root').dup
161
206
  @default_namespace = other.instance_variable_get('@default_namespace').dup
207
+ @finalized = false
162
208
 
163
209
  super
164
210
  end
@@ -124,9 +124,7 @@ module Shale
124
124
  # @api public
125
125
  def to_schema(klass, id: nil, title: nil, description: nil, pretty: false)
126
126
  schema = as_schema(klass, id: id, title: title, description: description)
127
- options = pretty ? :pretty : nil
128
-
129
- Shale.json_adapter.dump(schema, options)
127
+ Shale.json_adapter.dump(schema, pretty: pretty)
130
128
  end
131
129
 
132
130
  private
@@ -200,7 +200,7 @@ module Shale
200
200
  # @api public
201
201
  def as_models(schemas)
202
202
  unless Shale.xml_adapter
203
- raise AdapterError, ADAPTER_NOT_SET_MESSAGE
203
+ raise AdapterError, XML_ADAPTER_NOT_SET_MESSAGE
204
204
  end
205
205
 
206
206
  if Shale.xml_adapter.name == 'Shale::Adapter::Ox'
@@ -35,8 +35,8 @@ module Shale
35
35
  def as_xml(doc)
36
36
  import = doc.create_element('xs:import')
37
37
 
38
- doc.add_attribute(import, 'namespace', @namespace)
39
- doc.add_attribute(import, 'schemaLocation', @location)
38
+ doc.add_attribute(import, 'namespace', @namespace) if @namespace
39
+ doc.add_attribute(import, 'schemaLocation', @location) if @location
40
40
 
41
41
  import
42
42
  end
@@ -222,13 +222,11 @@ module Shale
222
222
  def to_schemas(klass, base_name = nil, pretty: false, declaration: false)
223
223
  schemas = as_schemas(klass, base_name)
224
224
 
225
- options = [
226
- pretty ? :pretty : nil,
227
- declaration ? :declaration : nil,
228
- ]
229
-
230
225
  schemas.to_h do |schema|
231
- [schema.name, Shale.xml_adapter.dump(schema.as_xml, *options)]
226
+ [
227
+ schema.name,
228
+ Shale.xml_adapter.dump(schema.as_xml, pretty: pretty, declaration: declaration),
229
+ ]
232
230
  end
233
231
  end
234
232