lutaml-model 0.6.3 → 0.6.4
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/.rubocop_todo.yml +4 -5
- data/Gemfile +1 -0
- data/README.adoc +243 -40
- data/lib/lutaml/model/error/liquid_not_enabled_error.rb +9 -0
- data/lib/lutaml/model/error.rb +1 -0
- data/lib/lutaml/model/liquefiable.rb +15 -2
- data/lib/lutaml/model/serialize.rb +0 -2
- data/lib/lutaml/model/version.rb +1 -1
- data/spec/fixtures/liquid_templates/_ceramic.liquid +6 -0
- data/spec/fixtures/liquid_templates/_ceramics.liquid +3 -0
- data/spec/fixtures/liquid_templates/_ceramics_in_one.liquid +4 -0
- data/spec/lutaml/model/liquefiable_spec.rb +152 -14
- data/spec/spec_helper.rb +1 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16b8569b5f2b450dfa8218c1c55a2175f154790220a54536bc9acbf6bc718312
|
4
|
+
data.tar.gz: d9d62e793690a72856e2663a67eb4eeb9cd8b909a861a91b093d8b849674a983
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e491d76d913445b9929b4e1939becc31c4b1ccb656aeaaa3e83caa20bf3c5e53142c3cc45f1a82b0a85d4b7111ab6994d5a5c03588c4f42dd8f76d101c95db0
|
7
|
+
data.tar.gz: e18a44f0047929b93c2bc66c82f8942d3cf48818c6597722bba0b78107c2630aa59f84b3b4034a105155d889e64fa7e8f11881fbc9eca076b3103c21f8f189cf
|
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2025-02-
|
3
|
+
# on 2025-02-15 02:54:02 UTC using RuboCop version 1.71.2.
|
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
|
@@ -138,7 +138,7 @@ RSpec/DescribedClass:
|
|
138
138
|
Exclude:
|
139
139
|
- 'spec/lutaml/model/xml_mapping_spec.rb'
|
140
140
|
|
141
|
-
# Offense count:
|
141
|
+
# Offense count: 157
|
142
142
|
# Configuration parameters: CountAsOne.
|
143
143
|
RSpec/ExampleLength:
|
144
144
|
Max: 54
|
@@ -149,7 +149,7 @@ RSpec/LeakyConstantDeclaration:
|
|
149
149
|
- 'spec/benchmarks/xml_parsing_benchmark_spec.rb'
|
150
150
|
- 'spec/lutaml/model/xml_adapter/xml_namespace_spec.rb'
|
151
151
|
|
152
|
-
# Offense count:
|
152
|
+
# Offense count: 208
|
153
153
|
RSpec/MultipleExpectations:
|
154
154
|
Max: 14
|
155
155
|
|
@@ -163,13 +163,12 @@ RSpec/MultipleMemoizedHelpers:
|
|
163
163
|
RSpec/NestedGroups:
|
164
164
|
Max: 4
|
165
165
|
|
166
|
-
# Offense count:
|
166
|
+
# Offense count: 5
|
167
167
|
RSpec/PendingWithoutReason:
|
168
168
|
Exclude:
|
169
169
|
- 'spec/lutaml/model/type/date_time_spec.rb'
|
170
170
|
- 'spec/lutaml/model/type/time_spec.rb'
|
171
171
|
- 'spec/lutaml/model/type/time_without_date_spec.rb'
|
172
|
-
- 'spec/lutaml/model/validation_spec.rb'
|
173
172
|
|
174
173
|
# Offense count: 3
|
175
174
|
# Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata.
|
data/Gemfile
CHANGED
data/README.adoc
CHANGED
@@ -413,9 +413,11 @@ end
|
|
413
413
|
|
414
414
|
==== Decimal type
|
415
415
|
|
416
|
-
|
416
|
+
WARNING: Decimal is an optional feature.
|
417
417
|
|
418
|
-
|
418
|
+
The Decimal type is a value type that is disabled by default.
|
419
|
+
|
420
|
+
NOTE: The reason why the Decimal type is disabled by default is that the
|
419
421
|
`BigDecimal` class became optional to the standard Ruby library from Ruby 3.4
|
420
422
|
onwards. The `Decimal` type is only enabled when the `bigdecimal` library is
|
421
423
|
loaded.
|
@@ -693,7 +695,7 @@ end
|
|
693
695
|
Lutaml lets you create reusable element and attribute collections using `no_root`. These can be imported into other models using:
|
694
696
|
|
695
697
|
- `import_model`: imports both attributes and mappings
|
696
|
-
- `import_model_attributes`: imports only attributes
|
698
|
+
- `import_model_attributes`: imports only attributes
|
697
699
|
- `import_model_mappings`: imports only mappings
|
698
700
|
|
699
701
|
NOTE: This feature works with XML. Import order determines how elements and attributes are overwritten.
|
@@ -3898,7 +3900,7 @@ class Person < Lutaml::Model::Serializable
|
|
3898
3900
|
}
|
3899
3901
|
end
|
3900
3902
|
|
3901
|
-
# Mapping-level transformation in XML format
|
3903
|
+
# Mapping-level transformation in XML format
|
3902
3904
|
xml do
|
3903
3905
|
map "full-name", to: :name, transform: {
|
3904
3906
|
export: ->(value) { "Dr. #{value}" },
|
@@ -4098,39 +4100,39 @@ NOTE: For `NokogiriAdapter`, we can also call `to_xml` on `value.node.adapter_no
|
|
4098
4100
|
|
4099
4101
|
# Nokogiri Adapter Node
|
4100
4102
|
|
4101
|
-
#<Lutaml::Model::XmlAdapter::NokogiriElement:0x0000000107656ed8
|
4102
|
-
# @attributes={},
|
4103
|
-
# @children=
|
4103
|
+
#<Lutaml::Model::XmlAdapter::NokogiriElement:0x0000000107656ed8
|
4104
|
+
# @attributes={},
|
4105
|
+
# @children=
|
4104
4106
|
# [#<Lutaml::Model::XmlAdapter::NokogiriElement:0x0000000107656cd0 @attributes={}, @children=[], @default_namespace=nil, @name="text", @namespace_prefix=nil, @text="\n ">,
|
4105
|
-
# #<Lutaml::Model::XmlAdapter::NokogiriElement:0x00000001076569b0
|
4106
|
-
# @attributes={},
|
4107
|
-
# @children=
|
4107
|
+
# #<Lutaml::Model::XmlAdapter::NokogiriElement:0x00000001076569b0
|
4108
|
+
# @attributes={},
|
4109
|
+
# @children=
|
4108
4110
|
# [#<Lutaml::Model::XmlAdapter::NokogiriElement:0x00000001076567f8 @attributes={}, @children=[], @default_namespace=nil, @name="text", @namespace_prefix=nil, @text="Metadata">],
|
4109
|
-
# @default_namespace=nil,
|
4110
|
-
# @name="category",
|
4111
|
-
# @namespace_prefix=nil,
|
4112
|
-
# @text="Metadata">,
|
4111
|
+
# @default_namespace=nil,
|
4112
|
+
# @name="category",
|
4113
|
+
# @namespace_prefix=nil,
|
4114
|
+
# @text="Metadata">,
|
4113
4115
|
# #<Lutaml::Model::XmlAdapter::NokogiriElement:0x0000000107656028 @attributes={}, @children=[], @default_namespace=nil, @name="text", @namespace_prefix=nil, @text="\n ">],
|
4114
|
-
# @default_namespace=nil,
|
4116
|
+
# @default_namespace=nil,
|
4115
4117
|
# @name="metadata",
|
4116
4118
|
# @namespace_prefix=nil,
|
4117
4119
|
# @text="\n Metadata\n ">
|
4118
4120
|
|
4119
4121
|
# Ox Adapter Node
|
4120
4122
|
|
4121
|
-
#<Lutaml::Model::XmlAdapter::OxElement:0x0000000107584f78
|
4122
|
-
# @attributes={},
|
4123
|
-
# @children=
|
4124
|
-
# [#<Lutaml::Model::XmlAdapter::OxElement:0x0000000107584e60
|
4125
|
-
# @attributes={},
|
4123
|
+
#<Lutaml::Model::XmlAdapter::OxElement:0x0000000107584f78
|
4124
|
+
# @attributes={},
|
4125
|
+
# @children=
|
4126
|
+
# [#<Lutaml::Model::XmlAdapter::OxElement:0x0000000107584e60
|
4127
|
+
# @attributes={},
|
4126
4128
|
# @children=[#<Lutaml::Model::XmlAdapter::OxElement:0x0000000107584d48 @attributes={}, @children=[], @default_namespace=nil, @name="text", @namespace_prefix=nil, @text="Metadata">],
|
4127
|
-
# @default_namespace=nil,
|
4128
|
-
# @name="category",
|
4129
|
-
# @namespace_prefix=nil,
|
4130
|
-
# @text="Metadata">],
|
4131
|
-
# @default_namespace=nil,
|
4132
|
-
# @name="metadata",
|
4133
|
-
# @namespace_prefix=nil,
|
4129
|
+
# @default_namespace=nil,
|
4130
|
+
# @name="category",
|
4131
|
+
# @namespace_prefix=nil,
|
4132
|
+
# @text="Metadata">],
|
4133
|
+
# @default_namespace=nil,
|
4134
|
+
# @name="metadata",
|
4135
|
+
# @namespace_prefix=nil,
|
4134
4136
|
# @text=nil>
|
4135
4137
|
|
4136
4138
|
# Oga Adapter Node
|
@@ -4190,7 +4192,7 @@ class CustomModelParentMapper < Lutaml::Model::Serializable
|
|
4190
4192
|
map_element :CustomModelChild,
|
4191
4193
|
with: { to: :child_to_xml, from: :child_from_xml }
|
4192
4194
|
end
|
4193
|
-
|
4195
|
+
|
4194
4196
|
def child_to_xml(model, parent, doc)
|
4195
4197
|
child_el = doc.create_element("CustomModelChild")
|
4196
4198
|
street_el = doc.create_element("street")
|
@@ -4227,7 +4229,7 @@ end
|
|
4227
4229
|
[source,ruby]
|
4228
4230
|
----
|
4229
4231
|
> instance = CustomModelParentMapper.from_xml(xml)
|
4230
|
-
> #<CustomModelParent:0x0000000107c9ca68 @child_mapper=#<CustomModelChild:0x0000000107c95218 @city="London", @street="Oxford Street">, @first_name="John">
|
4232
|
+
> #<CustomModelParent:0x0000000107c9ca68 @child_mapper=#<CustomModelChild:0x0000000107c95218 @city="London", @street="Oxford Street">, @first_name="John">
|
4231
4233
|
> CustomModelParentMapper.to_xml(instance)
|
4232
4234
|
> #<CustomModelParent><first_name>John</first_name><CustomModelChild><street>Oxford Street</street><city>London</city></CustomModelChild></CustomModelParent>
|
4233
4235
|
----
|
@@ -4595,27 +4597,228 @@ klin.validate
|
|
4595
4597
|
====
|
4596
4598
|
|
4597
4599
|
|
4598
|
-
== Liquid
|
4600
|
+
== Liquid template access
|
4601
|
+
|
4602
|
+
WARNING: The Liquid template feature is optional. To enable it, please
|
4603
|
+
explicitly require the `liquid` gem.
|
4604
|
+
|
4605
|
+
The https://shopify.github.io/liquid/[Liquid template language] is an
|
4606
|
+
open-source template language developed by Shopify and written in Ruby.
|
4607
|
+
|
4608
|
+
`Lutaml::Model::Serializable` objects can be safely accessed within Liquid
|
4609
|
+
templates through a `to_liquid` method that converts the objects into
|
4610
|
+
`Liquid::Drop` instances.
|
4599
4611
|
|
4600
|
-
|
4612
|
+
* All attributes are accessible in the Liquid template by their names.
|
4613
|
+
* Nested attributes are also converted into `Liquid::Drop` objects so
|
4614
|
+
inner attributes can be accessed using the Liquid dot notation.
|
4615
|
+
|
4616
|
+
NOTE: Every `Lutaml::Model::Serializable` class extends the `Liquefiable` module
|
4617
|
+
which generates a corresponding `Liquid::Drop` class.
|
4618
|
+
|
4619
|
+
NOTE: Methods defined in the `Lutaml::Model::Serializable` class are not
|
4620
|
+
accessible in the Liquid template.
|
4621
|
+
|
4622
|
+
.Using `to_liquid` to convert model instances into corresponding Liquid drop instances
|
4601
4623
|
|
4602
4624
|
[example]
|
4603
4625
|
====
|
4604
4626
|
[source,ruby]
|
4605
4627
|
----
|
4606
|
-
class
|
4628
|
+
class Ceramic < Lutaml::Model::Serializable
|
4629
|
+
attribute :name, :string
|
4630
|
+
attribute :temperature, :integer
|
4631
|
+
end
|
4632
|
+
|
4633
|
+
ceramic = Ceramic.new({ name: "Porcelain Vase", temperature: 1200 })
|
4634
|
+
ceramic_drop = ceramic.to_liquid
|
4635
|
+
# Ceramic::CeramicDrop
|
4636
|
+
|
4637
|
+
puts ceramic_drop.name
|
4638
|
+
# "Porcelain Vase"
|
4639
|
+
puts ceramic_drop.temperature
|
4640
|
+
# 1200
|
4641
|
+
----
|
4642
|
+
====
|
4643
|
+
|
4644
|
+
.Accessing LutaML::Model objects within a Liquid template
|
4645
|
+
[example]
|
4646
|
+
====
|
4647
|
+
[source,ruby]
|
4648
|
+
----
|
4649
|
+
class Ceramic < Lutaml::Model::Serializable
|
4650
|
+
attribute :name, :string
|
4651
|
+
attribute :temperature, :integer
|
4652
|
+
end
|
4653
|
+
|
4654
|
+
class CeramicCollection < Lutaml::Model::Serializable
|
4655
|
+
attribute :ceramics, Ceramic, collection: true
|
4656
|
+
end
|
4657
|
+
----
|
4658
|
+
|
4659
|
+
`sample.yml`:
|
4660
|
+
|
4661
|
+
[source,yaml]
|
4662
|
+
----
|
4663
|
+
---
|
4664
|
+
ceramics:
|
4665
|
+
- name: Porcelain Vase
|
4666
|
+
temperature: 1200
|
4667
|
+
- name: Earthenware Pot
|
4668
|
+
temperature: 950
|
4669
|
+
- name: Stoneware Jug
|
4670
|
+
temperature: 1200
|
4671
|
+
----
|
4672
|
+
|
4673
|
+
`template.liquid`:
|
4674
|
+
|
4675
|
+
[source,liquid]
|
4676
|
+
----
|
4677
|
+
{% for ceramic in ceramic_collection.ceramics %}
|
4678
|
+
* Name: "{{ ceramic.name }}"
|
4679
|
+
** Temperature: {{ ceramic.temperature }}
|
4680
|
+
{%- endfor %}
|
4681
|
+
----
|
4682
|
+
|
4683
|
+
[source,ruby]
|
4684
|
+
----
|
4685
|
+
# Load the Lutaml::Model collection
|
4686
|
+
ceramic_collection = CeramicCollection.from_yaml(File.read("sample.yml"))
|
4687
|
+
|
4688
|
+
# Load the Liquid template
|
4689
|
+
template = Liquid::Template.parse(File.read("template.liquid"))
|
4690
|
+
|
4691
|
+
# Pass the Lutaml::Model collection to the Liquid template and render
|
4692
|
+
output = template.render("ceramic_collection" => ceramic_collection)
|
4693
|
+
puts output
|
4694
|
+
# >
|
4695
|
+
# * Name: "Porcelain Vase"
|
4696
|
+
# ** Temperature: 1200
|
4697
|
+
# * Name: "Earthenware Pot"
|
4698
|
+
# ** Temperature: 950
|
4699
|
+
# * Name: "Stoneware Jug"
|
4700
|
+
# ** Temperature: 1200
|
4701
|
+
----
|
4702
|
+
====
|
4703
|
+
|
4704
|
+
.Accessing nested LutaML::Model objects within nested Liquid templates
|
4705
|
+
[example]
|
4706
|
+
====
|
4707
|
+
[source,ruby]
|
4708
|
+
----
|
4709
|
+
class Glaze < Lutaml::Model::Serializable
|
4710
|
+
attribute :color, :string
|
4711
|
+
attribute :opacity, :string
|
4712
|
+
end
|
4713
|
+
|
4714
|
+
class CeramicWork < Lutaml::Model::Serializable
|
4607
4715
|
attribute :name, :string
|
4608
|
-
attribute :
|
4716
|
+
attribute :glaze, Glaze
|
4717
|
+
end
|
4718
|
+
|
4719
|
+
class CeramicCollection < Lutaml::Model::Serializable
|
4720
|
+
attribute :ceramics, Ceramic, collection: true
|
4609
4721
|
end
|
4610
4722
|
|
4611
|
-
|
4612
|
-
|
4613
|
-
|
4723
|
+
ceramic_work = CeramicWork.new({
|
4724
|
+
name: "Celadon Bowl",
|
4725
|
+
glaze: Glaze.new({
|
4726
|
+
color: "Jade Green",
|
4727
|
+
opacity: "Translucent"
|
4728
|
+
})
|
4729
|
+
})
|
4730
|
+
ceramic_work_drop = ceramic_work.to_liquid
|
4731
|
+
# CeramicWork::CeramicWorkDrop
|
4732
|
+
|
4733
|
+
puts ceramic_work_drop.name
|
4734
|
+
# "Celadon Bowl"
|
4735
|
+
puts ceramic_work_drop.glaze.color
|
4736
|
+
# "Jade Green"
|
4737
|
+
puts ceramic_work_drop.glaze.opacity
|
4738
|
+
# "Translucent"
|
4739
|
+
----
|
4740
|
+
|
4741
|
+
`ceramics.yml`:
|
4742
|
+
|
4743
|
+
[source,yaml]
|
4744
|
+
----
|
4745
|
+
---
|
4746
|
+
ceramics:
|
4747
|
+
- name: Celadon Bowl
|
4748
|
+
glaze:
|
4749
|
+
color: Jade Green
|
4750
|
+
opacity: Translucent
|
4751
|
+
- name: Earthenware Pot
|
4752
|
+
glaze:
|
4753
|
+
color: Rust Red
|
4754
|
+
opacity: Opaque
|
4755
|
+
- name: Stoneware Jug
|
4756
|
+
glaze:
|
4757
|
+
color: Cobalt Blue
|
4758
|
+
opacity: Transparent
|
4759
|
+
----
|
4760
|
+
|
4761
|
+
|
4762
|
+
`templates/_ceramics.liquid`:
|
4763
|
+
|
4764
|
+
[source,liquid]
|
4765
|
+
----
|
4766
|
+
{% for ceramic in ceramic_collection.ceramics %}
|
4767
|
+
{% render 'ceramic' ceramic: ceramic %}
|
4768
|
+
{%- endfor %}
|
4769
|
+
----
|
4770
|
+
|
4771
|
+
NOTE: `render` is a Liquid tag that renders a partial template, by default
|
4772
|
+
Liquid uses the pattern `_%s.liquid` to find the partial template. Here
|
4773
|
+
`ceramic` refers to the file at `templates/_ceramic.liquid`.
|
4774
|
+
|
4775
|
+
`templates/_ceramic.liquid`:
|
4776
|
+
|
4777
|
+
[source,liquid]
|
4778
|
+
----
|
4779
|
+
* Name: "{{ ceramic.name }}"
|
4780
|
+
** Temperature: {{ ceramic.temperature }}
|
4781
|
+
{%- if ceramic.glaze %}
|
4782
|
+
** Glaze (color): {{ ceramic.glaze.color }}
|
4783
|
+
** Glaze (opacity): {{ ceramic.glaze.opacity }}
|
4784
|
+
{%- endif %}
|
4785
|
+
----
|
4786
|
+
|
4787
|
+
[source,ruby]
|
4788
|
+
----
|
4789
|
+
require 'liquid'
|
4790
|
+
|
4791
|
+
# Create a Liquid template object that supports dynamic loading
|
4792
|
+
template = Liquid::Template.new
|
4793
|
+
|
4794
|
+
# Link the Liquid template object to a "local file system" (directory)
|
4795
|
+
file_system = Liquid::LocalFileSystem.new('templates/')
|
4796
|
+
template.registers[:file_system] = file_system
|
4797
|
+
|
4798
|
+
# Load the partial template, this is necessary.
|
4799
|
+
# This will also allow Liquid to load any inner partials from the file system
|
4800
|
+
# dynamically (see `file_system.pattern` to see what it loads)
|
4801
|
+
template.parse(file_system.read_template_file('ceramics'))
|
4802
|
+
|
4803
|
+
# Read the lutaml-model collection
|
4804
|
+
ceramic_collection = CeramicCollection.from_yaml(File.read("ceramics.yml"))
|
4614
4805
|
|
4615
|
-
|
4616
|
-
|
4617
|
-
puts
|
4618
|
-
#
|
4806
|
+
# Render the template with the collection
|
4807
|
+
output = template.render("ceramic_collection" => ceramic_collection)
|
4808
|
+
puts output
|
4809
|
+
# >
|
4810
|
+
# * Name: "Celadon Bowl"
|
4811
|
+
# ** Temperature: 1200
|
4812
|
+
# ** Glaze (color): Jade Green
|
4813
|
+
# ** Glaze (finish): Translucent
|
4814
|
+
# * Name: "Earthenware Pot"
|
4815
|
+
# ** Temperature: 950
|
4816
|
+
# ** Glaze (color): Rust Red
|
4817
|
+
# ** Glaze (finish): Opaque
|
4818
|
+
# * Name: "Stoneware Jug"
|
4819
|
+
# ** Temperature: 1200
|
4820
|
+
# ** Glaze (color): Cobalt Blue
|
4821
|
+
# ** Glaze (finish): Transparent
|
4619
4822
|
----
|
4620
4823
|
====
|
4621
4824
|
|
data/lib/lutaml/model/error.rb
CHANGED
@@ -6,6 +6,7 @@ module Lutaml
|
|
6
6
|
end
|
7
7
|
|
8
8
|
require_relative "error/invalid_value_error"
|
9
|
+
require_relative "error/liquid_not_enabled_error"
|
9
10
|
require_relative "error/incorrect_mapping_argument_error"
|
10
11
|
require_relative "error/pattern_not_matched_error"
|
11
12
|
require_relative "error/unknown_adapter_type_error"
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require "liquid"
|
2
|
-
|
3
1
|
module Lutaml
|
4
2
|
module Model
|
5
3
|
module Liquefiable
|
@@ -9,6 +7,7 @@ module Lutaml
|
|
9
7
|
|
10
8
|
module ClassMethods
|
11
9
|
def register_liquid_drop_class
|
10
|
+
validate_liquid!
|
12
11
|
if drop_class
|
13
12
|
raise "#{drop_class_name} Already exists!"
|
14
13
|
end
|
@@ -38,6 +37,7 @@ module Lutaml
|
|
38
37
|
|
39
38
|
def register_drop_method(method_name)
|
40
39
|
register_liquid_drop_class unless drop_class
|
40
|
+
return if drop_class.method_defined?(method_name)
|
41
41
|
|
42
42
|
drop_class.define_method(method_name) do
|
43
43
|
value = @object.public_send(method_name)
|
@@ -49,9 +49,22 @@ module Lutaml
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
|
+
|
53
|
+
def validate_liquid!
|
54
|
+
return if Object.const_defined?(:Liquid)
|
55
|
+
|
56
|
+
raise Lutaml::Model::LiquidNotEnabledError
|
57
|
+
end
|
52
58
|
end
|
53
59
|
|
54
60
|
def to_liquid
|
61
|
+
self.class.validate_liquid!
|
62
|
+
|
63
|
+
if is_a?(Lutaml::Model::Serializable)
|
64
|
+
self.class.attributes.each_key do |attr_name|
|
65
|
+
self.class.register_drop_method(attr_name)
|
66
|
+
end
|
67
|
+
end
|
55
68
|
self.class.drop_class.new(self)
|
56
69
|
end
|
57
70
|
end
|
data/lib/lutaml/model/version.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "spec_helper"
|
2
|
+
require "liquid"
|
2
3
|
require_relative "../../fixtures/address"
|
3
4
|
|
4
5
|
class LiquefiableClass
|
@@ -16,6 +17,23 @@ class LiquefiableClass
|
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
20
|
+
module LiquefiableSpec
|
21
|
+
class Glaze < Lutaml::Model::Serializable
|
22
|
+
attribute :color, :string
|
23
|
+
attribute :opacity, :string
|
24
|
+
end
|
25
|
+
|
26
|
+
class Ceramic < Lutaml::Model::Serializable
|
27
|
+
attribute :name, :string
|
28
|
+
attribute :temperature, :integer
|
29
|
+
attribute :glaze, Glaze
|
30
|
+
end
|
31
|
+
|
32
|
+
class CeramicCollection < Lutaml::Model::Serializable
|
33
|
+
attribute :ceramics, Ceramic, collection: true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
19
37
|
RSpec.describe Lutaml::Model::Liquefiable do
|
20
38
|
before do
|
21
39
|
stub_const("DummyModel", Class.new(LiquefiableClass))
|
@@ -26,14 +44,27 @@ RSpec.describe Lutaml::Model::Liquefiable do
|
|
26
44
|
describe ".register_liquid_drop_class" do
|
27
45
|
context "when drop class does not exist" do
|
28
46
|
it "creates a new drop class" do
|
29
|
-
expect
|
30
|
-
dummy.class.
|
31
|
-
|
47
|
+
expect do
|
48
|
+
dummy.class.register_liquid_drop_class
|
49
|
+
end.to change {
|
50
|
+
dummy.class.const_defined?(:DummyModelDrop)
|
51
|
+
}
|
32
52
|
.from(false)
|
33
53
|
.to(true)
|
34
54
|
end
|
35
55
|
end
|
36
56
|
|
57
|
+
context "when 'liquid' is not available" do
|
58
|
+
before { allow(Object).to receive(:const_defined?).with(:Liquid).and_return(false) }
|
59
|
+
|
60
|
+
it "raises an error" do
|
61
|
+
expect { dummy.class.register_liquid_drop_class }.to raise_error(
|
62
|
+
Lutaml::Model::LiquidNotEnabledError,
|
63
|
+
"Liquid functionality is not available by default; please install and require `liquid` gem to use this functionality",
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
37
68
|
context "when drop class already exists" do
|
38
69
|
it "raises an error" do
|
39
70
|
dummy.class.register_liquid_drop_class
|
@@ -69,26 +100,41 @@ RSpec.describe Lutaml::Model::Liquefiable do
|
|
69
100
|
end
|
70
101
|
|
71
102
|
it "defines a method on the drop class" do
|
72
|
-
expect
|
73
|
-
dummy.
|
74
|
-
|
103
|
+
expect do
|
104
|
+
dummy.class.register_drop_method(:display_name)
|
105
|
+
end.to change {
|
106
|
+
dummy.to_liquid.respond_to?(:display_name)
|
107
|
+
}
|
75
108
|
.from(false)
|
76
109
|
.to(true)
|
77
110
|
end
|
78
111
|
end
|
79
112
|
|
80
113
|
describe ".to_liquid" do
|
81
|
-
|
82
|
-
|
83
|
-
dummy.class.register_drop_method(:display_name)
|
84
|
-
end
|
114
|
+
context "when liquid is not enabled" do
|
115
|
+
before { allow(Object).to receive(:const_defined?).with(:Liquid).and_return(false) }
|
85
116
|
|
86
|
-
|
87
|
-
|
117
|
+
it "raises an error" do
|
118
|
+
expect { dummy.to_liquid }.to raise_error(
|
119
|
+
Lutaml::Model::LiquidNotEnabledError,
|
120
|
+
"Liquid functionality is not available by default; please install and require `liquid` gem to use this functionality",
|
121
|
+
)
|
122
|
+
end
|
88
123
|
end
|
89
124
|
|
90
|
-
|
91
|
-
|
125
|
+
context "when liquid is enabled" do
|
126
|
+
before do
|
127
|
+
dummy.class.register_liquid_drop_class
|
128
|
+
dummy.class.register_drop_method(:display_name)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "returns an instance of the drop class" do
|
132
|
+
expect(dummy.to_liquid).to be_a(dummy.class.drop_class)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "allows access to registered methods via the drop class" do
|
136
|
+
expect(dummy.to_liquid.display_name).to eq("TestName (42)")
|
137
|
+
end
|
92
138
|
end
|
93
139
|
end
|
94
140
|
|
@@ -118,4 +164,96 @@ RSpec.describe Lutaml::Model::Liquefiable do
|
|
118
164
|
end
|
119
165
|
end
|
120
166
|
end
|
167
|
+
|
168
|
+
describe "working with liquid templates" do
|
169
|
+
let(:liquid_template_dir) do
|
170
|
+
File.join(File.dirname(__FILE__), "../../fixtures/liquid_templates")
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "rendering simple models with liquid templates" do
|
174
|
+
let :yaml do
|
175
|
+
<<~YAML
|
176
|
+
---
|
177
|
+
ceramics:
|
178
|
+
- name: Porcelain Vase
|
179
|
+
temperature: 1200
|
180
|
+
- name: Earthenware Pot
|
181
|
+
temperature: 950
|
182
|
+
- name: Stoneware Jug
|
183
|
+
temperature: 1200
|
184
|
+
YAML
|
185
|
+
end
|
186
|
+
let :template_path do
|
187
|
+
File.join(liquid_template_dir, "_ceramics_in_one.liquid")
|
188
|
+
end
|
189
|
+
|
190
|
+
it "renders" do
|
191
|
+
template = Liquid::Template.parse(File.read(template_path))
|
192
|
+
ceramic_collection = LiquefiableSpec::CeramicCollection.from_yaml(yaml)
|
193
|
+
output = template.render("ceramic_collection" => ceramic_collection)
|
194
|
+
|
195
|
+
expected_output = <<~OUTPUT
|
196
|
+
* Name: "Porcelain Vase"
|
197
|
+
** Temperature: 1200
|
198
|
+
* Name: "Earthenware Pot"
|
199
|
+
** Temperature: 950
|
200
|
+
* Name: "Stoneware Jug"
|
201
|
+
** Temperature: 1200
|
202
|
+
OUTPUT
|
203
|
+
|
204
|
+
expect(output.strip).to eq(expected_output.strip)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe "rendering nested models with liquid templates from file system" do
|
209
|
+
let :yaml do
|
210
|
+
<<~YAML
|
211
|
+
---
|
212
|
+
ceramics:
|
213
|
+
- name: Celadon Bowl
|
214
|
+
temperature: 1200
|
215
|
+
glaze:
|
216
|
+
color: Jade Green
|
217
|
+
opacity: Translucent
|
218
|
+
- name: Earthenware Pot
|
219
|
+
temperature: 950
|
220
|
+
glaze:
|
221
|
+
color: Rust Red
|
222
|
+
opacity: Opaque
|
223
|
+
- name: Stoneware Jug
|
224
|
+
temperature: 1200
|
225
|
+
glaze:
|
226
|
+
color: Cobalt Blue
|
227
|
+
opacity: Transparent
|
228
|
+
YAML
|
229
|
+
end
|
230
|
+
|
231
|
+
it "renders" do
|
232
|
+
template = Liquid::Template.new
|
233
|
+
file_system = Liquid::LocalFileSystem.new(liquid_template_dir)
|
234
|
+
template.registers[:file_system] = file_system
|
235
|
+
template.parse(file_system.read_template_file("ceramics"))
|
236
|
+
|
237
|
+
ceramic_collection = LiquefiableSpec::CeramicCollection.from_yaml(yaml)
|
238
|
+
output = template.render("ceramic_collection" => ceramic_collection)
|
239
|
+
# puts output
|
240
|
+
|
241
|
+
expected_output = <<~OUTPUT
|
242
|
+
* Name: "Celadon Bowl"
|
243
|
+
** Temperature: 1200
|
244
|
+
** Glaze (color): Jade Green
|
245
|
+
** Glaze (opacity): Translucent
|
246
|
+
* Name: "Earthenware Pot"
|
247
|
+
** Temperature: 950
|
248
|
+
** Glaze (color): Rust Red
|
249
|
+
** Glaze (opacity): Opaque
|
250
|
+
* Name: "Stoneware Jug"
|
251
|
+
** Temperature: 1200
|
252
|
+
** Glaze (color): Cobalt Blue
|
253
|
+
** Glaze (opacity): Transparent
|
254
|
+
OUTPUT
|
255
|
+
expect(output.strip).to eq(expected_output.strip)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
121
259
|
end
|
data/spec/spec_helper.rb
CHANGED
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.6.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-02-
|
11
|
+
date: 2025-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base64
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- lib/lutaml/model/error/incorrect_sequence_error.rb
|
112
112
|
- lib/lutaml/model/error/invalid_choice_range_error.rb
|
113
113
|
- lib/lutaml/model/error/invalid_value_error.rb
|
114
|
+
- lib/lutaml/model/error/liquid_not_enabled_error.rb
|
114
115
|
- lib/lutaml/model/error/multiple_mappings_error.rb
|
115
116
|
- lib/lutaml/model/error/no_root_mapping_error.rb
|
116
117
|
- lib/lutaml/model/error/no_root_namespace_error.rb
|
@@ -192,6 +193,9 @@ files:
|
|
192
193
|
- spec/ceramic_spec.rb
|
193
194
|
- spec/fixtures/address.rb
|
194
195
|
- spec/fixtures/ceramic.rb
|
196
|
+
- spec/fixtures/liquid_templates/_ceramic.liquid
|
197
|
+
- spec/fixtures/liquid_templates/_ceramics.liquid
|
198
|
+
- spec/fixtures/liquid_templates/_ceramics_in_one.liquid
|
195
199
|
- spec/fixtures/person.rb
|
196
200
|
- spec/fixtures/sample_model.rb
|
197
201
|
- spec/fixtures/vase.rb
|