shale 1.0.0 → 1.2.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 +20 -0
- data/README.md +263 -69
- data/lib/shale/adapter/json.rb +10 -7
- data/lib/shale/adapter/nokogiri.rb +1 -1
- data/lib/shale/adapter/ox.rb +2 -1
- data/lib/shale/adapter/toml_rb.rb +5 -3
- data/lib/shale/adapter/tomlib.rb +36 -0
- data/lib/shale/error.rb +26 -1
- data/lib/shale/mapper.rb +36 -30
- data/lib/shale/mapping/descriptor/dict.rb +10 -1
- data/lib/shale/mapping/dict.rb +4 -3
- data/lib/shale/mapping/dict_base.rb +29 -2
- data/lib/shale/schema/json_generator/base.rb +9 -3
- data/lib/shale/schema/json_generator/boolean.rb +2 -1
- data/lib/shale/schema/json_generator/collection.rb +18 -2
- data/lib/shale/schema/json_generator/date.rb +3 -1
- data/lib/shale/schema/json_generator/float.rb +7 -1
- data/lib/shale/schema/json_generator/integer.rb +7 -1
- data/lib/shale/schema/json_generator/object.rb +12 -2
- data/lib/shale/schema/json_generator/string.rb +6 -1
- data/lib/shale/schema/json_generator/time.rb +3 -1
- data/lib/shale/schema/json_generator/value.rb +2 -1
- data/lib/shale/schema/json_generator.rb +7 -3
- data/lib/shale/schema/xml_compiler.rb +12 -12
- data/lib/shale/type/boolean.rb +2 -0
- data/lib/shale/type/complex.rb +43 -18
- data/lib/shale/type/date.rb +2 -0
- data/lib/shale/type/float.rb +2 -0
- data/lib/shale/type/integer.rb +2 -0
- data/lib/shale/type/string.rb +2 -0
- data/lib/shale/type/time.rb +2 -0
- data/lib/shale/type.rb +56 -0
- data/lib/shale/utils.rb +1 -1
- data/lib/shale/version.rb +1 -1
- data/lib/shale.rb +18 -20
- data/shale.gemspec +3 -1
- metadata +21 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81b22181e1c63b2757fdd137f09a185caf894de6d43c108119c18c9260b48afd
|
4
|
+
data.tar.gz: 065bc2d6f8a6eec466b52574ed38846dc0b4e0315ba9b83fc0d24ed75066ef07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b106ac74372bc089093ee8c12238b48505cff4d318967e2760ef2842e9a783125227177fd5f2cb47b27872adc7cbbf0686226934132b5c8f346c71b92159c8a
|
7
|
+
data.tar.gz: dcb0088d6f700f1654313a72156e9d1e4cd0c1b75b99a82cea17e12af96ced1407e358b1d0cc52e7e3f0a1c46cb19d702b3a49628a0da67e521a20906e006a6c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
## [1.2.0] - 2024-10-31
|
2
|
+
|
3
|
+
### Added
|
4
|
+
- Allow to pass adapter specific options
|
5
|
+
- Allow to pass `additional_properties` option to JSON Schema generator
|
6
|
+
- Allow to pass `description` option to JSON Schema generator
|
7
|
+
- Support for symbol type aliases in attribute mappings
|
8
|
+
|
9
|
+
## [1.1.0] - 2024-02-17
|
10
|
+
|
11
|
+
### Added
|
12
|
+
- [bkjohnson] Add support for JSON Schema validation keywords (#29)
|
13
|
+
- Add support for Ruby 3.3
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
- Drop support for Ruby 2.6 and Ruby 2.7
|
17
|
+
|
18
|
+
### Fixed
|
19
|
+
- Fix Ox adapter incorrectly handling documents with XML declaration
|
20
|
+
|
1
21
|
## [1.0.0] - 2023-07-15
|
2
22
|
|
3
23
|
### Added
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@ Documentation with interactive examples is available at [Shale website](https://
|
|
17
17
|
|
18
18
|
## Installation
|
19
19
|
|
20
|
-
Shale supports Ruby (MRI)
|
20
|
+
Shale supports Ruby (MRI) 3.0+
|
21
21
|
|
22
22
|
Add this line to your application's Gemfile:
|
23
23
|
|
@@ -65,6 +65,7 @@ $ gem install shale
|
|
65
65
|
* [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
|
66
66
|
* [Delegating fields to child attributes](#delegating-fields-to-child-attributes)
|
67
67
|
* [Additional options](#additional-options)
|
68
|
+
* [Overriding attribute methods](#overriding-attribute-methods)
|
68
69
|
* [Using custom models](#using-custom-models)
|
69
70
|
* [Supported types](#supported-types)
|
70
71
|
* [Writing your own type](#writing-your-own-type)
|
@@ -82,17 +83,17 @@ $ gem install shale
|
|
82
83
|
require 'shale'
|
83
84
|
|
84
85
|
class Address < Shale::Mapper
|
85
|
-
attribute :city,
|
86
|
-
attribute :street,
|
87
|
-
attribute :zip,
|
86
|
+
attribute :city, :string
|
87
|
+
attribute :street, :string
|
88
|
+
attribute :zip, :string
|
88
89
|
end
|
89
90
|
|
90
91
|
class Person < Shale::Mapper
|
91
|
-
attribute :first_name,
|
92
|
-
attribute :last_name,
|
93
|
-
attribute :age,
|
94
|
-
attribute :married,
|
95
|
-
attribute :hobbies,
|
92
|
+
attribute :first_name, :string
|
93
|
+
attribute :last_name, :string
|
94
|
+
attribute :age, :integer
|
95
|
+
attribute :married, :boolean, default: -> { false }
|
96
|
+
attribute :hobbies, :string, collection: true
|
96
97
|
attribute :address, Address
|
97
98
|
end
|
98
99
|
```
|
@@ -208,8 +209,8 @@ person.to_yaml
|
|
208
209
|
### Converting TOML to object
|
209
210
|
|
210
211
|
To use TOML with Shale you have to set adapter you want to use.
|
211
|
-
|
212
|
-
|
212
|
+
It comes with adapters for [Tomlib](https://github.com/kgiszczak/tomlib) and
|
213
|
+
[toml-rb](https://github.com/emancu/toml-rb).
|
213
214
|
For details see [Adapters](#adapters) section.
|
214
215
|
|
215
216
|
To set it, first make sure Tomlib gem is installed:
|
@@ -221,8 +222,8 @@ $ gem install tomlib
|
|
221
222
|
then setup adapter:
|
222
223
|
|
223
224
|
```ruby
|
224
|
-
require 'tomlib'
|
225
|
-
Shale.toml_adapter = Tomlib
|
225
|
+
require 'sahle/adapter/tomlib'
|
226
|
+
Shale.toml_adapter = Shale::Adapter::Tomlib
|
226
227
|
|
227
228
|
# Alternatively if you'd like to use toml-rb, use:
|
228
229
|
require 'shale/adapter/toml_rb'
|
@@ -353,6 +354,25 @@ person.to_xml
|
|
353
354
|
|
354
355
|
### Converting CSV to object
|
355
356
|
|
357
|
+
To use CSV with Shale you have to set adapter.
|
358
|
+
Shale comes with adapter for [csv](https://github.com/ruby/csv).
|
359
|
+
For details see [Adapters](#adapters) section.
|
360
|
+
|
361
|
+
To set it, first make sure CSV gem is installed:
|
362
|
+
|
363
|
+
```
|
364
|
+
$ gem install csv
|
365
|
+
```
|
366
|
+
|
367
|
+
then setup adapter:
|
368
|
+
|
369
|
+
```ruby
|
370
|
+
require 'shale/adapter/csv'
|
371
|
+
Shale.csv_adapter = Shale::Adapter::CSV
|
372
|
+
```
|
373
|
+
|
374
|
+
Now you can use CSV with Shale.
|
375
|
+
|
356
376
|
CSV represents a flat data structure, so you can't map properties to complex types directly,
|
357
377
|
but you can use methods to map properties to complex types
|
358
378
|
(see [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
|
@@ -423,8 +443,8 @@ By default keys are named the same as attributes. To use custom keys use:
|
|
423
443
|
|
424
444
|
```ruby
|
425
445
|
class Person < Shale::Mapper
|
426
|
-
attribute :first_name,
|
427
|
-
attribute :last_name,
|
446
|
+
attribute :first_name, :string
|
447
|
+
attribute :last_name, :string
|
428
448
|
|
429
449
|
json do
|
430
450
|
map 'firstName', to: :first_name
|
@@ -437,8 +457,8 @@ end
|
|
437
457
|
|
438
458
|
```ruby
|
439
459
|
class Person < Shale::Mapper
|
440
|
-
attribute :first_name,
|
441
|
-
attribute :last_name,
|
460
|
+
attribute :first_name, :string
|
461
|
+
attribute :last_name, :string
|
442
462
|
|
443
463
|
yaml do
|
444
464
|
map 'firstName', to: :first_name
|
@@ -451,8 +471,8 @@ end
|
|
451
471
|
|
452
472
|
```ruby
|
453
473
|
class Person < Shale::Mapper
|
454
|
-
attribute :first_name,
|
455
|
-
attribute :last_name,
|
474
|
+
attribute :first_name, :string
|
475
|
+
attribute :last_name, :string
|
456
476
|
|
457
477
|
toml do
|
458
478
|
map 'firstName', to: :first_name
|
@@ -469,8 +489,8 @@ to `:first_name` attribute and the second column to `:last_name`.
|
|
469
489
|
|
470
490
|
```ruby
|
471
491
|
class Person < Shale::Mapper
|
472
|
-
attribute :first_name,
|
473
|
-
attribute :last_name,
|
492
|
+
attribute :first_name, :string
|
493
|
+
attribute :last_name, :string
|
474
494
|
|
475
495
|
csv do
|
476
496
|
map 'firstName', to: :first_name
|
@@ -483,8 +503,8 @@ end
|
|
483
503
|
|
484
504
|
```ruby
|
485
505
|
class Person < Shale::Mapper
|
486
|
-
attribute :first_name,
|
487
|
-
attribute :last_name,
|
506
|
+
attribute :first_name, :string
|
507
|
+
attribute :last_name, :string
|
488
508
|
|
489
509
|
hsh do
|
490
510
|
map 'firstName', to: :first_name
|
@@ -499,9 +519,9 @@ XML is more complicated format than JSON or YAML. To map elements, attributes an
|
|
499
519
|
|
500
520
|
```ruby
|
501
521
|
class Address < Shale::Mapper
|
502
|
-
attribute :street,
|
503
|
-
attribute :city,
|
504
|
-
attribute :zip,
|
522
|
+
attribute :street, :string
|
523
|
+
attribute :city, :string
|
524
|
+
attribute :zip, :string
|
505
525
|
|
506
526
|
xml do
|
507
527
|
map_content to: :street
|
@@ -511,10 +531,10 @@ class Address < Shale::Mapper
|
|
511
531
|
end
|
512
532
|
|
513
533
|
class Person < Shale::Mapper
|
514
|
-
attribute :first_name,
|
515
|
-
attribute :last_name,
|
516
|
-
attribute :age,
|
517
|
-
attribute :hobbies,
|
534
|
+
attribute :first_name, :string
|
535
|
+
attribute :last_name, :string
|
536
|
+
attribute :age, :integer
|
537
|
+
attribute :hobbies, :string, collection: true
|
518
538
|
attribute :address, Address
|
519
539
|
|
520
540
|
xml do
|
@@ -553,7 +573,7 @@ You can use `cdata: true` option on `map_element` and `map_content` to handle CD
|
|
553
573
|
|
554
574
|
```ruby
|
555
575
|
class Address < Shale::Mapper
|
556
|
-
attribute :content,
|
576
|
+
attribute :content, :string
|
557
577
|
|
558
578
|
xml do
|
559
579
|
map_content to: :content, cdata: true
|
@@ -561,7 +581,7 @@ class Address < Shale::Mapper
|
|
561
581
|
end
|
562
582
|
|
563
583
|
class Person < Shale::Mapper
|
564
|
-
attribute :first_name,
|
584
|
+
attribute :first_name, :string
|
565
585
|
attribute :address, Address
|
566
586
|
|
567
587
|
xml do
|
@@ -587,9 +607,9 @@ To map namespaced elements and attributes use `namespace` and `prefix` propertie
|
|
587
607
|
|
588
608
|
```ruby
|
589
609
|
class Person < Shale::Mapper
|
590
|
-
attribute :first_name,
|
591
|
-
attribute :last_name,
|
592
|
-
attribute :age,
|
610
|
+
attribute :first_name, :string
|
611
|
+
attribute :last_name, :string
|
612
|
+
attribute :age, :integer
|
593
613
|
|
594
614
|
xml do
|
595
615
|
root 'person'
|
@@ -614,11 +634,11 @@ explicitly declare it on `map_attribute`).
|
|
614
634
|
|
615
635
|
```ruby
|
616
636
|
class Person < Shale::Mapper
|
617
|
-
attribute :first_name,
|
618
|
-
attribute :middle_name,
|
619
|
-
attribute :last_name,
|
620
|
-
attribute :age,
|
621
|
-
attribute :hobby,
|
637
|
+
attribute :first_name, :string
|
638
|
+
attribute :middle_name, :string
|
639
|
+
attribute :last_name, :string
|
640
|
+
attribute :age, :integer
|
641
|
+
attribute :hobby, :string
|
622
642
|
|
623
643
|
xml do
|
624
644
|
root 'person'
|
@@ -654,9 +674,9 @@ For CSV the default is to render `nil` elements.
|
|
654
674
|
|
655
675
|
```ruby
|
656
676
|
class Person < Shale::Mapper
|
657
|
-
attribute :first_name,
|
658
|
-
attribute :last_name,
|
659
|
-
attribute :age,
|
677
|
+
attribute :first_name, :string
|
678
|
+
attribute :last_name, :string
|
679
|
+
attribute :age, :integer
|
660
680
|
|
661
681
|
json do
|
662
682
|
map 'first_name', to: :first_name, render_nil: true
|
@@ -704,9 +724,9 @@ class Base < Shale::Mapper
|
|
704
724
|
end
|
705
725
|
|
706
726
|
class Person < Base
|
707
|
-
attribute :first_name,
|
708
|
-
attribute :last_name,
|
709
|
-
attribute :age,
|
727
|
+
attribute :first_name, :string
|
728
|
+
attribute :last_name, :string
|
729
|
+
attribute :age, :integer
|
710
730
|
|
711
731
|
json do
|
712
732
|
# override default from Base class
|
@@ -723,8 +743,8 @@ end
|
|
723
743
|
|
724
744
|
```ruby
|
725
745
|
class Person < Base
|
726
|
-
attribute :first_name,
|
727
|
-
attribute :last_name,
|
746
|
+
attribute :first_name, :string
|
747
|
+
attribute :last_name, :string
|
728
748
|
|
729
749
|
json do
|
730
750
|
render_nil false
|
@@ -743,9 +763,9 @@ you can use methods to do so:
|
|
743
763
|
|
744
764
|
```ruby
|
745
765
|
class Person < Shale::Mapper
|
746
|
-
attribute :hobbies,
|
747
|
-
attribute :street,
|
748
|
-
attribute :city,
|
766
|
+
attribute :hobbies, :string, collection: true
|
767
|
+
attribute :street, :string
|
768
|
+
attribute :city, :string
|
749
769
|
|
750
770
|
json do
|
751
771
|
map 'hobbies', using: { from: :hobbies_from_json, to: :hobbies_to_json }
|
@@ -834,7 +854,7 @@ You can also pass a `context` object that will be available in extractor/generat
|
|
834
854
|
|
835
855
|
```ruby
|
836
856
|
class Person < Shale::Mapper
|
837
|
-
attribute :password,
|
857
|
+
attribute :password, :string
|
838
858
|
|
839
859
|
json do
|
840
860
|
map 'password', using: { from: :password_from_json, to: :password_to_json }
|
@@ -864,7 +884,7 @@ If you want to work on multiple elements at a time you can group them using `gro
|
|
864
884
|
|
865
885
|
```ruby
|
866
886
|
class Person < Shale::Mapper
|
867
|
-
attribute :name,
|
887
|
+
attribute :name, :string
|
868
888
|
|
869
889
|
json do
|
870
890
|
group from: :name_from_json, to: :name_to_json do
|
@@ -915,12 +935,12 @@ To delegate fields to child complex types you can use `receiver: :child` declara
|
|
915
935
|
|
916
936
|
```ruby
|
917
937
|
class Address < Shale::Mapper
|
918
|
-
attribute :city,
|
919
|
-
attribute :street,
|
938
|
+
attribute :city, :string
|
939
|
+
attribute :street, :string
|
920
940
|
end
|
921
941
|
|
922
942
|
class Person < Shale::Mapper
|
923
|
-
attribute :name,
|
943
|
+
attribute :name, :string
|
924
944
|
attribute :address, Address
|
925
945
|
|
926
946
|
json do
|
@@ -1040,8 +1060,8 @@ names and shouldn't be included in the returned collection. It also accepts all
|
|
1040
1060
|
|
1041
1061
|
```ruby
|
1042
1062
|
class Person
|
1043
|
-
attribute :first_name,
|
1044
|
-
attribute :last_name,
|
1063
|
+
attribute :first_name, :string
|
1064
|
+
attribute :last_name, :string
|
1045
1065
|
end
|
1046
1066
|
|
1047
1067
|
people = Person.from_csv(<<~DATA, headers: true, col_sep: '|')
|
@@ -1066,6 +1086,63 @@ Person.to_csv(people, headers: true, col_sep: '|')
|
|
1066
1086
|
# James|Sixpack
|
1067
1087
|
```
|
1068
1088
|
|
1089
|
+
Most adapters accept options specific to them. Eg. if you want to be able to work
|
1090
|
+
with NaN values in JSON:
|
1091
|
+
|
1092
|
+
```ruby
|
1093
|
+
class Person
|
1094
|
+
attribute :age, :float
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
person = Person.from_json('{"age": NaN}', allow_nan: true)
|
1098
|
+
|
1099
|
+
# =>
|
1100
|
+
#
|
1101
|
+
# #<Person:0x0000000113d7a488 @age=Float::NAN>
|
1102
|
+
|
1103
|
+
Person.to_json(person, allow_nan: true)
|
1104
|
+
|
1105
|
+
# =>
|
1106
|
+
#
|
1107
|
+
# {
|
1108
|
+
# "age": NaN
|
1109
|
+
# }
|
1110
|
+
```
|
1111
|
+
|
1112
|
+
### Overriding attribute methods
|
1113
|
+
|
1114
|
+
It's possible to override an attribute method to change its output:
|
1115
|
+
|
1116
|
+
```ruby
|
1117
|
+
class Person < Shale::Mapper
|
1118
|
+
attribute :gender, :string
|
1119
|
+
|
1120
|
+
def gender
|
1121
|
+
if super == 'm'
|
1122
|
+
'male'
|
1123
|
+
else
|
1124
|
+
'female'
|
1125
|
+
end
|
1126
|
+
end
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
puts Person.from_json('{"gender":"m"}')
|
1130
|
+
|
1131
|
+
# =>
|
1132
|
+
#
|
1133
|
+
# #<Person:0x00007f9bc3086d60
|
1134
|
+
# @gender="male">
|
1135
|
+
```
|
1136
|
+
|
1137
|
+
Be conscious that the original attribute value will be lost after its transformation though:
|
1138
|
+
|
1139
|
+
```ruby
|
1140
|
+
puts User.from_json('{"gender":"m"}').to_json
|
1141
|
+
# => {"gender":"male"}
|
1142
|
+
```
|
1143
|
+
|
1144
|
+
It'll no longer return gender `m`.
|
1145
|
+
|
1069
1146
|
### Using custom models
|
1070
1147
|
|
1071
1148
|
By default Shale combines mapper and model into one class. If you want to use your own classes
|
@@ -1083,15 +1160,15 @@ end
|
|
1083
1160
|
class AddressMapper < Shale::Mapper
|
1084
1161
|
model Address
|
1085
1162
|
|
1086
|
-
attribute :street,
|
1087
|
-
attribute :city,
|
1163
|
+
attribute :street, :string
|
1164
|
+
attribute :city, :string
|
1088
1165
|
end
|
1089
1166
|
|
1090
1167
|
class PersonMapper < Shale::Mapper
|
1091
1168
|
model Person
|
1092
1169
|
|
1093
|
-
attribute :first_name,
|
1094
|
-
attribute :last_name,
|
1170
|
+
attribute :first_name, :string
|
1171
|
+
attribute :last_name, :string
|
1095
1172
|
attribute :address, AddressMapper
|
1096
1173
|
end
|
1097
1174
|
|
@@ -1131,12 +1208,21 @@ PersonMapper.to_json(person, pretty: true)
|
|
1131
1208
|
|
1132
1209
|
Shale supports these types out of the box:
|
1133
1210
|
|
1134
|
-
- `Shale::Type::Boolean`
|
1135
|
-
- `Shale::Type::Date`
|
1136
|
-
- `Shale::Type::Float`
|
1137
|
-
- `Shale::Type::Integer`
|
1138
|
-
- `Shale::Type::String`
|
1139
|
-
- `Shale::Type::Time`
|
1211
|
+
- `:boolean` (`Shale::Type::Boolean`)
|
1212
|
+
- `:date` (`Shale::Type::Date`)
|
1213
|
+
- `:float` (`Shale::Type::Float`)
|
1214
|
+
- `:integer` (`Shale::Type::Integer`)
|
1215
|
+
- `:string` (`Shale::Type::String`)
|
1216
|
+
- `:time` (`Shale::Type::Time`)
|
1217
|
+
|
1218
|
+
The symbol type alias and the type class are interchangeable:
|
1219
|
+
|
1220
|
+
```ruby
|
1221
|
+
class Person < Shale::Mapper
|
1222
|
+
attribute :age, Shale::Type::Integer
|
1223
|
+
# attribute :age, :integer
|
1224
|
+
end
|
1225
|
+
```
|
1140
1226
|
|
1141
1227
|
### Writing your own type
|
1142
1228
|
|
@@ -1152,10 +1238,35 @@ class MyIntegerType < Shale::Type::Value
|
|
1152
1238
|
end
|
1153
1239
|
```
|
1154
1240
|
|
1241
|
+
Then you can use it in your model:
|
1242
|
+
|
1243
|
+
```ruby
|
1244
|
+
class Person < Shale::Mapper
|
1245
|
+
attribute :age, MyIntegerType
|
1246
|
+
end
|
1247
|
+
```
|
1248
|
+
|
1249
|
+
You can also register your own type with a symbol alias if you
|
1250
|
+
intend to use it often.
|
1251
|
+
|
1252
|
+
```ruby
|
1253
|
+
require 'shale/type'
|
1254
|
+
|
1255
|
+
Shale::Type.register(:my_integer, MyIntegerType)
|
1256
|
+
```
|
1257
|
+
|
1258
|
+
Then you can use it like this:
|
1259
|
+
|
1260
|
+
```ruby
|
1261
|
+
class Person < Shale::Mapper
|
1262
|
+
attribute :age, :my_integer
|
1263
|
+
end
|
1264
|
+
```
|
1265
|
+
|
1155
1266
|
### Adapters
|
1156
1267
|
|
1157
1268
|
Shale uses adapters for parsing and generating documents.
|
1158
|
-
By default Ruby's standard JSON
|
1269
|
+
By default Ruby's standard JSON and YAML parsers are used for handling JSON and YAML documents.
|
1159
1270
|
|
1160
1271
|
You can change it by providing your own adapter. For JSON, YAML, TOML and CSV adapter must
|
1161
1272
|
implement `.load` and `.dump` class methods.
|
@@ -1183,6 +1294,14 @@ require 'shale/adapter/toml_rb'
|
|
1183
1294
|
Shale.toml_adapter = Shale::Adapter::TomlRB
|
1184
1295
|
```
|
1185
1296
|
|
1297
|
+
To handle CSV documents you have to set CSV adapter. Shale provides adapter for `csv` parser:
|
1298
|
+
|
1299
|
+
```ruby
|
1300
|
+
require 'shale'
|
1301
|
+
require 'shale/adapter/csv'
|
1302
|
+
Shale.csv_adapter = Shale::Adapter::CSV
|
1303
|
+
```
|
1304
|
+
|
1186
1305
|
To handle XML documents you have to explicitly set XML adapter.
|
1187
1306
|
Shale provides adapters for most popular Ruby XML parsers:
|
1188
1307
|
|
@@ -1288,6 +1407,81 @@ end
|
|
1288
1407
|
Shale::Schema::JSONGenerator.register_json_type(MyEmailType, MyEmailJSONType)
|
1289
1408
|
```
|
1290
1409
|
|
1410
|
+
To add validation keywords to the schema, you can use a custom model and do this:
|
1411
|
+
|
1412
|
+
```ruby
|
1413
|
+
require 'shale/schema'
|
1414
|
+
|
1415
|
+
class PersonMapper < Shale::Mapper
|
1416
|
+
model Person
|
1417
|
+
|
1418
|
+
attribute :first_name, :string
|
1419
|
+
attribute :last_name, :string
|
1420
|
+
attribute :address, :string
|
1421
|
+
attribute :age, :integer
|
1422
|
+
|
1423
|
+
json do
|
1424
|
+
properties max_properties: 5, additional_properties: false
|
1425
|
+
|
1426
|
+
map "first_name", to: :first_name, schema: { required: true }
|
1427
|
+
map "last_name", to: :last_name, schema: { required: true }
|
1428
|
+
map "address", to: :address, schema: { max_length: 128, description: "Street, home number, city and country" }
|
1429
|
+
map "age", to: :age, schema: { minimum: 1, maximum: 150, description: "Person age" }
|
1430
|
+
end
|
1431
|
+
end
|
1432
|
+
|
1433
|
+
Shale::Schema.to_json(
|
1434
|
+
PersonMapper,
|
1435
|
+
pretty: true
|
1436
|
+
)
|
1437
|
+
|
1438
|
+
# =>
|
1439
|
+
#
|
1440
|
+
# {
|
1441
|
+
# "$schema": "https://json-schema.org/draft/2020-12/schema",
|
1442
|
+
# "description": "My description",
|
1443
|
+
# "$ref": "#/$defs/Person",
|
1444
|
+
# "$defs": {
|
1445
|
+
# "Person": {
|
1446
|
+
# "type": "object",
|
1447
|
+
# "properties": {
|
1448
|
+
# "first_name": {
|
1449
|
+
# "type": "string"
|
1450
|
+
# },
|
1451
|
+
# "last_name": {
|
1452
|
+
# "type": "string"
|
1453
|
+
# },
|
1454
|
+
# "address": {
|
1455
|
+
# "type": [
|
1456
|
+
# "string",
|
1457
|
+
# "null"
|
1458
|
+
# ],
|
1459
|
+
# "maxLength": 128,
|
1460
|
+
# "description": "Street, home number, city and country"
|
1461
|
+
# },
|
1462
|
+
# "age": {
|
1463
|
+
# "type": [
|
1464
|
+
# "integer",
|
1465
|
+
# "null"
|
1466
|
+
# ],
|
1467
|
+
# "minimum": 1,
|
1468
|
+
# "maximum": 150,
|
1469
|
+
# "description": "Person age"
|
1470
|
+
# }
|
1471
|
+
# },
|
1472
|
+
# "required": [
|
1473
|
+
# "first_name",
|
1474
|
+
# "last_name"
|
1475
|
+
# ],
|
1476
|
+
# "maxProperties": 5,
|
1477
|
+
# "additionalProperties": false
|
1478
|
+
# }
|
1479
|
+
# }
|
1480
|
+
# }
|
1481
|
+
```
|
1482
|
+
|
1483
|
+
Validation keywords are supported for all types, only the global `enum` and `const` types are not supported.
|
1484
|
+
|
1291
1485
|
### Compiling JSON Schema into Shale model
|
1292
1486
|
|
1293
1487
|
:warning: Only **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema is supported
|
data/lib/shale/adapter/json.rb
CHANGED
@@ -11,27 +11,30 @@ module Shale
|
|
11
11
|
# Parse JSON into Hash
|
12
12
|
#
|
13
13
|
# @param [String] json JSON document
|
14
|
+
# @param [Hash] options
|
14
15
|
#
|
15
16
|
# @return [Hash]
|
16
17
|
#
|
17
18
|
# @api private
|
18
|
-
def self.load(json)
|
19
|
-
::JSON.parse(json)
|
19
|
+
def self.load(json, **options)
|
20
|
+
::JSON.parse(json, **options)
|
20
21
|
end
|
21
22
|
|
22
23
|
# Serialize Hash into JSON
|
23
24
|
#
|
24
25
|
# @param [Hash] obj Hash object
|
25
|
-
# @param [
|
26
|
+
# @param [Hash] options
|
26
27
|
#
|
27
28
|
# @return [String]
|
28
29
|
#
|
29
30
|
# @api private
|
30
|
-
def self.dump(obj,
|
31
|
-
|
32
|
-
|
31
|
+
def self.dump(obj, **options)
|
32
|
+
json_options = options.except(:pretty)
|
33
|
+
|
34
|
+
if options[:pretty]
|
35
|
+
::JSON.pretty_generate(obj, **json_options)
|
33
36
|
else
|
34
|
-
::JSON.generate(obj)
|
37
|
+
::JSON.generate(obj, **json_options)
|
35
38
|
end
|
36
39
|
end
|
37
40
|
end
|
data/lib/shale/adapter/ox.rb
CHANGED
@@ -22,7 +22,8 @@ module Shale
|
|
22
22
|
#
|
23
23
|
# @api private
|
24
24
|
def self.load(xml)
|
25
|
-
|
25
|
+
element = ::Ox.parse(xml)
|
26
|
+
Node.new(element.respond_to?(:root) ? element.root : element)
|
26
27
|
rescue ::Ox::ParseError => e
|
27
28
|
raise ParseError, "Document is invalid: #{e.message}"
|
28
29
|
end
|
@@ -4,29 +4,31 @@ require 'toml-rb'
|
|
4
4
|
|
5
5
|
module Shale
|
6
6
|
module Adapter
|
7
|
-
#
|
7
|
+
# TomlRB adapter
|
8
8
|
#
|
9
9
|
# @api public
|
10
10
|
class TomlRB
|
11
11
|
# Parse TOML into Hash
|
12
12
|
#
|
13
13
|
# @param [String] toml TOML document
|
14
|
+
# @param [Hash] options
|
14
15
|
#
|
15
16
|
# @return [Hash]
|
16
17
|
#
|
17
18
|
# @api private
|
18
|
-
def self.load(toml)
|
19
|
+
def self.load(toml, **_options)
|
19
20
|
::TomlRB.parse(toml)
|
20
21
|
end
|
21
22
|
|
22
23
|
# Serialize Hash into TOML
|
23
24
|
#
|
24
25
|
# @param [Hash] obj Hash object
|
26
|
+
# @param [Hash] options
|
25
27
|
#
|
26
28
|
# @return [String]
|
27
29
|
#
|
28
30
|
# @api private
|
29
|
-
def self.dump(obj)
|
31
|
+
def self.dump(obj, **_options)
|
30
32
|
::TomlRB.dump(obj)
|
31
33
|
end
|
32
34
|
end
|