shale 0.7.1 → 0.9.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 +19 -2
- data/README.md +184 -15
- data/lib/shale/adapter/csv.rb +48 -0
- data/lib/shale/adapter/nokogiri/document.rb +7 -2
- data/lib/shale/adapter/nokogiri.rb +11 -4
- data/lib/shale/adapter/ox.rb +10 -4
- data/lib/shale/adapter/rexml.rb +18 -4
- data/lib/shale/mapper.rb +40 -1
- data/lib/shale/mapping/descriptor/dict.rb +10 -1
- data/lib/shale/mapping/descriptor/xml.rb +19 -2
- data/lib/shale/mapping/dict.rb +14 -46
- data/lib/shale/mapping/dict_base.rb +76 -0
- data/lib/shale/mapping/dict_group.rb +41 -0
- data/lib/shale/mapping/group/dict.rb +55 -0
- data/lib/shale/mapping/group/dict_grouping.rb +41 -0
- data/lib/shale/mapping/group/xml.rb +43 -0
- data/lib/shale/mapping/group/xml_grouping.rb +27 -0
- data/lib/shale/mapping/xml.rb +40 -152
- data/lib/shale/mapping/xml_base.rb +227 -0
- data/lib/shale/mapping/xml_group.rb +70 -0
- data/lib/shale/type/complex.rb +198 -18
- data/lib/shale/type/date.rb +11 -0
- data/lib/shale/type/time.rb +11 -0
- data/lib/shale/type/value.rb +22 -0
- data/lib/shale/version.rb +1 -1
- data/lib/shale.rb +30 -4
- data/shale.gemspec +3 -3
- metadata +14 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f880bc8d984c45e7e8a05bd155c1014df237e037263c7bf68a7ae82c0e49ea4
|
4
|
+
data.tar.gz: ba7a2f12bed87e048dd53d43900f1c8203d90f5f89a43b3824475ddda39eb07b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54023d4f621dae53537f73e0ad79d3736d5d52e605c1a7da2c4bdb06588b348feaae9066ce00b6b3aedc9e84ea23a425884eabf987717ffda6d3c22eccc6325f
|
7
|
+
data.tar.gz: e82cad292dab557891cad4f210bfb4a97d2096a6d2151a5a8aef020358accb5986e527e32a141a9a2e3a01d594e9a3adb42c0f7e8d17464517731136f63289a2
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,26 @@
|
|
1
|
-
## [0.
|
1
|
+
## [0.9.0] - 2022-10-31
|
2
|
+
|
3
|
+
### Added
|
4
|
+
- Support for CSV
|
5
|
+
- Allow to specify version and add encoding to XML declaration
|
6
|
+
- Support for mapping/generating collections
|
7
|
+
|
8
|
+
## [0.8.0] - 2022-08-30
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Allow to group mappings using `group` block
|
12
|
+
- Bring back Ruby 2.6 support
|
13
|
+
|
14
|
+
### Changed
|
15
|
+
- Use anonymous module for attributes definition.
|
16
|
+
It allows to override accessors and `super` works as expected.
|
17
|
+
|
18
|
+
## [0.7.1] - 2022-08-12
|
2
19
|
|
3
20
|
### Fixed
|
4
21
|
- Fix broken handling of Date and Time types
|
5
22
|
|
6
|
-
## [0.7.0] -
|
23
|
+
## [0.7.0] - 2022-08-09
|
7
24
|
|
8
25
|
### Added
|
9
26
|
- `only: []` and `except: []` options that allow to controll what attributes are rendered/parsed
|
data/README.md
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
# Shale
|
2
2
|
|
3
|
-
Shale is a Ruby object mapper and serializer for JSON, YAML, TOML and XML.
|
4
|
-
It allows you to parse JSON, YAML, TOML and XML data and convert it into Ruby data structures,
|
5
|
-
as well as serialize data structures into JSON, YAML, TOML or XML.
|
3
|
+
Shale is a Ruby object mapper and serializer for JSON, YAML, TOML, CSV and XML.
|
4
|
+
It allows you to parse JSON, YAML, TOML, CSV and XML data and convert it into Ruby data structures,
|
5
|
+
as well as serialize data structures into JSON, YAML, TOML, CSV or XML.
|
6
6
|
|
7
7
|
Documentation with interactive examples is available at [Shale website](https://www.shalerb.org)
|
8
8
|
|
9
9
|
## Features
|
10
10
|
|
11
|
-
* Convert JSON, YAML, TOML and XML to Ruby data model
|
12
|
-
* Convert Ruby data model to JSON, YAML, TOML and XML
|
11
|
+
* Convert JSON, YAML, TOML, CSV and XML to Ruby data model
|
12
|
+
* Convert Ruby data model to JSON, YAML, TOML, CSV and XML
|
13
13
|
* Generate JSON and XML Schema from Ruby models
|
14
14
|
* Compile JSON and XML Schema into Ruby models
|
15
|
-
* Out of the box support for JSON, YAML, Tomlib, toml-rb, Nokogiri, REXML and Ox parsers
|
15
|
+
* Out of the box support for JSON, YAML, Tomlib, toml-rb, CSV, Nokogiri, REXML and Ox parsers
|
16
16
|
* Support for custom adapters
|
17
17
|
|
18
18
|
## Installation
|
19
19
|
|
20
|
-
Shale supports Ruby (MRI) 2.
|
20
|
+
Shale supports Ruby (MRI) 2.6+
|
21
21
|
|
22
22
|
Add this line to your application's Gemfile:
|
23
23
|
|
@@ -51,9 +51,13 @@ $ gem install shale
|
|
51
51
|
* [Converting object to Hash](#converting-object-to-hash)
|
52
52
|
* [Converting XML to object](#converting-xml-to-object)
|
53
53
|
* [Converting object to XML](#converting-object-to-xml)
|
54
|
+
* [Converting CSV to object](#converting-csv-to-object)
|
55
|
+
* [Converting object to CSV](#converting-object-to-csv)
|
56
|
+
* [Converting collections](#converting-collections)
|
54
57
|
* [Mapping JSON keys to object attributes](#mapping-json-keys-to-object-attributes)
|
55
58
|
* [Mapping YAML keys to object attributes](#mapping-yaml-keys-to-object-attributes)
|
56
59
|
* [Mapping TOML keys to object attributes](#mapping-toml-keys-to-object-attributes)
|
60
|
+
* [Mapping CSV columns to object attributes](#mapping-csv-columns-to-object-attributes)
|
57
61
|
* [Mapping Hash keys to object attributes](#mapping-hash-keys-to-object-attributes)
|
58
62
|
* [Mapping XML elements and attributes to object attributes](#mapping-xml-elements-and-attributes-to-object-attributes)
|
59
63
|
* [Using XML namespaces](#using-xml-namespaces)
|
@@ -346,6 +350,70 @@ person.to_xml
|
|
346
350
|
# </person>
|
347
351
|
```
|
348
352
|
|
353
|
+
### Converting CSV to object
|
354
|
+
|
355
|
+
CSV represents a flat data structure, so you can't map properties to complex types directly,
|
356
|
+
but you can use methods to map properties to complex types
|
357
|
+
(see [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
|
358
|
+
section).
|
359
|
+
|
360
|
+
`.from_csv` method allways returns an array of records.
|
361
|
+
|
362
|
+
```ruby
|
363
|
+
people = Person.from_csv(<<~DATA)
|
364
|
+
John,Doe,50,false
|
365
|
+
DATA
|
366
|
+
```
|
367
|
+
|
368
|
+
### Converting object to CSV
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
people[0].to_csv # or Person.to_csv(people) if you want to convert a collection
|
372
|
+
|
373
|
+
# =>
|
374
|
+
#
|
375
|
+
# John,Doe,50,false
|
376
|
+
```
|
377
|
+
|
378
|
+
### Converting collections
|
379
|
+
|
380
|
+
Shale allows converting collections for formats that support it (JSON, YAML and CSV).
|
381
|
+
To convert Ruby array to JSON:
|
382
|
+
|
383
|
+
```ruby
|
384
|
+
person1 = Person.new(name: 'John Doe')
|
385
|
+
person2 = Person.new(name: 'Joe Sixpack')
|
386
|
+
|
387
|
+
Person.to_json([person1, person2], pretty: true)
|
388
|
+
# or Person.to_yaml([person1, person2])
|
389
|
+
# or Person.to_csv([person1, person2])
|
390
|
+
|
391
|
+
# =>
|
392
|
+
#
|
393
|
+
# [
|
394
|
+
# { "name": "John Doe" },
|
395
|
+
# { "name": "Joe Sixpack" }
|
396
|
+
# ]
|
397
|
+
```
|
398
|
+
|
399
|
+
To convert JSON array to Ruby:
|
400
|
+
|
401
|
+
```ruby
|
402
|
+
Person.from_json(<<~JSON)
|
403
|
+
[
|
404
|
+
{ "name": "John Doe" },
|
405
|
+
{ "name": "Joe Sixpack" }
|
406
|
+
]
|
407
|
+
JSON
|
408
|
+
|
409
|
+
# =>
|
410
|
+
#
|
411
|
+
# [
|
412
|
+
# #<Person:0x00000001033dbce8 @name="John Doe">,
|
413
|
+
# #<Person:0x00000001033db4c8 @name="Joe Sixpack">
|
414
|
+
# ]
|
415
|
+
```
|
416
|
+
|
349
417
|
### Mapping JSON keys to object attributes
|
350
418
|
|
351
419
|
By default keys are named the same as attributes. To use custom keys use:
|
@@ -392,6 +460,24 @@ class Person < Shale::Mapper
|
|
392
460
|
end
|
393
461
|
```
|
394
462
|
|
463
|
+
### Mapping CSV columns to object attributes
|
464
|
+
|
465
|
+
For CSV the order of mapping matters, the first argument in the `map` method is only
|
466
|
+
used as a label in header row. So, in the example below the first column will be mapped
|
467
|
+
to `:first_name` attribute and the second column to `:last_name`.
|
468
|
+
|
469
|
+
```ruby
|
470
|
+
class Person < Shale::Mapper
|
471
|
+
attribute :first_name, Shale::Type::String
|
472
|
+
attribute :last_name, Shale::Type::String
|
473
|
+
|
474
|
+
csv do
|
475
|
+
map 'firstName', to: :first_name
|
476
|
+
map 'lastName', to: :last_name
|
477
|
+
end
|
478
|
+
end
|
479
|
+
```
|
480
|
+
|
395
481
|
### Mapping Hash keys to object attributes
|
396
482
|
|
397
483
|
```ruby
|
@@ -561,8 +647,9 @@ DATA
|
|
561
647
|
|
562
648
|
### Rendering nil values
|
563
649
|
|
564
|
-
|
565
|
-
by using `render_nil: true` on a mapping.
|
650
|
+
For JSON, YAML, TOML and XML by default, elements with `nil` value are not rendered.
|
651
|
+
You can change this behavior by using `render_nil: true` on a mapping.
|
652
|
+
For CSV the default is to render `nil` elements.
|
566
653
|
|
567
654
|
```ruby
|
568
655
|
class Person < Shale::Mapper
|
@@ -729,6 +816,55 @@ end
|
|
729
816
|
Person.new(password: 'secret').to_json(context: current_user)
|
730
817
|
```
|
731
818
|
|
819
|
+
If you want to work on multiple elements at a time you can group them using `group` block:
|
820
|
+
|
821
|
+
```ruby
|
822
|
+
class Person < Shale::Mapper
|
823
|
+
attribute :name, Shale::Type::String
|
824
|
+
|
825
|
+
json do
|
826
|
+
group from: :name_from_json, to: :name_to_json do
|
827
|
+
map 'first_name'
|
828
|
+
map 'last_name'
|
829
|
+
end
|
830
|
+
end
|
831
|
+
|
832
|
+
xml do
|
833
|
+
group from: :name_from_xml, to: :name_to_xml do
|
834
|
+
map_content
|
835
|
+
map_element 'first_name'
|
836
|
+
map_attribute 'last_name'
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
def name_from_json(model, value)
|
841
|
+
model.name = "#{value['first_name']} #{value['last_name']}"
|
842
|
+
end
|
843
|
+
|
844
|
+
def name_to_json(model, doc)
|
845
|
+
doc['first_name'] = model.name.split(' ')[0]
|
846
|
+
doc['last_name'] = model.name.split(' ')[1]
|
847
|
+
end
|
848
|
+
|
849
|
+
def name_from_xml(model, value)
|
850
|
+
# value => { content: ..., attributes: {}, elements: {} }
|
851
|
+
end
|
852
|
+
|
853
|
+
def name_to_xml(model, element, doc)
|
854
|
+
# ...
|
855
|
+
end
|
856
|
+
end
|
857
|
+
|
858
|
+
Person.from_json(<<~DATA)
|
859
|
+
{
|
860
|
+
"first_name": "John",
|
861
|
+
"last_name": "Doe"
|
862
|
+
}
|
863
|
+
DATA
|
864
|
+
|
865
|
+
# => #<Person:0x00007f9bc3086d60 @name="John Doe">
|
866
|
+
```
|
867
|
+
|
732
868
|
### Additional options
|
733
869
|
|
734
870
|
You can control which attributes to render and parse by
|
@@ -804,19 +940,52 @@ person.to_json(pretty: true)
|
|
804
940
|
# }
|
805
941
|
```
|
806
942
|
|
807
|
-
You can also add an XML declaration by passing `declaration: true`
|
943
|
+
You can also add an XML declaration by passing `declaration: true` and `encoding: true`
|
944
|
+
or if you want to spcify version: `declaration: '1.1'` and `encoding: 'ASCII'` to `#to_xml`
|
808
945
|
|
809
946
|
```ruby
|
810
|
-
person.to_xml(pretty: true, declaration: true)
|
947
|
+
person.to_xml(pretty: true, declaration: true, encoding: true)
|
811
948
|
|
812
949
|
# =>
|
813
950
|
#
|
814
|
-
# <?xml version="1.0"?>
|
951
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
815
952
|
# <Person>
|
816
953
|
# <Address city="London"/>
|
817
954
|
# </Person>
|
818
955
|
```
|
819
956
|
|
957
|
+
For CSV you can pass `headers: true` to indicate that the first row contains column
|
958
|
+
names and shouldn't be included in the returned collection. It also accepts all the options that
|
959
|
+
[CSV parser](https://ruby-doc.org/stdlib-3.1.2/libdoc/csv/rdoc/CSV.html#class-CSV-label-Options) accepts.
|
960
|
+
|
961
|
+
```ruby
|
962
|
+
class Person
|
963
|
+
attribute :first_name, Shale::Type::String
|
964
|
+
attribute :last_name, Shale::Type::String
|
965
|
+
end
|
966
|
+
|
967
|
+
people = Person.from_csv(<<~DATA, headers: true, col_sep: '|')
|
968
|
+
first_name|last_name
|
969
|
+
John|Doe
|
970
|
+
James|Sixpack
|
971
|
+
DATA
|
972
|
+
|
973
|
+
# =>
|
974
|
+
#
|
975
|
+
# [
|
976
|
+
# #<Person:0x0000000113d7a488 @first_name="John", @last_name="Doe">,
|
977
|
+
# #<Person:0x0000000113d7a488 @first_name="James", @last_name="Sixpack">
|
978
|
+
# ]
|
979
|
+
|
980
|
+
Person.to_csv(people, headers: true, col_sep: '|')
|
981
|
+
|
982
|
+
# =>
|
983
|
+
#
|
984
|
+
# first_name|last_name
|
985
|
+
# John|Doe
|
986
|
+
# James|Sixpack
|
987
|
+
```
|
988
|
+
|
820
989
|
### Using custom models
|
821
990
|
|
822
991
|
By default Shale combines mapper and model into one class. If you want to use your own classes
|
@@ -906,10 +1075,10 @@ end
|
|
906
1075
|
### Adapters
|
907
1076
|
|
908
1077
|
Shale uses adapters for parsing and generating documents.
|
909
|
-
By default Ruby's standard JSON, YAML parsers are used for handling JSON
|
1078
|
+
By default Ruby's standard JSON, YAML, CSV parsers are used for handling JSON YAML, CSV documents.
|
910
1079
|
|
911
|
-
You can change it by providing your own adapter. For JSON, YAML and
|
912
|
-
`.load` and `.dump` class methods.
|
1080
|
+
You can change it by providing your own adapter. For JSON, YAML, TOML and CSV adapter must
|
1081
|
+
implement `.load` and `.dump` class methods.
|
913
1082
|
|
914
1083
|
```ruby
|
915
1084
|
require 'shale'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
module Shale
|
6
|
+
module Adapter
|
7
|
+
# CSV adapter
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
class CSV
|
11
|
+
# Parse CSV into Array<Hash<String, any>>
|
12
|
+
#
|
13
|
+
# @param [String] csv CSV document
|
14
|
+
# @param [Array<String>] headers
|
15
|
+
# @param [Hash] options
|
16
|
+
#
|
17
|
+
# @return [Array<Hash<String, any>>]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
def self.load(csv, headers:, **options)
|
21
|
+
::CSV.parse(csv, headers: headers, **options).map(&:to_h)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Serialize Array<Hash<String, any>> into CSV
|
25
|
+
#
|
26
|
+
# @param [Array<Hash<String, any>>] obj Array<Hash<String, any>> object
|
27
|
+
# @param [Array<String>] headers
|
28
|
+
# @param [Hash] options
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def self.dump(obj, headers:, **options)
|
34
|
+
::CSV.generate(**options) do |csv|
|
35
|
+
obj.each do |row|
|
36
|
+
values = []
|
37
|
+
|
38
|
+
headers.each do |header|
|
39
|
+
values << row[header] if row.key?(header)
|
40
|
+
end
|
41
|
+
|
42
|
+
csv << values
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -9,9 +9,14 @@ module Shale
|
|
9
9
|
class Document
|
10
10
|
# Initialize object
|
11
11
|
#
|
12
|
+
# @param [String, nil] version
|
13
|
+
#
|
12
14
|
# @api private
|
13
|
-
def initialize
|
14
|
-
|
15
|
+
def initialize(version = nil)
|
16
|
+
ver = nil
|
17
|
+
ver = version if version.is_a?(String)
|
18
|
+
|
19
|
+
@doc = ::Nokogiri::XML::Document.new(ver)
|
15
20
|
@namespaces = {}
|
16
21
|
end
|
17
22
|
|
@@ -37,12 +37,13 @@ module Shale
|
|
37
37
|
#
|
38
38
|
# @param [::Nokogiri::XML::Document] doc Nokogiri document
|
39
39
|
# @param [true, false] pretty
|
40
|
-
# @param [true, false] declaration
|
40
|
+
# @param [true, false, String] declaration
|
41
|
+
# @param [true, false, String] encoding
|
41
42
|
#
|
42
43
|
# @return [String]
|
43
44
|
#
|
44
45
|
# @api private
|
45
|
-
def self.dump(doc, pretty: false, declaration: false)
|
46
|
+
def self.dump(doc, pretty: false, declaration: false, encoding: false)
|
46
47
|
save_with = ::Nokogiri::XML::Node::SaveOptions::AS_XML
|
47
48
|
|
48
49
|
if pretty
|
@@ -53,6 +54,10 @@ module Shale
|
|
53
54
|
save_with |= ::Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
|
54
55
|
end
|
55
56
|
|
57
|
+
if encoding
|
58
|
+
doc.encoding = encoding == true ? 'UTF-8' : encoding
|
59
|
+
end
|
60
|
+
|
56
61
|
result = doc.to_xml(save_with: save_with)
|
57
62
|
|
58
63
|
unless pretty
|
@@ -64,9 +69,11 @@ module Shale
|
|
64
69
|
|
65
70
|
# Create Shale::Adapter::Nokogiri::Document instance
|
66
71
|
#
|
72
|
+
# @param [true, false, String, nil] declaration
|
73
|
+
#
|
67
74
|
# @api private
|
68
|
-
def self.create_document
|
69
|
-
Document.new
|
75
|
+
def self.create_document(version = nil)
|
76
|
+
Document.new(version)
|
70
77
|
end
|
71
78
|
end
|
72
79
|
end
|
data/lib/shale/adapter/ox.rb
CHANGED
@@ -31,12 +31,13 @@ module Shale
|
|
31
31
|
#
|
32
32
|
# @param [::Ox::Document, ::Ox::Element] doc Ox document
|
33
33
|
# @param [true, false] pretty
|
34
|
-
# @param [true, false] declaration
|
34
|
+
# @param [true, false, String] declaration
|
35
|
+
# @param [true, false, String] encoding
|
35
36
|
#
|
36
37
|
# @return [String]
|
37
38
|
#
|
38
39
|
# @api private
|
39
|
-
def self.dump(doc, pretty: false, declaration: false)
|
40
|
+
def self.dump(doc, pretty: false, declaration: false, encoding: false)
|
40
41
|
opts = { indent: -1, with_xml: false }
|
41
42
|
|
42
43
|
if pretty
|
@@ -44,7 +45,12 @@ module Shale
|
|
44
45
|
end
|
45
46
|
|
46
47
|
if declaration
|
47
|
-
doc[:version] = '1.0'
|
48
|
+
doc[:version] = declaration == true ? '1.0' : declaration
|
49
|
+
|
50
|
+
if encoding
|
51
|
+
doc[:encoding] = encoding == true ? 'UTF-8' : encoding
|
52
|
+
end
|
53
|
+
|
48
54
|
opts[:with_xml] = true
|
49
55
|
end
|
50
56
|
|
@@ -54,7 +60,7 @@ module Shale
|
|
54
60
|
# Create Shale::Adapter::Ox::Document instance
|
55
61
|
#
|
56
62
|
# @api private
|
57
|
-
def self.create_document
|
63
|
+
def self.create_document(_version = nil)
|
58
64
|
Document.new
|
59
65
|
end
|
60
66
|
end
|
data/lib/shale/adapter/rexml.rb
CHANGED
@@ -32,14 +32,28 @@ module Shale
|
|
32
32
|
#
|
33
33
|
# @param [::REXML::Document] doc REXML document
|
34
34
|
# @param [true, false] pretty
|
35
|
-
# @param [true, false] declaration
|
35
|
+
# @param [true, false, String] declaration
|
36
|
+
# @param [true, false, String] encoding
|
36
37
|
#
|
37
38
|
# @return [String]
|
38
39
|
#
|
39
40
|
# @api private
|
40
|
-
def self.dump(doc, pretty: false, declaration: false)
|
41
|
+
def self.dump(doc, pretty: false, declaration: false, encoding: false)
|
41
42
|
if declaration
|
42
|
-
|
43
|
+
ver = nil
|
44
|
+
enc = nil
|
45
|
+
|
46
|
+
if declaration.is_a?(String)
|
47
|
+
ver = declaration
|
48
|
+
end
|
49
|
+
|
50
|
+
if encoding == true
|
51
|
+
enc = 'UTF-8'
|
52
|
+
else
|
53
|
+
enc = encoding || nil
|
54
|
+
end
|
55
|
+
|
56
|
+
doc.add(::REXML::XMLDecl.new(ver, enc))
|
43
57
|
end
|
44
58
|
|
45
59
|
io = StringIO.new
|
@@ -58,7 +72,7 @@ module Shale
|
|
58
72
|
# Create Shale::Adapter::REXML::Document instance
|
59
73
|
#
|
60
74
|
# @api private
|
61
|
-
def self.create_document
|
75
|
+
def self.create_document(_version = nil)
|
62
76
|
Document.new
|
63
77
|
end
|
64
78
|
end
|
data/lib/shale/mapper.rb
CHANGED
@@ -49,6 +49,7 @@ module Shale
|
|
49
49
|
@json_mapping = Mapping::Dict.new
|
50
50
|
@yaml_mapping = Mapping::Dict.new
|
51
51
|
@toml_mapping = Mapping::Dict.new
|
52
|
+
@csv_mapping = Mapping::Dict.new(render_nil_default: true)
|
52
53
|
@xml_mapping = Mapping::Xml.new
|
53
54
|
|
54
55
|
class << self
|
@@ -87,6 +88,13 @@ module Shale
|
|
87
88
|
# @api public
|
88
89
|
attr_reader :toml_mapping
|
89
90
|
|
91
|
+
# Return CSV mapping object
|
92
|
+
#
|
93
|
+
# @return [Shale::Mapping::Dict]
|
94
|
+
#
|
95
|
+
# @api public
|
96
|
+
attr_reader :csv_mapping
|
97
|
+
|
90
98
|
# Return XML mapping object
|
91
99
|
#
|
92
100
|
# @return [Shale::Mapping::XML]
|
@@ -98,6 +106,10 @@ module Shale
|
|
98
106
|
def inherited(subclass)
|
99
107
|
super
|
100
108
|
|
109
|
+
attributes_module = Module.new
|
110
|
+
subclass.instance_variable_set('@attributes_module', attributes_module)
|
111
|
+
subclass.include(attributes_module)
|
112
|
+
|
101
113
|
subclass.instance_variable_set('@model', subclass)
|
102
114
|
subclass.instance_variable_set('@attributes', @attributes.dup)
|
103
115
|
|
@@ -105,12 +117,14 @@ module Shale
|
|
105
117
|
subclass.instance_variable_set('@__json_mapping_init', @json_mapping.dup)
|
106
118
|
subclass.instance_variable_set('@__yaml_mapping_init', @yaml_mapping.dup)
|
107
119
|
subclass.instance_variable_set('@__toml_mapping_init', @toml_mapping.dup)
|
120
|
+
subclass.instance_variable_set('@__csv_mapping_init', @csv_mapping.dup)
|
108
121
|
subclass.instance_variable_set('@__xml_mapping_init', @xml_mapping.dup)
|
109
122
|
|
110
123
|
subclass.instance_variable_set('@hash_mapping', @hash_mapping.dup)
|
111
124
|
subclass.instance_variable_set('@json_mapping', @json_mapping.dup)
|
112
125
|
subclass.instance_variable_set('@yaml_mapping', @yaml_mapping.dup)
|
113
126
|
subclass.instance_variable_set('@toml_mapping', @toml_mapping.dup)
|
127
|
+
subclass.instance_variable_set('@csv_mapping', @csv_mapping.dup)
|
114
128
|
|
115
129
|
xml_mapping = @xml_mapping.dup
|
116
130
|
xml_mapping.root(Utils.underscore(subclass.name || ''))
|
@@ -169,9 +183,10 @@ module Shale
|
|
169
183
|
@json_mapping.map(name.to_s, to: name) unless @json_mapping.finalized?
|
170
184
|
@yaml_mapping.map(name.to_s, to: name) unless @yaml_mapping.finalized?
|
171
185
|
@toml_mapping.map(name.to_s, to: name) unless @toml_mapping.finalized?
|
186
|
+
@csv_mapping.map(name.to_s, to: name) unless @csv_mapping.finalized?
|
172
187
|
@xml_mapping.map_element(name.to_s, to: name) unless @xml_mapping.finalized?
|
173
188
|
|
174
|
-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
189
|
+
@attributes_module.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
175
190
|
attr_reader :#{name}
|
176
191
|
|
177
192
|
def #{name}=(val)
|
@@ -276,6 +291,30 @@ module Shale
|
|
276
291
|
@toml_mapping.instance_eval(&block)
|
277
292
|
end
|
278
293
|
|
294
|
+
# Define CSV mapping
|
295
|
+
#
|
296
|
+
# @param [Proc] block
|
297
|
+
#
|
298
|
+
# @example
|
299
|
+
# calss Person < Shale::Mapper
|
300
|
+
# attribute :first_name, Shale::Type::String
|
301
|
+
# attribute :last_name, Shale::Type::String
|
302
|
+
# attribute :age, Shale::Type::Integer
|
303
|
+
#
|
304
|
+
# csv do
|
305
|
+
# map 'first_name', to: :first_name
|
306
|
+
# map 'last_name', to: :last_name
|
307
|
+
# map 'age', to: :age
|
308
|
+
# end
|
309
|
+
# end
|
310
|
+
#
|
311
|
+
# @api public
|
312
|
+
def csv(&block)
|
313
|
+
@csv_mapping = @__csv_mapping_init.dup
|
314
|
+
@csv_mapping.finalize!
|
315
|
+
@csv_mapping.instance_eval(&block)
|
316
|
+
end
|
317
|
+
|
279
318
|
# Define XML mapping
|
280
319
|
#
|
281
320
|
# @param [Proc] block
|
@@ -35,17 +35,26 @@ module Shale
|
|
35
35
|
# @api private
|
36
36
|
attr_reader :method_to
|
37
37
|
|
38
|
+
# Return group name
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
attr_reader :group
|
44
|
+
|
38
45
|
# Initialize instance
|
39
46
|
#
|
40
47
|
# @param [String] name
|
41
48
|
# @param [Symbol, nil] attribute
|
42
49
|
# @param [Hash, nil] methods
|
50
|
+
# @param [String, nil] group
|
43
51
|
# @param [true, false] render_nil
|
44
52
|
#
|
45
53
|
# @api private
|
46
|
-
def initialize(name:, attribute:, methods:, render_nil:)
|
54
|
+
def initialize(name:, attribute:, methods:, group:, render_nil:)
|
47
55
|
@name = name
|
48
56
|
@attribute = attribute
|
57
|
+
@group = group
|
49
58
|
@render_nil = render_nil
|
50
59
|
|
51
60
|
if methods
|
@@ -28,13 +28,21 @@ module Shale
|
|
28
28
|
# @param [String] name
|
29
29
|
# @param [Symbol, String] attribute
|
30
30
|
# @param [Hash, nil] methods
|
31
|
+
# @param [String, nil] group
|
31
32
|
# @param [Shale::Mapping::XmlNamespace] namespace
|
32
33
|
# @param [true, false] cdata
|
33
34
|
# @param [true, false] render_nil
|
34
35
|
#
|
35
36
|
# @api private
|
36
|
-
def initialize(name:, attribute:, methods:, namespace:, cdata:, render_nil:)
|
37
|
-
super(
|
37
|
+
def initialize(name:, attribute:, methods:, group:, namespace:, cdata:, render_nil:)
|
38
|
+
super(
|
39
|
+
name: name,
|
40
|
+
attribute: attribute,
|
41
|
+
methods: methods,
|
42
|
+
group: group,
|
43
|
+
render_nil: render_nil
|
44
|
+
)
|
45
|
+
|
38
46
|
@namespace = namespace
|
39
47
|
@cdata = cdata
|
40
48
|
end
|
@@ -47,6 +55,15 @@ module Shale
|
|
47
55
|
def prefixed_name
|
48
56
|
[namespace.prefix, name].compact.join(':')
|
49
57
|
end
|
58
|
+
|
59
|
+
# Return name with XML namespace
|
60
|
+
#
|
61
|
+
# @return [String]
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
def namespaced_name
|
65
|
+
[namespace.name, name].compact.join(':')
|
66
|
+
end
|
50
67
|
end
|
51
68
|
end
|
52
69
|
end
|