shale 0.3.1 → 0.6.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/README.md +398 -41
  4. data/exe/shaleb +108 -36
  5. data/lib/shale/adapter/nokogiri/document.rb +97 -0
  6. data/lib/shale/adapter/nokogiri/node.rb +100 -0
  7. data/lib/shale/adapter/nokogiri.rb +11 -151
  8. data/lib/shale/adapter/ox/document.rb +90 -0
  9. data/lib/shale/adapter/ox/node.rb +97 -0
  10. data/lib/shale/adapter/ox.rb +9 -134
  11. data/lib/shale/adapter/rexml/document.rb +98 -0
  12. data/lib/shale/adapter/rexml/node.rb +99 -0
  13. data/lib/shale/adapter/rexml.rb +9 -150
  14. data/lib/shale/adapter/toml_rb.rb +34 -0
  15. data/lib/shale/attribute.rb +6 -0
  16. data/lib/shale/error.rb +56 -0
  17. data/lib/shale/mapper.rb +67 -13
  18. data/lib/shale/mapping/descriptor/xml.rb +10 -1
  19. data/lib/shale/mapping/dict.rb +18 -0
  20. data/lib/shale/mapping/xml.rb +40 -5
  21. data/lib/shale/schema/compiler/boolean.rb +21 -0
  22. data/lib/shale/schema/compiler/complex.rb +88 -0
  23. data/lib/shale/schema/compiler/date.rb +21 -0
  24. data/lib/shale/schema/compiler/float.rb +21 -0
  25. data/lib/shale/schema/compiler/integer.rb +21 -0
  26. data/lib/shale/schema/compiler/property.rb +70 -0
  27. data/lib/shale/schema/compiler/string.rb +21 -0
  28. data/lib/shale/schema/compiler/time.rb +21 -0
  29. data/lib/shale/schema/compiler/value.rb +21 -0
  30. data/lib/shale/schema/compiler/xml_complex.rb +50 -0
  31. data/lib/shale/schema/compiler/xml_property.rb +73 -0
  32. data/lib/shale/schema/json_compiler.rb +331 -0
  33. data/lib/shale/schema/{json → json_generator}/base.rb +2 -2
  34. data/lib/shale/schema/{json → json_generator}/boolean.rb +1 -1
  35. data/lib/shale/schema/{json → json_generator}/collection.rb +2 -2
  36. data/lib/shale/schema/{json → json_generator}/date.rb +1 -1
  37. data/lib/shale/schema/{json → json_generator}/float.rb +1 -1
  38. data/lib/shale/schema/{json → json_generator}/integer.rb +1 -1
  39. data/lib/shale/schema/{json → json_generator}/object.rb +5 -2
  40. data/lib/shale/schema/{json → json_generator}/ref.rb +1 -1
  41. data/lib/shale/schema/{json → json_generator}/schema.rb +6 -4
  42. data/lib/shale/schema/{json → json_generator}/string.rb +1 -1
  43. data/lib/shale/schema/{json → json_generator}/time.rb +1 -1
  44. data/lib/shale/schema/json_generator/value.rb +23 -0
  45. data/lib/shale/schema/{json.rb → json_generator.rb} +36 -36
  46. data/lib/shale/schema/xml_compiler.rb +919 -0
  47. data/lib/shale/schema/{xml → xml_generator}/attribute.rb +1 -1
  48. data/lib/shale/schema/{xml → xml_generator}/complex_type.rb +5 -2
  49. data/lib/shale/schema/{xml → xml_generator}/element.rb +1 -1
  50. data/lib/shale/schema/{xml → xml_generator}/import.rb +1 -1
  51. data/lib/shale/schema/{xml → xml_generator}/ref_attribute.rb +1 -1
  52. data/lib/shale/schema/{xml → xml_generator}/ref_element.rb +1 -1
  53. data/lib/shale/schema/{xml → xml_generator}/schema.rb +5 -5
  54. data/lib/shale/schema/{xml → xml_generator}/typed_attribute.rb +1 -1
  55. data/lib/shale/schema/{xml → xml_generator}/typed_element.rb +1 -1
  56. data/lib/shale/schema/{xml.rb → xml_generator.rb} +25 -26
  57. data/lib/shale/schema.rb +44 -5
  58. data/lib/shale/type/{composite.rb → complex.rb} +156 -51
  59. data/lib/shale/type/value.rb +31 -2
  60. data/lib/shale/utils.rb +42 -7
  61. data/lib/shale/version.rb +1 -1
  62. data/lib/shale.rb +22 -19
  63. data/shale.gemspec +3 -3
  64. metadata +50 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36678c1f4afd6e0cf2d6a9a9e4b5becebf11e76404cb50dba7dc5269b5ca42cc
