shale 0.9.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/README.md +277 -50
- data/exe/shaleb +19 -4
- data/lib/shale/adapter/nokogiri.rb +1 -1
- data/lib/shale/adapter/ox.rb +2 -1
- data/lib/shale/error.rb +32 -8
- data/lib/shale/mapper.rb +7 -7
- data/lib/shale/mapping/delegates.rb +95 -0
- data/lib/shale/mapping/descriptor/dict.rb +19 -1
- data/lib/shale/mapping/descriptor/xml.rb +13 -2
- data/lib/shale/mapping/dict.rb +15 -4
- data/lib/shale/mapping/dict_base.rb +32 -4
- data/lib/shale/mapping/dict_group.rb +1 -1
- data/lib/shale/mapping/validator.rb +10 -3
- data/lib/shale/mapping/xml.rb +22 -6
- data/lib/shale/mapping/xml_base.rb +21 -12
- data/lib/shale/schema/compiler/complex.rb +52 -8
- data/lib/shale/schema/compiler/xml_complex.rb +5 -4
- data/lib/shale/schema/json_compiler.rb +27 -13
- data/lib/shale/schema/json_generator/base.rb +9 -3
- data/lib/shale/schema/json_generator/collection.rb +17 -2
- data/lib/shale/schema/json_generator/float.rb +6 -1
- data/lib/shale/schema/json_generator/integer.rb +6 -1
- data/lib/shale/schema/json_generator/object.rb +10 -2
- data/lib/shale/schema/json_generator/string.rb +5 -1
- data/lib/shale/schema/json_generator.rb +8 -4
- data/lib/shale/schema/xml_compiler.rb +58 -30
- data/lib/shale/schema/xml_generator.rb +3 -3
- data/lib/shale/schema.rb +10 -4
- data/lib/shale/type/complex.rb +176 -24
- data/lib/shale/utils.rb +22 -4
- data/lib/shale/version.rb +1 -1
- data/lib/shale.rb +12 -16
- data/shale.gemspec +3 -1
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60a0f059693d5ea371ffca8b475ebb261ee99096509e588d2f1163a96bf8fbc0
|
4
|
+
data.tar.gz: c1af0c61c7d9a93bd601188c50916d4f702228052541adee34456c4d7dac8b9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31bd59c352febaf287eda07a79f56e5fe942fd86623f532e48c25ff5e946bb53fc879c3f8bb13121989268057beb4ee740f8aac7b1275dda8b9a2d21a5f75aaf
|
7
|
+
data.tar.gz: 127b46cdeb0960643aa60410597f7ace1815dd19e3845cd0cb7c2ea3d2d44b4326333656bdf96209effcf17daabbc5a70de9f430acd42e21d961e2c356d9be9f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
## [1.1.0] - 2024-02-17
|
2
|
+
|
3
|
+
### Added
|
4
|
+
- [bkjohnson] Add support for JSON Schema validation keywords (#29)
|
5
|
+
- Add support for Ruby 3.3
|
6
|
+
|
7
|
+
### Changed
|
8
|
+
- Drop support for Ruby 2.6 and Ruby 2.7
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
- Fix Ox adapter incorrectly handling documents with XML declaration
|
12
|
+
|
13
|
+
## [1.0.0] - 2023-07-15
|
14
|
+
|
15
|
+
### Added
|
16
|
+
- Support for Ruby 3.2
|
17
|
+
- Support for delegating fields to nested attributes
|
18
|
+
- JSON and XML schema namespace mapping support
|
19
|
+
- Allow to set render_nil defaults
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
- Use `ShaleError` as a base class for exceptions
|
23
|
+
- Use model instead of mapper names for schema types
|
24
|
+
|
25
|
+
### Fixed
|
26
|
+
- Fix compilation error for bundled JSON schemas
|
27
|
+
- Fix type inference for XML schema when default namespace is used
|
28
|
+
- Fix XML schema handling with a period in the element name
|
29
|
+
|
1
30
|
## [0.9.0] - 2022-10-31
|
2
31
|
|
3
32
|
### 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
|
|
@@ -63,6 +63,7 @@ $ gem install shale
|
|
63
63
|
* [Using XML namespaces](#using-xml-namespaces)
|
64
64
|
* [Rendering nil values](#rendering-nil-values)
|
65
65
|
* [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
|
66
|
+
* [Delegating fields to child attributes](#delegating-fields-to-child-attributes)
|
66
67
|
* [Additional options](#additional-options)
|
67
68
|
* [Using custom models](#using-custom-models)
|
68
69
|
* [Supported types](#supported-types)
|
@@ -352,6 +353,25 @@ person.to_xml
|
|
352
353
|
|
353
354
|
### Converting CSV to object
|
354
355
|
|
356
|
+
To use CSV with Shale you have to set adapter.
|
357
|
+
Shale comes with adapter for [csv](https://github.com/ruby/csv).
|
358
|
+
For details see [Adapters](#adapters) section.
|
359
|
+
|
360
|
+
To set it, first make sure CSV gem is installed:
|
361
|
+
|
362
|
+
```
|
363
|
+
$ gem install csv
|
364
|
+
```
|
365
|
+
|
366
|
+
then setup adapter:
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
require 'shale/adapter/csv'
|
370
|
+
Shale.csv_adapter = Shale::Adapter::CSV
|
371
|
+
```
|
372
|
+
|
373
|
+
Now you can use CSV with Shale.
|
374
|
+
|
355
375
|
CSV represents a flat data structure, so you can't map properties to complex types directly,
|
356
376
|
but you can use methods to map properties to complex types
|
357
377
|
(see [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
|
@@ -692,6 +712,49 @@ puts person.to_xml(pretty: true)
|
|
692
712
|
# </person>
|
693
713
|
```
|
694
714
|
|
715
|
+
If you want to change how nil values are rendered for all mappings you can use `render_nil` method:
|
716
|
+
|
717
|
+
```ruby
|
718
|
+
class Base < Shale::Mapper
|
719
|
+
json do
|
720
|
+
# change render_nil default for all JSON mappings inheriting from Base class
|
721
|
+
render_nil true
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
class Person < Base
|
726
|
+
attribute :first_name, Shale::Type::String
|
727
|
+
attribute :last_name, Shale::Type::String
|
728
|
+
attribute :age, Shale::Type::Integer
|
729
|
+
|
730
|
+
json do
|
731
|
+
# override default from Base class
|
732
|
+
render_nil false
|
733
|
+
|
734
|
+
map 'first_name', to: :first_name
|
735
|
+
map 'last_name', to: :last_name
|
736
|
+
map 'age', to: :age, render_nil: true # override default
|
737
|
+
end
|
738
|
+
end
|
739
|
+
```
|
740
|
+
|
741
|
+
:warning: The default affects only the mappings declared after setting the default value e.g.
|
742
|
+
|
743
|
+
```ruby
|
744
|
+
class Person < Base
|
745
|
+
attribute :first_name, Shale::Type::String
|
746
|
+
attribute :last_name, Shale::Type::String
|
747
|
+
|
748
|
+
json do
|
749
|
+
render_nil false
|
750
|
+
map 'first_name', to: :first_name # render_nil will be false for this mapping
|
751
|
+
|
752
|
+
render_nil true
|
753
|
+
map 'last_name', to: :last_name # render_nil will be true for this mapping
|
754
|
+
end
|
755
|
+
end
|
756
|
+
```
|
757
|
+
|
695
758
|
### Using methods to extract and generate data
|
696
759
|
|
697
760
|
If you need full controll over extracting and generating data from/to document,
|
@@ -865,6 +928,42 @@ DATA
|
|
865
928
|
# => #<Person:0x00007f9bc3086d60 @name="John Doe">
|
866
929
|
```
|
867
930
|
|
931
|
+
### Delegating fields to child attributes
|
932
|
+
|
933
|
+
To delegate fields to child complex types you can use `receiver: :child` declaration:
|
934
|
+
|
935
|
+
```ruby
|
936
|
+
class Address < Shale::Mapper
|
937
|
+
attribute :city, Shale::Type::String
|
938
|
+
attribute :street, Shale::Type::String
|
939
|
+
end
|
940
|
+
|
941
|
+
class Person < Shale::Mapper
|
942
|
+
attribute :name, Shale::Type::String
|
943
|
+
attribute :address, Address
|
944
|
+
|
945
|
+
json do
|
946
|
+
map 'name', to: :name
|
947
|
+
map 'city', to: :city, receiver: :address
|
948
|
+
map 'street', to: :street, receiver: :address
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
person = Person.from_json(<<~DATA)
|
953
|
+
{
|
954
|
+
"name": "John Doe",
|
955
|
+
"city": "London",
|
956
|
+
"street": "Oxford Street"
|
957
|
+
}
|
958
|
+
DATA
|
959
|
+
|
960
|
+
# =>
|
961
|
+
#
|
962
|
+
# #<Person:0x00007f9bc3086d60
|
963
|
+
# @name="John Doe",
|
964
|
+
# @address=#<Address:0x0000000102cbd218 @city="London", @street="Oxford Street">>
|
965
|
+
```
|
966
|
+
|
868
967
|
### Additional options
|
869
968
|
|
870
969
|
You can control which attributes to render and parse by
|
@@ -1075,7 +1174,7 @@ end
|
|
1075
1174
|
### Adapters
|
1076
1175
|
|
1077
1176
|
Shale uses adapters for parsing and generating documents.
|
1078
|
-
By default Ruby's standard JSON
|
1177
|
+
By default Ruby's standard JSON and YAML parsers are used for handling JSON and YAML documents.
|
1079
1178
|
|
1080
1179
|
You can change it by providing your own adapter. For JSON, YAML, TOML and CSV adapter must
|
1081
1180
|
implement `.load` and `.dump` class methods.
|
@@ -1103,6 +1202,14 @@ require 'shale/adapter/toml_rb'
|
|
1103
1202
|
Shale.toml_adapter = Shale::Adapter::TomlRB
|
1104
1203
|
```
|
1105
1204
|
|
1205
|
+
To handle CSV documents you have to set CSV adapter. Shale provides adapter for `csv` parser:
|
1206
|
+
|
1207
|
+
```ruby
|
1208
|
+
require 'shale'
|
1209
|
+
require 'shale/adapter/csv'
|
1210
|
+
Shale.csv_adapter = Shale::Adapter::CSV
|
1211
|
+
```
|
1212
|
+
|
1106
1213
|
To handle XML documents you have to explicitly set XML adapter.
|
1107
1214
|
Shale provides adapters for most popular Ruby XML parsers:
|
1108
1215
|
|
@@ -1208,11 +1315,82 @@ end
|
|
1208
1315
|
Shale::Schema::JSONGenerator.register_json_type(MyEmailType, MyEmailJSONType)
|
1209
1316
|
```
|
1210
1317
|
|
1318
|
+
To add validation keywords to the schema, you can use a custom model and do this:
|
1319
|
+
|
1320
|
+
```ruby
|
1321
|
+
require 'shale/schema'
|
1322
|
+
|
1323
|
+
class PersonMapper < Shale::Mapper
|
1324
|
+
model Person
|
1325
|
+
|
1326
|
+
attribute :first_name, Shale::Type::String
|
1327
|
+
attribute :last_name, Shale::Type::String
|
1328
|
+
attribute :address, Shale::Type::String
|
1329
|
+
attribute :age, Shale::Type::Integer
|
1330
|
+
|
1331
|
+
json do
|
1332
|
+
properties max_properties: 5
|
1333
|
+
|
1334
|
+
map "first_name", to: :first_name, schema: { required: true }
|
1335
|
+
map "last_name", to: :last_name, schema: { required: true }
|
1336
|
+
map "address", to: :age, schema: { max_length: 128 }
|
1337
|
+
map "age", to: :age, schema: { minimum: 1, maximum: 150 }
|
1338
|
+
end
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
Shale::Schema.to_json(
|
1342
|
+
PersonMapper,
|
1343
|
+
pretty: true
|
1344
|
+
)
|
1345
|
+
|
1346
|
+
# =>
|
1347
|
+
#
|
1348
|
+
# {
|
1349
|
+
# "$schema": "https://json-schema.org/draft/2020-12/schema",
|
1350
|
+
# "description": "My description",
|
1351
|
+
# "$ref": "#/$defs/Person",
|
1352
|
+
# "$defs": {
|
1353
|
+
# "Person": {
|
1354
|
+
# "type": "object",
|
1355
|
+
# "maxProperties": 5,
|
1356
|
+
# "properties": {
|
1357
|
+
# "first_name": {
|
1358
|
+
# "type": "string"
|
1359
|
+
# },
|
1360
|
+
# "last_name": {
|
1361
|
+
# "type": "string"
|
1362
|
+
# },
|
1363
|
+
# "age": {
|
1364
|
+
# "type": [
|
1365
|
+
# "integer",
|
1366
|
+
# "null"
|
1367
|
+
# ],
|
1368
|
+
# "minimum": 1,
|
1369
|
+
# "maximum": 150
|
1370
|
+
# },
|
1371
|
+
# "address": {
|
1372
|
+
# "type": [
|
1373
|
+
# "string",
|
1374
|
+
# "null"
|
1375
|
+
# ],
|
1376
|
+
# "maxLength": 128
|
1377
|
+
# }
|
1378
|
+
# },
|
1379
|
+
# "required": ["first_name", "last_name"]
|
1380
|
+
# }
|
1381
|
+
# }
|
1382
|
+
# }
|
1383
|
+
```
|
1384
|
+
|
1385
|
+
Validation keywords are supported for all types, only the global `enum` and `const` types are not supported.
|
1386
|
+
|
1211
1387
|
### Compiling JSON Schema into Shale model
|
1212
1388
|
|
1213
1389
|
:warning: Only **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema is supported
|
1214
1390
|
|
1215
|
-
To generate Shale data model from JSON Schema use
|
1391
|
+
To generate Shale data model from JSON Schema use `Shale::Schema.from_json`.
|
1392
|
+
You can pass `root_name: 'Foobar'` to change the name of the root type and
|
1393
|
+
`namespace_mapping: {}` to map schemas to Ruby modules:
|
1216
1394
|
|
1217
1395
|
```ruby
|
1218
1396
|
require 'shale/schema'
|
@@ -1223,7 +1401,11 @@ schema = <<~SCHEMA
|
|
1223
1401
|
"properties": {
|
1224
1402
|
"firstName": { "type": "string" },
|
1225
1403
|
"lastName": { "type": "string" },
|
1226
|
-
"address": {
|
1404
|
+
"address": { "$ref": "http://bar.com" }
|
1405
|
+
},
|
1406
|
+
"$defs": {
|
1407
|
+
"Address": {
|
1408
|
+
"$id": "http://bar.com",
|
1227
1409
|
"type": "object",
|
1228
1410
|
"properties": {
|
1229
1411
|
"street": { "type": "string" },
|
@@ -1234,38 +1416,53 @@ schema = <<~SCHEMA
|
|
1234
1416
|
}
|
1235
1417
|
SCHEMA
|
1236
1418
|
|
1237
|
-
Shale::Schema.from_json(
|
1419
|
+
Shale::Schema.from_json(
|
1420
|
+
[schema],
|
1421
|
+
root_name: 'Person',
|
1422
|
+
namespace_mapping: {
|
1423
|
+
nil => 'Api::Foo', # default schema (without ID)
|
1424
|
+
'http://bar.com' => 'Api::Bar',
|
1425
|
+
}
|
1426
|
+
)
|
1238
1427
|
|
1239
1428
|
# =>
|
1240
1429
|
#
|
1241
1430
|
# {
|
1242
|
-
# "address" => "
|
1431
|
+
# "api/bar/address" => "
|
1243
1432
|
# require 'shale'
|
1244
1433
|
#
|
1245
|
-
#
|
1246
|
-
#
|
1247
|
-
#
|
1434
|
+
# module Api
|
1435
|
+
# module Bar
|
1436
|
+
# class Address < Shale::Mapper
|
1437
|
+
# attribute :street, Shale::Type::String
|
1438
|
+
# attribute :city, Shale::Type::String
|
1248
1439
|
#
|
1249
|
-
#
|
1250
|
-
#
|
1251
|
-
#
|
1440
|
+
# json do
|
1441
|
+
# map 'street', to: :street
|
1442
|
+
# map 'city', to: :city
|
1443
|
+
# end
|
1444
|
+
# end
|
1252
1445
|
# end
|
1253
1446
|
# end
|
1254
1447
|
# ",
|
1255
|
-
# "person" => "
|
1448
|
+
# "api/foo/person" => "
|
1256
1449
|
# require 'shale'
|
1257
1450
|
#
|
1258
|
-
# require_relative 'address'
|
1451
|
+
# require_relative '../bar/address'
|
1259
1452
|
#
|
1260
|
-
#
|
1261
|
-
#
|
1262
|
-
#
|
1263
|
-
#
|
1453
|
+
# module Api
|
1454
|
+
# module Foo
|
1455
|
+
# class Person < Shale::Mapper
|
1456
|
+
# attribute :first_name, Shale::Type::String
|
1457
|
+
# attribute :last_name, Shale::Type::String
|
1458
|
+
# attribute :address, Api::Bar::Address
|
1264
1459
|
#
|
1265
|
-
#
|
1266
|
-
#
|
1267
|
-
#
|
1268
|
-
#
|
1460
|
+
# json do
|
1461
|
+
# map 'firstName', to: :first_name
|
1462
|
+
# map 'lastName', to: :last_name
|
1463
|
+
# map 'address', to: :address
|
1464
|
+
# end
|
1465
|
+
# end
|
1269
1466
|
# end
|
1270
1467
|
# end
|
1271
1468
|
# "
|
@@ -1275,7 +1472,7 @@ Shale::Schema.from_json([schema], root_name: 'Person')
|
|
1275
1472
|
You can also use a command line tool to do it:
|
1276
1473
|
|
1277
1474
|
```
|
1278
|
-
$ shaleb -c -i schema.json -r Person
|
1475
|
+
$ shaleb -c -i schema.json -r Person -m http://bar.com=Api::Bar,=Api::Foo
|
1279
1476
|
```
|
1280
1477
|
|
1281
1478
|
### Generating XML Schema
|
@@ -1346,22 +1543,39 @@ Shale::Schema::XMLGenerator.register_xml_type(MyEmailType, 'myEmailXMLType')
|
|
1346
1543
|
|
1347
1544
|
### Compiling XML Schema into Shale model
|
1348
1545
|
|
1349
|
-
To generate Shale data model from XML Schema use
|
1546
|
+
To generate Shale data model from XML Schema use `Shale::Schema.from_xml`.
|
1547
|
+
You can pass `namespace_mapping: {}` to map XML namespaces to Ruby modules:
|
1350
1548
|
|
1351
1549
|
```ruby
|
1352
1550
|
require 'shale/schema'
|
1353
1551
|
|
1354
|
-
|
1355
|
-
<xs:schema
|
1552
|
+
schema1 = <<~SCHEMA
|
1553
|
+
<xs:schema
|
1554
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
1555
|
+
xmlns:bar="http://bar.com"
|
1556
|
+
elementFormDefault="qualified"
|
1557
|
+
>
|
1558
|
+
<xs:import namespace="http://bar.com" />
|
1559
|
+
|
1356
1560
|
<xs:element name="Person" type="Person" />
|
1357
1561
|
|
1358
1562
|
<xs:complexType name="Person">
|
1359
1563
|
<xs:sequence>
|
1360
|
-
<xs:element name="
|
1361
|
-
<xs:element
|
1362
|
-
<xs:element name="Address" type="Address" />
|
1564
|
+
<xs:element name="Name" type="xs:string" />
|
1565
|
+
<xs:element ref="bar:Address" />
|
1363
1566
|
</xs:sequence>
|
1364
1567
|
</xs:complexType>
|
1568
|
+
</xs:schema>
|
1569
|
+
SCHEMA
|
1570
|
+
|
1571
|
+
schema2 = <<~SCHEMA
|
1572
|
+
<xs:schema
|
1573
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
1574
|
+
xmlns:bar="http://bar.com"
|
1575
|
+
targetNamespace="http://bar.com"
|
1576
|
+
elementFormDefault="qualified"
|
1577
|
+
>
|
1578
|
+
<xs:element name="Address" type="bar:Address" />
|
1365
1579
|
|
1366
1580
|
<xs:complexType name="Address">
|
1367
1581
|
<xs:sequence>
|
@@ -1372,42 +1586,55 @@ schema = <<~SCHEMA
|
|
1372
1586
|
</xs:schema>
|
1373
1587
|
SCHEMA
|
1374
1588
|
|
1375
|
-
Shale::Schema.from_xml(
|
1589
|
+
Shale::Schema.from_xml(
|
1590
|
+
[schema1, schema2],
|
1591
|
+
namespace_mapping: {
|
1592
|
+
nil => 'Api::Foo', # no namespace
|
1593
|
+
'http://bar.com' => 'Api::Bar',
|
1594
|
+
}
|
1595
|
+
)
|
1376
1596
|
|
1377
1597
|
# =>
|
1378
1598
|
#
|
1379
1599
|
# {
|
1380
|
-
# "address" => "
|
1600
|
+
# "api/bar/address" => "
|
1381
1601
|
# require 'shale'
|
1382
1602
|
#
|
1383
|
-
#
|
1384
|
-
#
|
1385
|
-
#
|
1603
|
+
# module Api
|
1604
|
+
# module Bar
|
1605
|
+
# class Address < Shale::Mapper
|
1606
|
+
# attribute :street, Shale::Type::String
|
1607
|
+
# attribute :city, Shale::Type::String
|
1386
1608
|
#
|
1387
|
-
#
|
1388
|
-
#
|
1609
|
+
# xml do
|
1610
|
+
# root 'Address'
|
1611
|
+
# namespace 'http://bar.com', 'bar'
|
1389
1612
|
#
|
1390
|
-
#
|
1391
|
-
#
|
1613
|
+
# map_element 'Street', to: :street
|
1614
|
+
# map_element 'City', to: :city
|
1615
|
+
# end
|
1616
|
+
# end
|
1392
1617
|
# end
|
1393
1618
|
# end
|
1394
1619
|
# ",
|
1395
|
-
# "person" => "
|
1620
|
+
# "api/foo/person" => "
|
1396
1621
|
# require 'shale'
|
1397
1622
|
#
|
1398
|
-
# require_relative 'address'
|
1623
|
+
# require_relative '../bar/address'
|
1399
1624
|
#
|
1400
|
-
#
|
1401
|
-
#
|
1402
|
-
#
|
1403
|
-
#
|
1625
|
+
# module Api
|
1626
|
+
# module Foo
|
1627
|
+
# class Person < Shale::Mapper
|
1628
|
+
# attribute :name, Shale::Type::String
|
1629
|
+
# attribute :address, Api::Bar::Address
|
1404
1630
|
#
|
1405
|
-
#
|
1406
|
-
#
|
1631
|
+
# xml do
|
1632
|
+
# root 'Person'
|
1407
1633
|
#
|
1408
|
-
#
|
1409
|
-
#
|
1410
|
-
#
|
1634
|
+
# map_element 'Name', to: :name
|
1635
|
+
# map_element 'Address', to: :address, prefix: 'bar', namespace: 'http://bar.com'
|
1636
|
+
# end
|
1637
|
+
# end
|
1411
1638
|
# end
|
1412
1639
|
# end
|
1413
1640
|
# "
|
@@ -1417,7 +1644,7 @@ Shale::Schema.from_xml([schema])
|
|
1417
1644
|
You can also use a command line tool to do it:
|
1418
1645
|
|
1419
1646
|
```
|
1420
|
-
$ shaleb -c -f xml -i schema.xml
|
1647
|
+
$ shaleb -c -f xml -i schema.xml -m http://bar.com=Api::Bar,=Api::Foo
|
1421
1648
|
```
|
1422
1649
|
|
1423
1650
|
## Contributing
|
data/exe/shaleb
CHANGED
@@ -36,8 +36,8 @@ ARGV << '-h' if ARGV.empty?
|
|
36
36
|
OptionParser.new do |opts|
|
37
37
|
opts.banner = <<~BANNER
|
38
38
|
Usage: shaleb [options]
|
39
|
-
example generate schema from Shale model: shaleb -g -i data_model.rb -
|
40
|
-
example generate Shale model from schema: shaleb -c -i schema1.json,schema2.json -
|
39
|
+
example generate schema from Shale model: shaleb -g -i data_model.rb -r MyRoot
|
40
|
+
example generate Shale model from schema: shaleb -c -i schema1.json,schema2.json -r MyRoot
|
41
41
|
BANNER
|
42
42
|
|
43
43
|
opts.on('-g', '--generate', 'generate schema from Shale model')
|
@@ -47,6 +47,7 @@ OptionParser.new do |opts|
|
|
47
47
|
opts.on('-r ROOT', '--root ROOT', 'Shale model class name')
|
48
48
|
opts.on('-f FORMAT', '--format FORMAT', 'Schema format: JSON (default), XML')
|
49
49
|
opts.on('-p', '--pretty', 'Pretty print generated schema')
|
50
|
+
opts.on('-m MAPPING', '--mapping', Array, 'Namespace mapping')
|
50
51
|
|
51
52
|
opts.on('-v', '--version', 'Show version') do
|
52
53
|
puts "shaleb version #{Shale::VERSION}"
|
@@ -71,11 +72,24 @@ if params[:compile]
|
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
75
|
+
if params[:mapping]
|
76
|
+
namespace_mapping = params[:mapping]
|
77
|
+
.to_h { |e| [*e.split('='), nil][0, 2] }
|
78
|
+
.transform_keys { |key| key.empty? ? nil : key }
|
79
|
+
end
|
80
|
+
|
74
81
|
if params[:format] == 'xml'
|
75
82
|
load_xml_parser
|
76
|
-
models = Shale::Schema.from_xml(
|
83
|
+
models = Shale::Schema.from_xml(
|
84
|
+
schemas,
|
85
|
+
namespace_mapping: namespace_mapping
|
86
|
+
)
|
77
87
|
else
|
78
|
-
models = Shale::Schema.from_json(
|
88
|
+
models = Shale::Schema.from_json(
|
89
|
+
schemas,
|
90
|
+
root_name: params[:root],
|
91
|
+
namespace_mapping: namespace_mapping
|
92
|
+
)
|
79
93
|
end
|
80
94
|
|
81
95
|
if params[:output]
|
@@ -84,6 +98,7 @@ if params[:compile]
|
|
84
98
|
|
85
99
|
models.each do |name, model|
|
86
100
|
output_path = File.join(dir, "#{name}.rb")
|
101
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
87
102
|
File.write(output_path, model)
|
88
103
|
end
|
89
104
|
else
|
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
|
data/lib/shale/error.rb
CHANGED
@@ -38,6 +38,18 @@ module Shale
|
|
38
38
|
Shale.xml_adapter = Shale::Adapter::Ox
|
39
39
|
MSG
|
40
40
|
|
41
|
+
# Error message displayed when CSV adapter is not set
|
42
|
+
# @api private
|
43
|
+
CSV_ADAPTER_NOT_SET_MESSAGE = <<~MSG
|
44
|
+
CSV Adapter is not set.
|
45
|
+
To use Shale with CSV documents you have to install parser and set adapter.
|
46
|
+
|
47
|
+
# To use csv gem:
|
48
|
+
# Make sure csv is installed eg. execute: gem install csv
|
49
|
+
require 'shale/adapter/csv'
|
50
|
+
Shale.csv_adapter = Shale::Adapter::CSV
|
51
|
+
MSG
|
52
|
+
|
41
53
|
# Error for assigning value to not existing attribute
|
42
54
|
#
|
43
55
|
# @api private
|
@@ -53,10 +65,16 @@ module Shale
|
|
53
65
|
end
|
54
66
|
end
|
55
67
|
|
68
|
+
# Shale base error class
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
class ShaleError < StandardError
|
72
|
+
end
|
73
|
+
|
56
74
|
# Error for trying to assign not callable object as an attribute's default
|
57
75
|
#
|
58
76
|
# @api private
|
59
|
-
class DefaultNotCallableError <
|
77
|
+
class DefaultNotCallableError < ShaleError
|
60
78
|
# Initialize error object
|
61
79
|
#
|
62
80
|
# @param [String] record
|
@@ -71,36 +89,42 @@ module Shale
|
|
71
89
|
# Error for passing incorrect model type
|
72
90
|
#
|
73
91
|
# @api private
|
74
|
-
class IncorrectModelError <
|
92
|
+
class IncorrectModelError < ShaleError
|
75
93
|
end
|
76
94
|
|
77
95
|
# Error for passing incorrect arguments to map functions
|
78
96
|
#
|
79
97
|
# @api private
|
80
|
-
class IncorrectMappingArgumentsError <
|
98
|
+
class IncorrectMappingArgumentsError < ShaleError
|
99
|
+
end
|
100
|
+
|
101
|
+
# Error for using incorrect type
|
102
|
+
#
|
103
|
+
# @api private
|
104
|
+
class NotAShaleMapperError < ShaleError
|
81
105
|
end
|
82
106
|
|
83
|
-
#
|
107
|
+
# Raised when receiver attribute is not defined
|
84
108
|
#
|
85
109
|
# @api private
|
86
|
-
class
|
110
|
+
class AttributeNotDefinedError < ShaleError
|
87
111
|
end
|
88
112
|
|
89
113
|
# Schema compilation error
|
90
114
|
#
|
91
115
|
# @api private
|
92
|
-
class SchemaError <
|
116
|
+
class SchemaError < ShaleError
|
93
117
|
end
|
94
118
|
|
95
119
|
# Parsing error
|
96
120
|
#
|
97
121
|
# @api private
|
98
|
-
class ParseError <
|
122
|
+
class ParseError < ShaleError
|
99
123
|
end
|
100
124
|
|
101
125
|
# Adapter error
|
102
126
|
#
|
103
127
|
# @api private
|
104
|
-
class AdapterError <
|
128
|
+
class AdapterError < ShaleError
|
105
129
|
end
|
106
130
|
end
|