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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55348c33e2e23ce7c53c33e588621b8e73df49c5ca4e82e70c8216ad8f0cc6ab
4
- data.tar.gz: dd39d10a7f036596de8bce7f154197d446d065c76deee5a0b334522b8bbfdcea
3
+ metadata.gz: 45fc67305626a2fe4d38db31804a618fd887a9855ff8ddb7ef2d0d0e8cc8b9b8
4
+ data.tar.gz: 7ffbc1f1b1958d05ebbf82889b1b54f032df48a4ed9052f3a963b896bfb43238
5
5
  SHA512:
6
- metadata.gz: 46d78508e5cd397bf19c79c4dfba9bb49835945ae6ae83744588bc134c7809988716ea83c2f83485efdf50bf4a31e8be4daafbf6ada78a22dbfa90e14def72ba
7
- data.tar.gz: 05005dc4d4e6309913e706f38bf925c0ac77533728b34b89f8a69c901ea728d53bddf163e377ec7638be145ebf7bf7eb77f2d3c3ff078d7e7feb9ad6e52ff14f
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-17 14:46:05 UTC using RuboCop version 1.64.1.
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: 77
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: 72
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
- The name "LutaML" comes from the Latin word for clay, "Lutum", and "ML"
17
- for Markup Language. Just as clay can be molded and modeled into beautiful and
18
- practical end products, the Lutaml::Model gem is used for data modeling,
19
- allowing you to shape and structure your data into useful forms.
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: Lutaml::Model is designed to be compatible with the
23
- https://www.shalerb.org[Shale] data modeling API. Shale is an amazing Ruby data
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 default configuration is as follows:
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.
@@ -3,11 +3,92 @@ module Lutaml
3
3
  module Config
4
4
  extend self
5
5
 
6
- attr_accessor :xml_adapter, :json_adapter, :yaml_adapter, :toml_adapter
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
@@ -6,3 +6,4 @@ module Lutaml
6
6
  end
7
7
 
8
8
  require_relative "error/invalid_value_error"
9
+ require_relative "error/unknown_adapter_type_error"
@@ -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
- FORMATS.each do |format|
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) || hash.key?(key.to_sym) || hash.key?(key.to_s)
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] || hash[key.to_sym] || hash[key.to_s]
437
+ hash[key.to_sym] || hash[key.to_s]
440
438
  end
441
439
 
442
- FORMATS.each do |format|
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")
@@ -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"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Model
5
- VERSION = "0.3.5"
5
+ VERSION = "0.3.6"
6
6
  end
7
7
  end
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.5
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-18 00:00:00.000000000 Z
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