4
- data.tar.gz: 51c6c94abafe1767c579c270e3c3cb4da2ca79a2a29a9d28ea6bfe09bc4b53fb
3
+ metadata.gz: 243b99a073ac189f66ae0fbfedd94a5715399de731d0e0fd1d970dad749d27a0
4
+ data.tar.gz: d2f57de2427574d710d6a6fe9ba35868fd162214ce8aa2092ddfb3fe1f5e7c3d
5
5
  SHA512:
6
- metadata.gz: ea21dff00b6ea2663d20f9f377140250f78c29214a93f226047fe29d47680ae526652010ae268e4cf694ca1877cd8d19bfe8f0bbd767fa871fa80afaefee1c83
7
- data.tar.gz: 414d45b7bcd2477bc276eee17c598efba40350e0234c32f783c73217bee65ae4260d07e8a7bcfc7f48e1f76c9af4852de1c1c109c5b807e99a945305e2de6286
6
+ metadata.gz: 9de1be5eccbb647f05b6573d783491f858fb56614f09c7c625e7fa922c7b89b5d38863a57defbe506d42f0b542b326e4ca61ecf308b94f7b35b4056751e0299e
7
+ data.tar.gz: a1e29fc097c130c55e45837af198e3cd4f7d3ad6a94b17d032eb31b8065f7ea013682836256d12127480965ed3733079e5badd7a8b0060e3bc60f00734fcc215
data/CHANGELOG.md CHANGED
@@ -1,3 +1,40 @@
1
+ ## [0.6.0] - 2022-07-05
2
+
3
+ ### Added
4
+ - Support for TOML
5
+ - Support for CDATA nodes in XML documents
6
+ - Support for using custom models
7
+
8
+ ### Fixed
9
+ - Allow to map XML content using methods
10
+ - Prevent adding default mapping after mapping block was declared
11
+
12
+ ## [0.5.0] - 2022-06-28
13
+
14
+ ### Added
15
+ - Allow to generate Shale model from XML Schema
16
+
17
+ ### Changed
18
+ - Shale doesn't defaults to REXML anymore - XML adapter needs to be set explicitly
19
+ - Rename "JSONSchemaError" to "SchemaError"
20
+ - Rename "Composite" type to "Complex"
21
+ - Drop support for Ruby 2.6
22
+
23
+ ## [0.4.0] - 2022-05-30
24
+
25
+ ### Added
26
+ - Allow to add title to JSON Schema
27
+ - Map Shale::Type::Value to "anyType" XML Schema type
28
+ - Map Shale::Type::Value to "any" JSON Schema type
29
+ - Allow to generate Shale model from JSON Schema
30
+
31
+ ### Changed
32
+ - Performance improvements
33
+ - Reformat README a little bit and fix typos
34
+
35
+ ### Fixed
36
+ - Fix stack overflow caused by circular dependency when generating JSON and XML schemas
37
+
1
38
  ## [0.3.1] - 2022-04-29
2
39
 
3
40
  ### Changed
data/README.md CHANGED
@@ -1,10 +1,23 @@
1
1
  # Shale
2
2
 
