lutaml-model 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +4 -3
- data/README.adoc +424 -19
- data/lib/lutaml/model/config.rb +82 -1
- data/lib/lutaml/model/error/unknown_adapter_type_error.rb +16 -0
- data/lib/lutaml/model/error.rb +1 -0
- data/lib/lutaml/model/serialize.rb +4 -6
- data/lib/lutaml/model/type.rb +0 -24
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model.rb +2 -2
- metadata +3 -3
- data/lib/lutaml/model/type/json.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45fc67305626a2fe4d38db31804a618fd887a9855ff8ddb7ef2d0d0e8cc8b9b8
|
4
|
+
data.tar.gz: 7ffbc1f1b1958d05ebbf82889b1b54f032df48a4ed9052f3a963b896bfb43238
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37a4e64c1b61b6a1112329b18ea4bd9b544fe125859cd81a1054b162817e1ffb22e03f4168836ce8890e6f6cba6f137c78110522322c0a0fe6fde3e121c533d4
|
7
|
+
data.tar.gz: bd3bfb6600103c25034c3604fcdc83947d8eb3a14b23ec54e93186f66d273a5270a923394bd5f00e5caf3d58c9ff7c65efce9cd5f7a874ac22f4582711622d27
|
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2024-08-
|
3
|
+
# on 2024-08-19 03:44:26 UTC using RuboCop version 1.65.1.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -14,7 +14,7 @@ Gemspec/RequireMFA:
|
|
14
14
|
Exclude:
|
15
15
|
- 'lutaml-model.gemspec'
|
16
16
|
|
17
|
-
# Offense count:
|
17
|
+
# Offense count: 78
|
18
18
|
# This cop supports safe autocorrection (--autocorrect).
|
19
19
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
|
20
20
|
# URISchemes: http, https
|
@@ -28,6 +28,7 @@ Layout/LineLength:
|
|
28
28
|
- 'lib/lutaml/model/xml_adapter/ox_adapter.rb'
|
29
29
|
- 'lib/lutaml/model/xml_adapter/xml_document.rb'
|
30
30
|
- 'spec/lutaml/model/comparable_model_spec.rb'
|
31
|
+
- 'spec/lutaml/model/custom_serialization_spec.rb'
|
31
32
|
- 'spec/lutaml/model/delegation_spec.rb'
|
32
33
|
- 'spec/lutaml/model/schema/json_schema_spec.rb'
|
33
34
|
- 'spec/lutaml/model/serializable_spec.rb'
|
@@ -102,7 +103,7 @@ RSpec/ContextWording:
|
|
102
103
|
- 'spec/lutaml/model/xml_adapter/oga_adapter_spec.rb'
|
103
104
|
- 'spec/lutaml/model/xml_adapter/ox_adapter_spec.rb'
|
104
105
|
|
105
|
-
# Offense count:
|
106
|
+
# Offense count: 73
|
106
107
|
# Configuration parameters: CountAsOne.
|
107
108
|
RSpec/ExampleLength:
|
108
109
|
Max: 57
|
data/README.adoc
CHANGED
@@ -13,16 +13,13 @@ objects to and from various formats such as JSON, XML, YAML, and TOML. It uses
|
|
13
13
|
an adapter pattern to support multiple libraries for each format, providing
|
14
14
|
flexibility and extensibility for your data modeling needs.
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
NOTE: Lutaml::Model is designed to be mostly compatible with the data modeling
|
17
|
+
API of https://www.shalerb.org[Shale], an impressive Ruby data modeller.
|
18
|
+
Lutaml::Model is meant to address advanced needs not currently addressed by
|
19
|
+
Shale.
|
21
20
|
|
22
|
-
NOTE:
|
23
|
-
|
24
|
-
modeller. Lutaml::Model is meant to address needs that are not currently
|
25
|
-
addressed by Shale.
|
21
|
+
NOTE: Instructions on how to migrate from Shale to Lutaml::Model are provided in
|
22
|
+
<<migrate-from-shale>>.
|
26
23
|
|
27
24
|
|
28
25
|
== Data modeling in a nutshell
|
@@ -80,6 +77,7 @@ There are two ways to define a data model in Lutaml::Model:
|
|
80
77
|
* Inheriting from the `Lutaml::Model::Serializable` class
|
81
78
|
* Including the `Lutaml::Model::Serialize` module
|
82
79
|
|
80
|
+
[[define-through-inheritance]]
|
83
81
|
==== Definition through inheritance
|
84
82
|
|
85
83
|
The simplest way to define a model is to create a class that inherits from
|
@@ -98,6 +96,7 @@ class Kiln < Lutaml::Model::Serializable
|
|
98
96
|
end
|
99
97
|
----
|
100
98
|
|
99
|
+
[[define-through-inclusion]]
|
101
100
|
==== Definition through inclusion
|
102
101
|
|
103
102
|
If the model class already has a super class that it inherits from, the model
|
@@ -169,12 +168,6 @@ attribute :name_of_attribute, {symbol | string | class}
|
|
169
168
|
| `Boolean` | `:boolean` | `Lutaml::Model::Type::Boolean` | `Boolean`
|
170
169
|
| `Decimal` | `:decimal` | `Lutaml::Model::Type::Decimal` | `::BigDecimal`
|
171
170
|
| `Hash` | `:hash` | `Lutaml::Model::Type::Hash` | `::Hash`
|
172
|
-
| `Uuid` | `:uuid` | `Lutaml::Model::Type::Uuid` | `::String`
|
173
|
-
| `Symbol` | `:symbol` | `Lutaml::Model::Type::Symbol` | `Symbol`
|
174
|
-
| `Binary` | `:binary` | `Lutaml::Model::Type::Binary` | `Binary`
|
175
|
-
| `Url` | `:url` | `Lutaml::Model::Type::Url` | `::URI`
|
176
|
-
| `IpAddress` | `:ip_address` | `Lutaml::Model::Type::IpAddress` | `::IPAddr`
|
177
|
-
| `Json` | `:json` | `Lutaml::Model::Type::Json` | `::JSON`
|
178
171
|
|
179
172
|
|===
|
180
173
|
|
@@ -238,6 +231,7 @@ end
|
|
238
231
|
----
|
239
232
|
====
|
240
233
|
|
234
|
+
[[attribute-enumeration]]
|
241
235
|
=== Attribute as an enumeration
|
242
236
|
|
243
237
|
An attribute can be defined as an enumeration by using the `values` directive.
|
@@ -777,6 +771,7 @@ end
|
|
777
771
|
----
|
778
772
|
====
|
779
773
|
|
774
|
+
[[namespace-inherit]]
|
780
775
|
===== Namespace with `inherit` option
|
781
776
|
|
782
777
|
The `inherit` option is used at the element level to inherit the namespace from
|
@@ -838,7 +833,7 @@ end
|
|
838
833
|
----
|
839
834
|
====
|
840
835
|
|
841
|
-
|
836
|
+
[[mixed-content]]
|
842
837
|
==== Mixed content
|
843
838
|
|
844
839
|
===== General
|
@@ -859,6 +854,8 @@ To map this to Lutaml::Model we can use the `mixed` option in either way:
|
|
859
854
|
* when defining the model;
|
860
855
|
* when referencing the model.
|
861
856
|
|
857
|
+
NOTE: This feature is not supported by Shale.
|
858
|
+
|
862
859
|
|
863
860
|
===== Specifying the `mixed` option at `root`
|
864
861
|
|
@@ -1071,7 +1068,7 @@ end
|
|
1071
1068
|
----
|
1072
1069
|
====
|
1073
1070
|
|
1074
|
-
|
1071
|
+
[[separate-serialization-model]]
|
1075
1072
|
=== Separate serialization model
|
1076
1073
|
|
1077
1074
|
The `Serialize` module can be used to define only serialization mappings for a
|
@@ -1283,6 +1280,9 @@ end
|
|
1283
1280
|
----
|
1284
1281
|
====
|
1285
1282
|
|
1283
|
+
NOTE: The corresponding keyword used by Shale is `receiver:` instead of
|
1284
|
+
`delegate:`.
|
1285
|
+
|
1286
1286
|
|
1287
1287
|
==== Attribute serialization with custom methods
|
1288
1288
|
|
@@ -1365,7 +1365,7 @@ end
|
|
1365
1365
|
====
|
1366
1366
|
|
1367
1367
|
|
1368
|
-
|
1368
|
+
[[attribute-extraction]]
|
1369
1369
|
==== Attribute extraction
|
1370
1370
|
|
1371
1371
|
NOTE: This feature is for key-value data model serialization only.
|
@@ -1561,7 +1561,7 @@ serialization format.
|
|
1561
1561
|
You will need to specify the configuration for the adapter you want to use. The
|
1562
1562
|
easiest way is to copy and paste the following configuration into your code.
|
1563
1563
|
|
1564
|
-
The
|
1564
|
+
The configuration is as follows:
|
1565
1565
|
|
1566
1566
|
[source,ruby]
|
1567
1567
|
----
|
@@ -1579,6 +1579,21 @@ Lutaml::Model::Config.configure do |config|
|
|
1579
1579
|
end
|
1580
1580
|
----
|
1581
1581
|
|
1582
|
+
You can also provide the adapter type by using symbols like
|
1583
|
+
|
1584
|
+
[source,ruby]
|
1585
|
+
----
|
1586
|
+
require 'lutaml/model'
|
1587
|
+
|
1588
|
+
Lutaml::Model::Config.configure do |config|
|
1589
|
+
config.xml_adapter_type = :nokogiri # can be one of [:nokogiri, :ox, :oga]
|
1590
|
+
config.yaml_adapter_type = :standard_yaml
|
1591
|
+
config.json_adapter_type = :standard_json # can be one of [:standard_json, :multi_json]
|
1592
|
+
config.toml_adapter_type = :toml_rb # can be one of [:toml_rb, :tomlib]
|
1593
|
+
end
|
1594
|
+
----
|
1595
|
+
|
1596
|
+
NOTE: By default `yaml_adapter_type` and `json_adapter_type` are set to `:standard_yaml` and `:standard_json` respectively.
|
1582
1597
|
|
1583
1598
|
=== XML
|
1584
1599
|
|
@@ -1699,6 +1714,396 @@ Lutaml::Model::Config.configure do |config|
|
|
1699
1714
|
end
|
1700
1715
|
----
|
1701
1716
|
|
1717
|
+
|
1718
|
+
== Comparison with Shale
|
1719
|
+
|
1720
|
+
Lutaml::Model is a serialization library that is similar to Shale, but with some
|
1721
|
+
differences in implementation.
|
1722
|
+
|
1723
|
+
[cols="a,a,a,a",options="header"]
|
1724
|
+
|===
|
1725
|
+
| Feature | Lutaml::Model | Shale | Notes
|
1726
|
+
|
1727
|
+
| Data model definition
|
1728
|
+
|
|
1729
|
+
3 types:
|
1730
|
+
|
1731
|
+
* <<define-through-inheritance,Inherit from `Lutaml::Model::Serializable`>>
|
1732
|
+
* <<define-through-inclusion,Include `Lutaml::Model::Serialize`>>
|
1733
|
+
* <<separate-serialization-model,Separate serialization model class>>
|
1734
|
+
|
|
1735
|
+
2 types:
|
1736
|
+
|
1737
|
+
* Inherit from `Shale::Mapper`
|
1738
|
+
* Custom model class
|
1739
|
+
|
|
1740
|
+
|
1741
|
+
| Value types
|
1742
|
+
| `Lutaml::Model::Type` includes: `Integer`, `String`, `Float`, `Boolean`, `Date`, `DateTime`, `Time`, `Hash`.
|
1743
|
+
| `Shale::Type` includes: `Integer`, `String`, `Float`, `Boolean`, `Date`, `Time`.
|
1744
|
+
| Lutaml::Model supports the additional value types `DateTime` and `Hash`.
|
1745
|
+
|
1746
|
+
| Configuration
|
1747
|
+
| `Lutaml::Model::Config`
|
1748
|
+
| `Shale.{type}_adapter`
|
1749
|
+
| Lutaml::Model uses a configuration block to set the serialization adapters.
|
1750
|
+
|
1751
|
+
| Custom serialization methods
|
1752
|
+
| `:with`, on individual attributes
|
1753
|
+
| `:using`, on entire object/document
|
1754
|
+
| Lutaml::Model uses the `:with` keyword for custom serialization methods.
|
1755
|
+
|
1756
|
+
| Serialization formats
|
1757
|
+
| XML, YAML, JSON, TOML
|
1758
|
+
| XML, YAML, JSON, TOML, CSV
|
1759
|
+
| Lutaml::Model does not support CSV.
|
1760
|
+
|
1761
|
+
| Adapter support
|
1762
|
+
| XML (Nokogiri, Ox, Oga), YAML, JSON (JSON, MultiJson), TOML (Toml-rb, Tomlib)
|
1763
|
+
| XML (Nokogiri, Ox), YAML, JSON (JSON, MultiJson), TOML (Toml-rb, Tomlib), CSV
|
1764
|
+
| Lutaml::Model does not support CSV.
|
1765
|
+
|
1766
|
+
4+h| XML features
|
1767
|
+
|
1768
|
+
| XML mixed content support
|
1769
|
+
| Yes. Supports the following kind of XML through <<mixed-content,mixed content>> support.
|
1770
|
+
|
1771
|
+
[source,xml]
|
1772
|
+
----
|
1773
|
+
<description>My name is
|
1774
|
+
<bold>John Doe</bold>,
|
1775
|
+
and I'm <i>28</i>
|
1776
|
+
years old</description>
|
1777
|
+
----
|
1778
|
+
| No. Shale's `map_content` only supports the first text node.
|
1779
|
+
|
|
1780
|
+
|
1781
|
+
| XML namespace inheritance
|
1782
|
+
| Yes. Supports the <<namespace-inherit,`inherit`>> option to inherit the
|
1783
|
+
namespace from the root element.
|
1784
|
+
| No.
|
1785
|
+
|
|
1786
|
+
|
1787
|
+
4+h| Attribute features
|
1788
|
+
|
1789
|
+
| Attribute delegation
|
1790
|
+
| `:delegate` option to delegate attribute mappings to a model.
|
1791
|
+
| `:receiver` option to delegate attribute mappings to a model.
|
1792
|
+
|
|
1793
|
+
|
1794
|
+
| Enumerations
|
1795
|
+
| Yes. Supports enumerations as value types through the
|
1796
|
+
<<attribute-enumeration,`values:` option>>.
|
1797
|
+
| No.
|
1798
|
+
| Lutaml::Model supports enumerations as value types.
|
1799
|
+
|
1800
|
+
| Attribute extraction
|
1801
|
+
| Yes. Supports <<attribute-extraction,attribute extraction>> from key-value
|
1802
|
+
data models.
|
1803
|
+
| No.
|
1804
|
+
| Lutaml::Model supports attribute extraction from key-value data models.
|
1805
|
+
|
1806
|
+
|
1807
|
+
|===
|
1808
|
+
|
1809
|
+
|
1810
|
+
[[migrate-from-shale]]
|
1811
|
+
== Migration steps from Shale
|
1812
|
+
|
1813
|
+
The following sections provide a guide for migrating from Shale to Lutaml::Model.
|
1814
|
+
|
1815
|
+
=== Step 1: Replace inheritance class
|
1816
|
+
|
1817
|
+
`Lutaml::Model` uses `Lutaml::Model::Serializable` as the base inheritance class.
|
1818
|
+
|
1819
|
+
[source,ruby]
|
1820
|
+
----
|
1821
|
+
class Example < Lutaml::Model::Serializable
|
1822
|
+
# ...
|
1823
|
+
end
|
1824
|
+
----
|
1825
|
+
|
1826
|
+
[NOTE]
|
1827
|
+
====
|
1828
|
+
`Lutaml::Model` also supports an inclusion method as in the following example,
|
1829
|
+
which is not supported by Shale. This is useful for cases where you want to
|
1830
|
+
include the serialization methods in a class that already inherits from another
|
1831
|
+
class.
|
1832
|
+
|
1833
|
+
[source,ruby]
|
1834
|
+
----
|
1835
|
+
class Example
|
1836
|
+
include Lutaml::Model::Serialize
|
1837
|
+
# ...
|
1838
|
+
end
|
1839
|
+
----
|
1840
|
+
====
|
1841
|
+
|
1842
|
+
Shale uses `Shale::Mapper` as the base inheritance class.
|
1843
|
+
|
1844
|
+
[source,ruby]
|
1845
|
+
----
|
1846
|
+
class Example < Shale::Mapper
|
1847
|
+
# ...
|
1848
|
+
end
|
1849
|
+
----
|
1850
|
+
|
1851
|
+
Actions:
|
1852
|
+
|
1853
|
+
* Replace mentions of `Shale::Mapper` with `Lutaml::Model::Serializable`.
|
1854
|
+
* Potentially replace inheritance with inclusion for suitable cases.
|
1855
|
+
|
1856
|
+
|
1857
|
+
=== Step 2: Replace value type definitions
|
1858
|
+
|
1859
|
+
Value types in `Lutaml::Model` are under the `Lutaml::Model::Type` module.
|
1860
|
+
|
1861
|
+
[source,ruby]
|
1862
|
+
----
|
1863
|
+
class Example < Lutaml::Model::Serializable
|
1864
|
+
attribute :length, Lutaml::Model::Type::Integer
|
1865
|
+
attribute :description, Lutaml::Model::Type::String
|
1866
|
+
end
|
1867
|
+
----
|
1868
|
+
|
1869
|
+
[NOTE]
|
1870
|
+
====
|
1871
|
+
`Lutaml::Model` also supports specifying predefined value types as strings or
|
1872
|
+
symbols, which is not supported by Shale.
|
1873
|
+
|
1874
|
+
[source,ruby]
|
1875
|
+
----
|
1876
|
+
class Example < Lutaml::Model::Serializable
|
1877
|
+
attribute :length, :integer
|
1878
|
+
attribute :description, "String"
|
1879
|
+
end
|
1880
|
+
----
|
1881
|
+
====
|
1882
|
+
|
1883
|
+
Value types in Shale are under the `Shale::Type` module.
|
1884
|
+
|
1885
|
+
[source,ruby]
|
1886
|
+
----
|
1887
|
+
class Example < Shale::Mapper
|
1888
|
+
attribute :length, Shale::Type::Integer
|
1889
|
+
attribute :description, Shale::Type::String
|
1890
|
+
end
|
1891
|
+
----
|
1892
|
+
|
1893
|
+
Action:
|
1894
|
+
|
1895
|
+
* Replace mentions of `Shale::Type` with `Lutaml::Model::Type`.
|
1896
|
+
* Potentially replace value type definitions with strings or symbols.
|
1897
|
+
|
1898
|
+
|
1899
|
+
=== Step 3: Configure serialization adapters
|
1900
|
+
|
1901
|
+
`Lutaml::Model` uses a configuration block to set the serialization adapters.
|
1902
|
+
|
1903
|
+
[source,ruby]
|
1904
|
+
----
|
1905
|
+
require 'lutaml/model/xml_adapter/nokogiri_adapter'
|
1906
|
+
Lutaml::Model::Config.configure do |config|
|
1907
|
+
config.xml_adapter = Lutaml::Model::XmlAdapter::NokogiriAdapter
|
1908
|
+
end
|
1909
|
+
----
|
1910
|
+
|
1911
|
+
The equivalent for Shale is this:
|
1912
|
+
|
1913
|
+
[source,ruby]
|
1914
|
+
----
|
1915
|
+
require 'shale/adapter/nokogiri'
|
1916
|
+
Shale.xml_adapter = Shale::Adapter::Nokogiri
|
1917
|
+
----
|
1918
|
+
|
1919
|
+
|
1920
|
+
Here are places that this code may reside at:
|
1921
|
+
|
1922
|
+
* If your code is a standalone Ruby script, this code will be present in your code.
|
1923
|
+
* If your code is organized in a Ruby gem, this code will be specified somewhere referenced by `lib/your_gem_name.rb`.
|
1924
|
+
* If your code contains tests or specs, they will be in the test setup file, e.g. RSpec `spec/spec_helper.rb`.
|
1925
|
+
|
1926
|
+
Actions:
|
1927
|
+
|
1928
|
+
* Replace the Shale configuration block with the `Lutaml::Model::Config`
|
1929
|
+
configuration block.
|
1930
|
+
|
1931
|
+
* Replace the Shale adapter with the `Lutaml::Model` adapter.
|
1932
|
+
|
1933
|
+
|
1934
|
+
|
1935
|
+
=== Step 4: Rewrite custom serialization methods
|
1936
|
+
|
1937
|
+
There is an implementation difference between Lutaml::Model and Shale for custom
|
1938
|
+
serialization methods.
|
1939
|
+
|
1940
|
+
Custom serialization methods in `Lutaml::Model` map to individual attributes.
|
1941
|
+
|
1942
|
+
For custom serialization methods, Lutaml::Model uses the `:with` keyword
|
1943
|
+
instead of the `:using` keyword used by Shale.
|
1944
|
+
|
1945
|
+
[source,ruby]
|
1946
|
+
----
|
1947
|
+
class Example < Lutaml::Model::Serializable
|
1948
|
+
attribute :name, :string
|
1949
|
+
attribute :size, :integer
|
1950
|
+
attribute :color, :string
|
1951
|
+
attribute :description, :string
|
1952
|
+
|
1953
|
+
json do
|
1954
|
+
map "name", to: :name, with: { to: :name_to_json, from: :name_from_json }
|
1955
|
+
map "size", to: :size
|
1956
|
+
map "color", to: :color,
|
1957
|
+
with: { to: :color_to_json, from: :color_from_json }
|
1958
|
+
map "description", to: :description,
|
1959
|
+
with: { to: :description_to_json, from: :description_from_json }
|
1960
|
+
end
|
1961
|
+
|
1962
|
+
xml do
|
1963
|
+
root "CustomSerialization"
|
1964
|
+
map_element "Name", to: :name,
|
1965
|
+
with: { to: :name_to_xml, from: :name_from_xml }
|
1966
|
+
map_attribute "Size", to: :size
|
1967
|
+
map_element "Color", to: :color,
|
1968
|
+
with: { to: :color_to_xml, from: :color_from_xml }
|
1969
|
+
map_content to: :description,
|
1970
|
+
with: { to: :description_to_xml,
|
1971
|
+
from: :description_from_xml }
|
1972
|
+
end
|
1973
|
+
|
1974
|
+
def name_to_json(_model, value)
|
1975
|
+
"JSON Masterpiece: #{value}"
|
1976
|
+
end
|
1977
|
+
|
1978
|
+
def name_from_json(_model, doc)
|
1979
|
+
doc["name"].sub(/^JSON Masterpiece: /, "")
|
1980
|
+
end
|
1981
|
+
|
1982
|
+
def color_to_json(_model, value)
|
1983
|
+
value.upcase
|
1984
|
+
end
|
1985
|
+
|
1986
|
+
def color_from_json(_model, doc)
|
1987
|
+
doc["color"].downcase
|
1988
|
+
end
|
1989
|
+
|
1990
|
+
def description_to_json(_model, value)
|
1991
|
+
"JSON Description: #{value}"
|
1992
|
+
end
|
1993
|
+
|
1994
|
+
def description_from_json(_model, doc)
|
1995
|
+
doc["description"].sub(/^JSON Description: /, "")
|
1996
|
+
end
|
1997
|
+
|
1998
|
+
def name_to_xml(_model, value)
|
1999
|
+
"XML Masterpiece: #{value}"
|
2000
|
+
end
|
2001
|
+
|
2002
|
+
def name_from_xml(_model, value)
|
2003
|
+
value.sub(/^XML Masterpiece: /, "")
|
2004
|
+
end
|
2005
|
+
|
2006
|
+
def color_to_xml(_model, value)
|
2007
|
+
value.upcase
|
2008
|
+
end
|
2009
|
+
|
2010
|
+
def color_from_xml(_model, value)
|
2011
|
+
value.downcase
|
2012
|
+
end
|
2013
|
+
|
2014
|
+
def description_to_xml(_model, value)
|
2015
|
+
"XML Description: #{value}"
|
2016
|
+
end
|
2017
|
+
|
2018
|
+
def description_from_xml(_model, value)
|
2019
|
+
value.sub(/^XML Description: /, "")
|
2020
|
+
end
|
2021
|
+
end
|
2022
|
+
----
|
2023
|
+
|
2024
|
+
Custom serialization methods in Shale do not map to specific attributes, but
|
2025
|
+
allow the user to specify where the data goes.
|
2026
|
+
|
2027
|
+
[source,ruby]
|
2028
|
+
----
|
2029
|
+
class Example < Shale::Mapper
|
2030
|
+
attribute :name, Shale::Type::String
|
2031
|
+
attribute :size, Shale::Type::Integer
|
2032
|
+
attribute :color, Shale::Type::String
|
2033
|
+
attribute :description, Shale::Type::String
|
2034
|
+
|
2035
|
+
json do
|
2036
|
+
map "name", using: { from: :name_from_json, to: :name_to_json }
|
2037
|
+
map "size", to: :size
|
2038
|
+
map "color", using: { from: :color_from_json, to: :color_to_json }
|
2039
|
+
map "description", to: :description, using: { from: :description_from_json, to: :description_to_json }
|
2040
|
+
end
|
2041
|
+
|
2042
|
+
xml do
|
2043
|
+
root "CustomSerialization"
|
2044
|
+
map_element "Name", using: { from: :name_from_xml, to: :name_to_xml }
|
2045
|
+
map_attribute "Size", to: :size
|
2046
|
+
map_element "Color", using: { from: :color_from_xml, to: :color_to_xml }
|
2047
|
+
map_content to: :description, using: { from: :description_from_xml, to: :description_to_xml }
|
2048
|
+
end
|
2049
|
+
|
2050
|
+
def name_to_json(model, doc)
|
2051
|
+
doc['name'] = "JSON Masterpiece: #{model.name}"
|
2052
|
+
end
|
2053
|
+
|
2054
|
+
def name_from_json(model, value)
|
2055
|
+
model.name = value.sub(/^JSON Masterpiece: /, "")
|
2056
|
+
end
|
2057
|
+
|
2058
|
+
def color_to_json(model, doc)
|
2059
|
+
doc['color'] = model.color.upcase
|
2060
|
+
end
|
2061
|
+
|
2062
|
+
def color_from_json(model, doc)
|
2063
|
+
model.color = doc['color'].downcase
|
2064
|
+
end
|
2065
|
+
|
2066
|
+
def description_to_json(model, doc)
|
2067
|
+
doc['description'] = "JSON Description: #{model.description}"
|
2068
|
+
end
|
2069
|
+
|
2070
|
+
def description_from_json(model, doc)
|
2071
|
+
model.description = doc['description'].sub(/^JSON Description: /, "")
|
2072
|
+
end
|
2073
|
+
|
2074
|
+
def name_from_xml(model, node)
|
2075
|
+
model.name = node.text.sub(/^XML Masterpiece: /, "")
|
2076
|
+
end
|
2077
|
+
|
2078
|
+
def name_to_xml(model, parent, doc)
|
2079
|
+
name_element = doc.create_element('Name')
|
2080
|
+
doc.add_text(name_element, model.street.to_s)
|
2081
|
+
doc.add_element(parent, name_element)
|
2082
|
+
end
|
2083
|
+
end
|
2084
|
+
----
|
2085
|
+
|
2086
|
+
NOTE: There are cases where the Shale implementation of custom methods work
|
2087
|
+
differently from the Lutaml::Model implementation. In these cases, you will need
|
2088
|
+
to adjust the custom methods accordingly.
|
2089
|
+
|
2090
|
+
Actions:
|
2091
|
+
|
2092
|
+
* Replace the `using` keyword with the `with` keyword.
|
2093
|
+
* Adjust the custom methods.
|
2094
|
+
|
2095
|
+
|
2096
|
+
== About LutaML
|
2097
|
+
|
2098
|
+
The name "LutaML" is pronounced as "Looh-tah-mel".
|
2099
|
+
|
2100
|
+
The name "LutaML" comes from the Latin word for clay, "Lutum", and "ML"
|
2101
|
+
for "Markup Language". Just as clay can be molded and modeled into beautiful and
|
2102
|
+
practical end products, the Lutaml::Model gem is used for data modeling,
|
2103
|
+
allowing you to shape and structure your data into useful forms.
|
2104
|
+
|
2105
|
+
|
2106
|
+
|
1702
2107
|
== License and Copyright
|
1703
2108
|
|
1704
2109
|
This project is licensed under the BSD 2-clause License.
|
data/lib/lutaml/model/config.rb
CHANGED
@@ -3,11 +3,92 @@ module Lutaml
|
|
3
3
|
module Config
|
4
4
|
extend self
|
5
5
|
|
6
|
-
|
6
|
+
# Default values are set for these so the readers are defined below
|
7
|
+
attr_writer :json_adapter, :yaml_adapter
|
8
|
+
|
9
|
+
attr_accessor :xml_adapter, :toml_adapter
|
10
|
+
|
11
|
+
AVAILABLE_FORMATS = %i[xml json yaml toml].freeze
|
7
12
|
|
8
13
|
def configure
|
9
14
|
yield self
|
10
15
|
end
|
16
|
+
|
17
|
+
# This will generate the following methods
|
18
|
+
#
|
19
|
+
# xml_adapter_type=
|
20
|
+
# @params:
|
21
|
+
# one of [:nokogiri, :ox, :oga]
|
22
|
+
# @example
|
23
|
+
# Lutaml::Model::Config.xml_adapter = :nokogiri
|
24
|
+
#
|
25
|
+
# json_adapter_type=
|
26
|
+
# @params:
|
27
|
+
# one of [:standard_json, :multi_json]
|
28
|
+
# if not set, :standard_json will be used by default
|
29
|
+
# @example
|
30
|
+
# Lutaml::Model::Config.json_adapter = :standard_json
|
31
|
+
#
|
32
|
+
# yaml_adapter_type=
|
33
|
+
# @params:
|
34
|
+
# one of [:standard_yaml]
|
35
|
+
# if not set, :standard_yaml will be used by default
|
36
|
+
# @example
|
37
|
+
# Lutaml::Model::Config.yaml_adapter = :standard_yaml
|
38
|
+
#
|
39
|
+
# toml_adapter_type=
|
40
|
+
# @params
|
41
|
+
# one of [:tomlib, :toml_rb]
|
42
|
+
# @example
|
43
|
+
# Lutaml::Model::Config.toml_adapter = :tomlib
|
44
|
+
AVAILABLE_FORMATS.each do |adapter_name|
|
45
|
+
define_method(:"#{adapter_name}_adapter_type=") do |type_name|
|
46
|
+
adapter = "#{adapter_name}_adapter"
|
47
|
+
type = "#{type_name}_adapter"
|
48
|
+
|
49
|
+
begin
|
50
|
+
adapter_file = File.join(adapter, type)
|
51
|
+
require_relative adapter_file
|
52
|
+
rescue LoadError
|
53
|
+
raise(
|
54
|
+
Lutaml::Model::UnknownAdapterTypeError.new(
|
55
|
+
adapter_name,
|
56
|
+
type_name,
|
57
|
+
),
|
58
|
+
cause: nil,
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
instance_variable_set(
|
63
|
+
:"@#{adapter}",
|
64
|
+
Lutaml::Model.const_get(to_class_name(adapter))
|
65
|
+
.const_get(to_class_name(type)),
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return JSON adapter. By default StandardJsonAdapter is used
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# Lutaml::Model::Config.json_adapter
|
74
|
+
# # => Lutaml::Model::YamlAdapter::StandardJsonAdapter
|
75
|
+
def json_adapter
|
76
|
+
@json_adapter || Lutaml::Model::JsonAdapter::StandardJsonAdapter
|
77
|
+
end
|
78
|
+
|
79
|
+
# Return YAML adapter. By default StandardYamlAdapter is used
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# Lutaml::Model::Config.yaml_adapter
|
83
|
+
# # => Lutaml::Model::YamlAdapter::StandardYamlAdapter
|
84
|
+
def yaml_adapter
|
85
|
+
@yaml_adapter || Lutaml::Model::YamlAdapter::StandardYamlAdapter
|
86
|
+
end
|
87
|
+
|
88
|
+
# @api private
|
89
|
+
def to_class_name(str)
|
90
|
+
str.to_s.split("_").map(&:capitalize).join
|
91
|
+
end
|
11
92
|
end
|
12
93
|
end
|
13
94
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Lutaml
|
2
|
+
module Model
|
3
|
+
class UnknownAdapterTypeError < Error
|
4
|
+
def initialize(adapter_name, type_name)
|
5
|
+
@adapter_name = adapter_name
|
6
|
+
@type_name = type_name
|
7
|
+
|
8
|
+
super()
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"Unknown type: `#{@type_name}` for `#{@adapter_name}` adapter"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/lutaml/model/error.rb
CHANGED
@@ -13,8 +13,6 @@ require_relative "comparable_model"
|
|
13
13
|
module Lutaml
|
14
14
|
module Model
|
15
15
|
module Serialize
|
16
|
-
FORMATS = %i[xml json yaml toml].freeze
|
17
|
-
|
18
16
|
include ComparableModel
|
19
17
|
|
20
18
|
def self.included(base)
|
@@ -73,7 +71,7 @@ module Lutaml
|
|
73
71
|
attr.options[:values].include?(value)
|
74
72
|
end
|
75
73
|
|
76
|
-
|
74
|
+
Lutaml::Model::Config::AVAILABLE_FORMATS.each do |format|
|
77
75
|
define_method(format) do |&block|
|
78
76
|
klass = format == :xml ? XmlMapping : KeyValueMapping
|
79
77
|
mappings[format] = klass.new
|
@@ -432,14 +430,14 @@ module Lutaml
|
|
432
430
|
end
|
433
431
|
|
434
432
|
def key_exist?(hash, key)
|
435
|
-
hash.key?(key
|
433
|
+
hash.key?(key.to_sym) || hash.key?(key.to_s)
|
436
434
|
end
|
437
435
|
|
438
436
|
def key_value(hash, key)
|
439
|
-
hash[key
|
437
|
+
hash[key.to_sym] || hash[key.to_s]
|
440
438
|
end
|
441
439
|
|
442
|
-
|
440
|
+
Lutaml::Model::Config::AVAILABLE_FORMATS.each do |format|
|
443
441
|
define_method(:"to_#{format}") do |options = {}|
|
444
442
|
validate
|
445
443
|
adapter = Lutaml::Model::Config.public_send(:"#{format}_adapter")
|
data/lib/lutaml/model/type.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
require "date"
|
2
2
|
require "bigdecimal"
|
3
|
-
require "securerandom"
|
4
|
-
require "uri"
|
5
|
-
require "ipaddr"
|
6
3
|
|
7
4
|
module Lutaml
|
8
5
|
module Model
|
@@ -20,12 +17,6 @@ module Lutaml
|
|
20
17
|
Boolean
|
21
18
|
Decimal
|
22
19
|
Hash
|
23
|
-
Uuid
|
24
|
-
Symbol
|
25
|
-
Binary
|
26
|
-
Url
|
27
|
-
IpAddress
|
28
|
-
Json
|
29
20
|
).each do |t|
|
30
21
|
class_eval <<~HEREDOC, __FILE__, __LINE__ + 1
|
31
22
|
class #{t} # class Integer
|
@@ -72,18 +63,6 @@ module Lutaml
|
|
72
63
|
BigDecimal(value.to_s)
|
73
64
|
when "Hash"
|
74
65
|
normalize_hash(Hash(value))
|
75
|
-
when "Uuid"
|
76
|
-
UUID_REGEX.match?(value) ? value : SecureRandom.uuid
|
77
|
-
when "Symbol"
|
78
|
-
value.to_sym
|
79
|
-
when "Binary"
|
80
|
-
value.force_encoding("BINARY")
|
81
|
-
when "Url"
|
82
|
-
URI.parse(value.to_s)
|
83
|
-
when "IpAddress"
|
84
|
-
IPAddr.new(value.to_s)
|
85
|
-
when "Json"
|
86
|
-
Json.cast(value)
|
87
66
|
else
|
88
67
|
value
|
89
68
|
end
|
@@ -107,8 +86,6 @@ module Lutaml
|
|
107
86
|
value.to_s("F")
|
108
87
|
when "Hash"
|
109
88
|
Hash(value)
|
110
|
-
when "Json"
|
111
|
-
value.to_json
|
112
89
|
else
|
113
90
|
value.to_s
|
114
91
|
end
|
@@ -145,4 +122,3 @@ end
|
|
145
122
|
|
146
123
|
require_relative "type/time_without_date"
|
147
124
|
require_relative "type/date_time"
|
148
|
-
require_relative "type/json"
|
data/lib/lutaml/model/version.rb
CHANGED
data/lib/lutaml/model.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
require_relative "model/version"
|
4
4
|
require_relative "model/type"
|
5
5
|
require_relative "model/serializable"
|
6
|
-
require_relative "model/json_adapter"
|
7
|
-
require_relative "model/yaml_adapter"
|
6
|
+
require_relative "model/json_adapter/standard_json_adapter"
|
7
|
+
require_relative "model/yaml_adapter/standard_yaml_adapter"
|
8
8
|
require_relative "model/xml_adapter"
|
9
9
|
require_relative "model/toml_adapter"
|
10
10
|
require_relative "model/error"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lutaml-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- lib/lutaml/model/config.rb
|
57
57
|
- lib/lutaml/model/error.rb
|
58
58
|
- lib/lutaml/model/error/invalid_value_error.rb
|
59
|
+
- lib/lutaml/model/error/unknown_adapter_type_error.rb
|
59
60
|
- lib/lutaml/model/json_adapter.rb
|
60
61
|
- lib/lutaml/model/json_adapter/json_document.rb
|
61
62
|
- lib/lutaml/model/json_adapter/json_object.rb
|
@@ -80,7 +81,6 @@ files:
|
|
80
81
|
- lib/lutaml/model/toml_adapter/tomlib_adapter.rb
|
81
82
|
- lib/lutaml/model/type.rb
|
82
83
|
- lib/lutaml/model/type/date_time.rb
|
83
|
-
- lib/lutaml/model/type/json.rb
|
84
84
|
- lib/lutaml/model/type/time_without_date.rb
|
85
85
|
- lib/lutaml/model/version.rb
|
86
86
|
- lib/lutaml/model/xml_adapter.rb
|
@@ -1,34 +0,0 @@
|
|
1
|
-
require "json"
|
2
|
-
|
3
|
-
module Lutaml
|
4
|
-
module Model
|
5
|
-
module Type
|
6
|
-
# JSON representation
|
7
|
-
class Json
|
8
|
-
attr_reader :value
|
9
|
-
|
10
|
-
def initialize(value)
|
11
|
-
@value = value
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_json(*_args)
|
15
|
-
@value.to_json
|
16
|
-
end
|
17
|
-
|
18
|
-
def ==(other)
|
19
|
-
@value == (other.is_a?(::Hash) ? other : other.value)
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.cast(value)
|
23
|
-
return value if value.is_a?(self) || value.nil?
|
24
|
-
|
25
|
-
new(::JSON.parse(value))
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.serialize(value)
|
29
|
-
value.to_json
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|