3
- Shale is a object mapper and serializer for JSON, YAML and XML.
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.
6
+
7
+ Documentation with interactive examples is available at [Shale website](https://www.shalerb.org)
8
+
9
+ ## Features
10
+
11
+ * Convert JSON, YAML, TOML and XML to Ruby data model
12
+ * Convert Ruby data model to JSON, YAML, TOML and XML
13
+ * Generate JSON and XML Schema from Ruby models
14
+ * Compile JSON and XML Schema into Ruby models
15
+ * Out of the box support for JSON, YAML, toml-rb, Nokogiri, REXML and Ox parsers
16
+ * Support for custom adapters
4
17
 
5
18
  ## Installation
6
19
 
7
- Shale supports Ruby (MRI) 2.6+
20
+ Shale supports Ruby (MRI) 2.7+
8
21
 
9
22
  Add this line to your application's Gemfile:
10
23
 
@@ -32,27 +45,31 @@ $ gem install shale
32
45
  * [Converting object to JSON](#converting-object-to-json)
33
46
  * [Converting YAML to object](#converting-yaml-to-object)
34
47
  * [Converting object to YAML](#converting-object-to-yaml)
48
+ * [Converting TOML to object](#converting-toml-to-object)
49
+ * [Converting object to TOML](#converting-object-to-toml)
35
50
  * [Converting Hash to object](#converting-hash-to-object)
36
51
  * [Converting object to Hash](#converting-object-to-hash)
37
52
  * [Converting XML to object](#converting-xml-to-object)
38
53
  * [Converting object to XML](#converting-object-to-xml)
39
54
  * [Mapping JSON keys to object attributes](#mapping-json-keys-to-object-attributes)
40
55
  * [Mapping YAML keys to object attributes](#mapping-yaml-keys-to-object-attributes)
56
+ * [Mapping TOML keys to object attributes](#mapping-toml-keys-to-object-attributes)
41
57
  * [Mapping Hash keys to object attributes](#mapping-hash-keys-to-object-attributes)
42
58
  * [Mapping XML elements and attributes to object attributes](#mapping-xml-elements-and-attributes-to-object-attributes)
43
59
  * [Using XML namespaces](#using-xml-namespaces)
44
60
  * [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
45
61
  * [Pretty printing and XML declaration](#pretty-printing-and-xml-declaration)
62
+ * [Using custom models](#using-custom-models)
46
63
  * [Supported types](#supported-types)
47
64
  * [Writing your own type](#writing-your-own-type)
48
65
  * [Adapters](#adapters)
49
66
  * [Generating JSON Schema](#generating-json-schema)
67
+ * [Compiling JSON Schema into Shale model](#compiling-json-schema-into-shale-model)
50
68
  * [Generating XML Schema](#generating-xml-schema)
69
+ * [Compiling XML Schema into Shale model](#compiling-xml-schema-into-shale-model)
51
70
 
52
71
  ## Usage
53
72
 
54
- Documentation with interactive examples is available at [Shale website](https://www.shalerb.org)
55
-
56
73
  ### Simple use case
57
74
 
58
75
  ```ruby
@@ -126,6 +143,7 @@ DATA
126
143
 
127
144
  ```ruby
128
145
  person.to_json
146
+
129
147
  # =>
130
148
  #
131
149
  # {
@@ -164,6 +182,63 @@ DATA
164
182
 
165
183
  ```ruby
166
184
  person.to_yaml
185
+
186
+ # =>
187
+ #
188
+ # ---
189
+ # first_name: John
190
+ # last_name: Doe
191
+ # age: 50
192
+ # married: false
193
+ # hobbies:
194
+ # - Singing
195
+ # - Dancing
196
+ # address:
197
+ # city: London
198
+ # street: Oxford Street
199
+ # zip: E1 6AN
200
+ ```
201
+
202
+ ### Converting TOML to object
203
+
204
+ To use TOML with Shale you have to set adapter you want to use.
205
+ Shale comes with adapter for [toml-rb](https://github.com/emancu/toml-rb).
206
+ For details see [Adapters](#adapters) section.
207
+
208
+ To set it, first make sure toml-rb gem is installed:
209
+
210
+ ```
211
+ $ gem install shale
212
+ ```
213
+
214
+ then setup adapter:
215
+
216
+ ```ruby
217
+ require 'shale/adapter/toml_rb'
218
+ Shale.toml_adapter = Shale::Adapter::TomlRB
219
+ ```
220
+
221
+ Now you can use TOML with Shale:
222
+
223
+ ```ruby
224
+ person = Person.from_toml(<<~DATA)
225
+ first_name = "John"
226
+ last_name = "Doe"
227
+ age = 50
228
+ married = false
229
+ hobbies = ["Singing", "Dancing"]
230
+ [address]
231
+ city = "London"
232
+ street = "Oxford Street"
233
+ zip = "E1 6AN"
234
+ DATA
235
+ ```
236
+
237
+ ### Converting object to TOML
238
+
239
+ ```ruby
240
+ person.to_toml
241
+
167
242
  # =>
168
243
  #
169
244
  # ---
@@ -201,6 +276,7 @@ person = Person.from_hash(
201
276
 
202
277
  ```ruby
203
278
  person.to_hash
279
+
204
280
  # =>
205
281
  #
206
282
  # {
@@ -215,6 +291,17 @@ person.to_hash
215
291
 
216
292
  ### Converting XML to object
217
293
 
294
+ To use XML with Shale you have to set adapter you want to use.
295
+ Shale comes with adapters for REXML, Nokogiri and OX parsers.
296
+ For details see [Adapters](#adapters) section.
297
+
298
+ ```ruby
299
+ require 'shale/adapter/rexml'
300
+ Shale.xml_adapter = Shale::Adapter::REXML
301
+ ```
302
+
303
+ Now you can use XML with Shale:
304
+
218
305
  ```ruby
219
306
  person = Person.from_xml(<<~DATA)
220
307
  <person>
@@ -237,6 +324,7 @@ DATA
237
324
 
238
325
  ```ruby
239
326
  person.to_xml
327
+
240
328
  # =>
241
329
  #
242
330
  # <person>
@@ -256,7 +344,9 @@ person.to_xml
256
344
 
257
345
  ### Mapping JSON keys to object attributes
258
346
 
259
- By default keys are named the same as attributes. To use custom key names use:
347
+ By default keys are named the same as attributes. To use custom keys use:
348
+
349
+ :warning: **Declaring custom mapping removes default mapping for given format!**
260
350
 
261
351
  ```ruby
262
352
  class Person < Shale::Mapper
@@ -284,6 +374,20 @@ class Person < Shale::Mapper
284
374
  end
285
375
  ```
286
376
 
377
+ ### Mapping TOML keys to object attributes
378
+
379
+ ```ruby
380
+ class Person < Shale::Mapper
381
+ attribute :first_name, Shale::Type::String
382
+ attribute :last_name, Shale::Type::String
383
+
384
+ toml do
385
+ map 'firstName', to: :first_name
386
+ map 'lastName', to: :last_name
387
+ end
388
+ end
389
+ ```
390
+
287
391
  ### Mapping Hash keys to object attributes
288
392
 
289
393
  ```ruby
@@ -300,7 +404,7 @@ end
300
404
 
301
405
  ### Mapping XML elements and attributes to object attributes
302
406
 
303
- XML is more complcated format than JSON or YAML. To map elements, attributes and content use:
407
+ XML is more complicated format than JSON or YAML. To map elements, attributes and content use:
304
408
 
305
409
  ```ruby
306
410
  class Address < Shale::Mapper
@@ -354,9 +458,38 @@ DATA
354
458
  - `map_attribute` - map element's attribute to attribute
355
459
  - `map_content` - map first text node to attribute
356
460
 
357
- ### Using XML namespaces
461
+ You can use `cdata: true` option on `map_element` and `map_content` to handle CDATA nodes:
358
462
 
359
- :warning: **Ox doesn't support XML namespaces**
463
+ ```ruby
464
+ class Address < Shale::Mapper
465
+ attribute :content, Shale::Type::String
466
+
467
+ xml do
468
+ map_content to: :content, cdata: true
469
+ end
470
+ end
471
+
472
+ class Person < Shale::Mapper
473
+ attribute :first_name, Shale::Type::String
474
+ attribute :address, Address
475
+
476
+ xml do
477
+ root 'Person'
478
+
479
+ map_element 'FirstName', to: :first_name, cdata: true
480
+ map_element 'Address', to: :address
481
+ end
482
+ end
483
+
484
+ person = Person.from_xml(<<~DATA)
485
+ <Person>
486
+ <FirstName><![CDATA[John]]></FirstName>
487
+ <Address><![CDATA[Oxford Street]]></Address>
488
+ </person>
489
+ DATA
490
+ ```
491
+
492
+ ### Using XML namespaces
360
493
 
361
494
  To map namespaced elements and attributes use `namespace` and `prefix` properties on
362
495
  `map_element` and `map_attribute`
@@ -385,7 +518,7 @@ DATA
385
518
  ```
386
519
 
387
520
  To define default namespace for all elements use `namespace` declaration
388
- (this will define namespace only on elements, if you want to define namespace on an attribute
521
+ (this will define namespace on elements only, if you want to define namespace on an attribute
389
522
  explicitly declare it on `map_attribute`).
390
523
 
391
524
  ```ruby
@@ -445,42 +578,42 @@ class Person < Shale::Mapper
445
578
  map_element 'Address', using: { from: :address_from_xml, to: :address_to_xml }
446
579
  end
447
580
 
448
- def hobbies_from_json(value)
449
- self.hobbies = value.split(',').map(&:strip)
581
+ def hobbies_from_json(model, value)
582
+ model.hobbies = value.split(',').map(&:strip)
450
583
  end
451
584
 
452
- def hobbies_to_json
453
- hobbies.join(', ')
585
+ def hobbies_to_json(model)
586
+ model.hobbies.join(', ')
454
587
  end
455
588
 
456
- def address_from_json(value)
457
- self.street = value['street']
458
- self.city = value['city']
589
+ def address_from_json(model, value)
590
+ model.street = value['street']
591
+ model.city = value['city']
459
592
  end
460
593
 
461
- def address_to_json
462
- { 'street' => street, 'city' => city }
594
+ def address_to_json(model)
595
+ { 'street' => model.street, 'city' => model.city }
463
596
  end
464
597
 
465
- def hobbies_from_xml(value)
466
- self.hobbies = value.split(',').map(&:strip)
598
+ def hobbies_from_xml(model, value)
599
+ model.hobbies = value.split(',').map(&:strip)
467
600
  end
468
601
 
469
- def hobbies_to_xml(element, doc)
470
- doc.add_attribute(element, 'hobbies', hobbies.join(', '))
602
+ def hobbies_to_xml(model, element, doc)
603
+ doc.add_attribute(element, 'hobbies', model.hobbies.join(', '))
471
604
  end
472
605
 
473
- def address_from_xml(node)
474
- self.street = node.children.find { |e| e.name == 'Street' }.text
475
- self.city = node.children.find { |e| e.name == 'City' }.text
606
+ def address_from_xml(model, node)
607
+ model.street = node.children.find { |e| e.name == 'Street' }.text
608
+ model.city = node.children.find { |e| e.name == 'City' }.text
476
609
  end
477
610
 
478
- def address_to_xml(parent, doc)
611
+ def address_to_xml(model, parent, doc)
479
612
  street_element = doc.create_element('Street')
480
- doc.add_text(street_element, street.to_s)
613
+ doc.add_text(street_element, model.street.to_s)
481
614
 
482
615
  city_element = doc.create_element('City')
483
- doc.add_text(city_element, city.to_s)
616
+ doc.add_text(city_element, model.city.to_s)
484
617
 
485
618
  address_element = doc.create_element('Address')
486
619
  doc.add_element(address_element, street_element)
@@ -505,7 +638,7 @@ person = Person.from_xml(<<~DATA)
505
638
  <Street>Oxford Street</Street>
506
639
  <City>London</City>
507
640
  </Address>
508
- </person>
641
+ </Person>
509
642
  DATA
510
643
 
511
644
  # =>
@@ -546,6 +679,67 @@ person.to_xml(:pretty, :declaration)
546
679
  # </Person>
547
680
  ```
548
681
 
682
+ ### Using custom models
683
+
684
+ By default Shale combines mapper and model into one class. If you want to use your own classes
685
+ as models you can do it by using `model` directive on the mapper:
686
+
687
+ ```ruby
688
+ class Address
689
+ attr_accessor :street, :city
690
+ end
691
+
692
+ class Person
693
+ attr_accessor :first_name, :last_name, :address
694
+ end
695
+
696
+ class AddressMapper < Shale::Mapper
697
+ model Address
698
+
699
+ attribute :street, Shale::Type::String
700
+ attribute :city, Shale::Type::String
701
+ end
702
+
703
+ class PersonMapper < Shale::Mapper
704
+ model Person
705
+
706
+ attribute :first_name, Shale::Type::String
707
+ attribute :last_name, Shale::Type::String
708
+ attribute :address, AddressMapper
709
+ end
710
+
711
+ person = PersonMapper.from_json(<<~DATA)
712
+ {
713
+ "first_name": "John",
714
+ "last_name": "Doe",
715
+ "address": {
716
+ "street": "Oxford Street",
717
+ "city": "London"
718
+ }
719
+ }
720
+ DATA
721
+
722
+ # =>
723
+ #
724
+ # #<Person:0x0000000113d7a488
725
+ # @first_name="John",
726
+ # @last_name="Doe",
727
+ # @address=#<Address:0x0000000113d7a140 @street="Oxford Street", @city="London">>
728
+
729
+ PersonMapper.to_json(person, :pretty)
730
+
731
+ # =>
732
+ #
733
+ # {
734
+ # "first_name": "John",
735
+ # "last_name": "Doe",
736
+ # "address": {
737
+ # "street": "Oxford Street",
738
+ # "city": "London"
739
+ # }
740
+ # }
741
+ ```
742
+
549
743
  ### Supported types
550
744
 
551
745
  Shale supports these types out of the box:
@@ -574,10 +768,9 @@ end
574
768
  ### Adapters
575
769
 
576
770
  Shale uses adapters for parsing and generating documents.
577
- By default Ruby's standard JSON parser is used for handling JSON documents, YAML for YAML and
578
- REXML for XML.
771
+ By default Ruby's standard JSON, YAML parsers are used for handling JSON and YAML documents.
579
772
 
580
- You can change it by providing your own adapter. For JSON and YAML, adapter must implement
773
+ You can change it by providing your own adapter. For JSON, YAML and TOML, adapter must implement
581
774
  `.load` and `.dump` class methods.
582
775
 
583
776
  ```ruby
@@ -588,12 +781,25 @@ Shale.json_adapter = MultiJson
588
781
  Shale.yaml_adapter = MyYamlAdapter
589
782
  ```
590
783
 
784
+ To handle TOML documents you have to set TOML adapter.
785
+ Shale provides adapter for `toml-rb` TOML parser:
786
+
787
+ ```ruby
788
+ require 'shale'
789
+
790
+ require 'shale/adapter/toml_rb'
791
+ Shale.toml_adapter = Shale::Adapter::TomlRB
792
+ ```
793
+
794
+ To handle XML documents you have to explicitly set XML adapter.
591
795
  Shale provides adapters for most popular Ruby XML parsers:
592
796
 
797
+ :warning: **Ox doesn't support XML namespaces**
798
+
593
799
  ```ruby
594
800
  require 'shale'
595
801
 
596
- # REXML is used by default:
802
+ # if you want to use REXML:
597
803
 
598
804
  require 'shale/adapter/rexml'
599
805
  Shale.xml_adapter = Shale::Adapter::REXML
@@ -611,14 +817,19 @@ Shale.xml_adapter = Shale::Adapter::Ox
611
817
 
612
818
  ### Generating JSON Schema
613
819
 
614
- To generate JSON Schema from you Shale data model use:
820
+ :warning: Only **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema is supported
615
821
 
616
- :warning: Shale only supports **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema
822
+ To generate JSON Schema from your Shale data model use:
617
823
 
618
824
  ```ruby
619
825
  require 'shale/schema'
620
826
 
621
- Shale::Schema.to_json(Person, id: 'http://foo.bar/schema/person', description: 'My description', pretty: true)
827
+ Shale::Schema.to_json(
828
+ Person,
829
+ id: 'http://foo.bar/schema/person',
830
+ description: 'My description',
831
+ pretty: true
832
+ )
622
833
 
623
834
  # =>
624
835
  #
@@ -663,7 +874,7 @@ Shale::Schema.to_json(Person, id: 'http://foo.bar/schema/person', description: '
663
874
  You can also use a command line tool to do it:
664
875
 
665
876
  ```
666
- $ shaleb -i data_model.rb -c Person -p
877
+ $ shaleb -i data_model.rb -r Person -p
667
878
  ```
668
879
 
669
880
  If you want to convert your own types to JSON Schema types use:
@@ -676,13 +887,83 @@ class MyEmailType < Shale::Type::Value
676
887
  ...
677
888
  end
678
889
 
679
- class MyEmailJSONType < Shale::Schema::JSON::Base
890
+ class MyEmailJSONType < Shale::Schema::JSONGenerator::Base
680
891
  def as_type
681
892
  { 'type' => 'string', 'format' => 'email' }
682
893
  end
683
894
  end
684
895
 
685
- Shale::Schema::JSON.register_json_type(MyEmailType, MyEmailJSONType)
896
+ Shale::Schema::JSONGenerator.register_json_type(MyEmailType, MyEmailJSONType)
897
+ ```
898
+
899
+ ### Compiling JSON Schema into Shale model
900
+
901
+ :warning: Only **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema is supported
902
+
903
+ To generate Shale data model from JSON Schema use:
904
+
905
+ ```ruby
906
+ require 'shale/schema'
907
+
908
+ schema = <<~SCHEMA
909
+ {
910
+ "type": "object",
911
+ "properties": {
912
+ "firstName": { "type": "string" },
913
+ "lastName": { "type": "string" },
914
+ "address": {
915
+ "type": "object",
916
+ "properties": {
917
+ "street": { "type": "string" },
918
+ "city": { "type": "string" }
919
+ }
920
+ }
921
+ }
922
+ }
923
+ SCHEMA
924
+
925
+ Shale::Schema.from_json([schema], root_name: 'Person')
926
+
927
+ # =>
928
+ #
929
+ # {
930
+ # "address" => "
931
+ # require 'shale'
932
+ #
933
+ # class Address < Shale::Mapper
934
+ # attribute :street, Shale::Type::String
935
+ # attribute :city, Shale::Type::String
936
+ #
937
+ # json do
938
+ # map 'street', to: :street
939
+ # map 'city', to: :city
940
+ # end
941
+ # end
942
+ # ",
943
+ # "person" => "
944
+ # require 'shale'
945
+ #
946
+ # require_relative 'address'
947
+ #
948
+ # class Person < Shale::Mapper
949
+ # attribute :first_name, Shale::Type::String
950
+ # attribute :last_name, Shale::Type::String
951
+ # attribute :address, Address
952
+ #
953
+ # json do
954
+ # map 'firstName', to: :first_name
955
+ # map 'lastName', to: :last_name
956
+ # map 'address', to: :address
957
+ # end
958
+ # end
959
+ # "
960
+ # }
961
+ ```
962
+
963
+ You can also use a command line tool to do it:
964
+
965
+ ```
966
+ $ shaleb -c -i schema.json -r Person
686
967
  ```
687
968
 
688
969
  ### Generating XML Schema
@@ -735,7 +1016,7 @@ Shale::Schema.to_xml(Person, pretty: true)
735
1016
  You can also use a command line tool to do it:
736
1017
 
737
1018
  ```
738
- $ shaleb -i data_model.rb -c Person -p -f xml
1019
+ $ shaleb -i data_model.rb -r Person -p -f xml
739
1020
  ```
740
1021
 
741
1022
  If you want to convert your own types to XML Schema types use:
@@ -748,7 +1029,83 @@ class MyEmailType < Shale::Type::Value
748
1029
  ...
749
1030
  end
750
1031
 
751
- Shale::Schema::XML.register_xml_type(MyEmailType, 'myEmailXMLType')
1032
+ Shale::Schema::XMLGenerator.register_xml_type(MyEmailType, 'myEmailXMLType')
1033
+ ```
1034
+
1035
+ ### Compiling XML Schema into Shale model
1036
+
1037
+ To generate Shale data model from XML Schema use:
1038
+
1039
+ ```ruby
1040
+ require 'shale/schema'
1041
+
1042
+ schema = <<~SCHEMA
1043
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
1044
+ <xs:element name="Person" type="Person" />
1045
+
1046
+ <xs:complexType name="Person">
1047
+ <xs:sequence>
1048
+ <xs:element name="FirstName" type="xs:string" />
1049
+ <xs:element name="LastName" type="xs:string" />
1050
+ <xs:element name="Address" type="Address" />
1051
+ </xs:sequence>
1052
+ </xs:complexType>
1053
+
1054
+ <xs:complexType name="Address">
1055
+ <xs:sequence>
1056
+ <xs:element name="Street" type="xs:string" />
1057
+ <xs:element name="City" type="xs:string" />
1058
+ </xs:sequence>
1059
+ </xs:complexType>
1060
+ </xs:schema>
1061
+ SCHEMA
1062
+
1063
+ Shale::Schema.from_xml([schema])
1064
+
1065
+ # =>
1066
+ #
1067
+ # {
1068
+ # "address" => "
1069
+ # require 'shale'
1070
+ #
1071
+ # class Address < Shale::Mapper
1072
+ # attribute :street, Shale::Type::String
1073
+ # attribute :city, Shale::Type::String
1074
+ #
1075
+ # xml do
1076
+ # root 'Address'
1077
+ #
1078
+ # map_element 'Street', to: :street
1079
+ # map_element 'City', to: :city
1080
+ # end
1081
+ # end
1082
+ # ",
1083
+ # "person" => "
1084
+ # require 'shale'
1085
+ #
1086
+ # require_relative 'address'
1087
+ #
1088
+ # class Person < Shale::Mapper
1089
+ # attribute :first_name, Shale::Type::String
1090
+ # attribute :last_name, Shale::Type::String
1091
+ # attribute :address, Address
1092
+ #
1093
+ # xml do
1094
+ # root 'Person'
1095
+ #
1096
+ # map_element 'FirstName', to: :first_name
1097
+ # map_element 'LastName', to: :last_name
1098
+ # map_element 'Address', to: :address
1099
+ # end
1100
+ # end
1101
+ # "
1102
+ # }
1103
+ ```
1104
+
1105
+ You can also use a command line tool to do it:
1106
+
1107
+ ```
1108
+ $ shaleb -c -f xml -i schema.xml
752
1109
  ```
753
1110
 
754
1111
  ## Contributing