lutaml-model 0.8.11 → 0.8.12
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/.github/workflows/opal.yml +31 -0
- data/.rspec-opal +5 -0
- data/.rubocop_todo.yml +45 -34
- data/README.adoc +10 -1
- data/docs/_guides/index.adoc +4 -0
- data/docs/_guides/opal.adoc +221 -0
- data/docs/_guides/xml_mappings/07_best_practices.adoc +2 -1
- data/docs/_pages/configuration.adoc +9 -4
- data/docs/_pages/index.adoc +1 -0
- data/docs/_pages/serialization_adapters.adoc +3 -2
- data/docs/index.adoc +1 -0
- data/lib/lutaml/hash_format/adapter/mapping.rb +2 -4
- data/lib/lutaml/json/adapter/mapping.rb +2 -4
- data/lib/lutaml/jsonl/adapter/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/hash/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/json/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/jsonl/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/toml/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/yaml/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/yamls/mapping.rb +2 -4
- data/lib/lutaml/key_value/mapping.rb +4 -4
- data/lib/lutaml/model/adapter_resolver.rb +5 -8
- data/lib/lutaml/model/mapping/mapping.rb +12 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/toml/adapter/mapping.rb +2 -4
- data/lib/lutaml/xml/schema/xsd.rb +5 -4
- data/lib/lutaml/xml/schema.rb +8 -5
- data/lib/lutaml/xml/xml_orderable.rb +17 -0
- data/lib/lutaml/xml.rb +8 -11
- data/lib/lutaml/yaml/adapter/mapping.rb +2 -4
- data/lib/lutaml/yamls/adapter/mapping.rb +7 -3
- data/lutaml-model.gemspec +1 -1
- data/spec/lutaml/model/opal_smoke_spec.rb +117 -0
- data/spec/lutaml/xml/opal_xml_spec.rb +145 -0
- data/spec/lutaml/xml/xml_spec.rb +64 -13
- data/spec/support/opal.rb +6 -0
- metadata +11 -4
|
@@ -218,17 +218,17 @@ module Lutaml
|
|
|
218
218
|
end
|
|
219
219
|
|
|
220
220
|
# Writers for deep_dup in subclasses
|
|
221
|
-
attr_writer :
|
|
221
|
+
attr_writer :register_mappings
|
|
222
222
|
|
|
223
223
|
def deep_dup
|
|
224
|
-
|
|
224
|
+
dup_instance.tap do |new_mapping|
|
|
225
225
|
new_mapping.mappings = duplicate_mappings
|
|
226
226
|
new_mapping.register_mappings = Lutaml::Model::Utils.deep_dup(@register_mappings)
|
|
227
227
|
end
|
|
228
228
|
end
|
|
229
229
|
|
|
230
|
-
def
|
|
231
|
-
|
|
230
|
+
def dup_instance
|
|
231
|
+
self.class.new(@format)
|
|
232
232
|
end
|
|
233
233
|
|
|
234
234
|
def find_by_to(to)
|
|
@@ -370,15 +370,12 @@ module Lutaml
|
|
|
370
370
|
|
|
371
371
|
# Detect available XML adapter.
|
|
372
372
|
#
|
|
373
|
-
#
|
|
373
|
+
# Delegates to moxml which is the authority on XML adapter
|
|
374
|
+
# availability and platform constraints (Opal, MRI, etc.).
|
|
375
|
+
#
|
|
376
|
+
# @return [Symbol] adapter type name
|
|
374
377
|
def detect_xml_adapter
|
|
375
|
-
|
|
376
|
-
return :nokogiri if Utils.safe_load("nokogiri", :Nokogiri)
|
|
377
|
-
return :ox if Utils.safe_load("ox", :Ox)
|
|
378
|
-
return :oga if Utils.safe_load("oga", :Oga)
|
|
379
|
-
return :rexml if Utils.safe_load("rexml", :REXML)
|
|
380
|
-
|
|
381
|
-
nil
|
|
378
|
+
Moxml::Config.runtime_default_adapter
|
|
382
379
|
end
|
|
383
380
|
|
|
384
381
|
# Detect available TOML adapter.
|
|
@@ -3,6 +3,8 @@ module Lutaml
|
|
|
3
3
|
class Mapping
|
|
4
4
|
include DeepDupable
|
|
5
5
|
|
|
6
|
+
attr_writer :mappings
|
|
7
|
+
|
|
6
8
|
def initialize
|
|
7
9
|
@mappings = []
|
|
8
10
|
@listeners = {} # target => [Listener, ...]
|
|
@@ -11,6 +13,16 @@ module Lutaml
|
|
|
11
13
|
@mappings_imported = ::Hash.new { |h, k| h[k] = false }
|
|
12
14
|
end
|
|
13
15
|
|
|
16
|
+
def deep_dup
|
|
17
|
+
duped = self.class.new
|
|
18
|
+
duped.mappings = duplicate_mappings
|
|
19
|
+
duped
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def duplicate_mappings
|
|
23
|
+
Lutaml::Model::Utils.deep_dup(@mappings)
|
|
24
|
+
end
|
|
25
|
+
|
|
14
26
|
# Get listeners for a specific target (element name/key).
|
|
15
27
|
#
|
|
16
28
|
# @param target [String, Symbol] The element name or key
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
# NOTE: Do NOT require lutaml/model here. This file is autoloaded via
|
|
4
4
|
# Lutaml::Xml::Schema::Xsd, and requiring lutaml/model creates a circular
|
|
5
|
-
# dependency since lutaml/xml.rb requires lutaml/model.
|
|
6
|
-
#
|
|
5
|
+
# dependency since lutaml/xml.rb requires lutaml/model. This file only sets
|
|
6
|
+
# a fallback XML adapter when no adapter has been selected yet.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
Lutaml::Model::Config.xml_adapter_type =
|
|
8
|
+
unless defined?(Lutaml::Model::Config.xml_adapter_type)
|
|
9
|
+
Lutaml::Model::Config.xml_adapter_type = Lutaml::Model::AdapterResolver.detect_xml_adapter
|
|
10
|
+
end
|
|
10
11
|
|
|
11
12
|
# Require the XsdNamespace class for XSD schema support
|
|
12
13
|
require_relative "xsd_namespace"
|
data/lib/lutaml/xml/schema.rb
CHANGED
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
module Lutaml
|
|
4
4
|
module Xml
|
|
5
5
|
module Schema
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
Lutaml::Model::RuntimeCompatibility.autoload_native(
|
|
7
|
+
self,
|
|
8
|
+
Xsd: "#{__dir__}/schema/xsd",
|
|
9
|
+
XsdSchema: "#{__dir__}/schema/xsd_schema",
|
|
10
|
+
RelaxngSchema: "#{__dir__}/schema/relaxng_schema",
|
|
11
|
+
Builder: "#{__dir__}/schema/builder",
|
|
12
|
+
BuiltinTypes: "#{__dir__}/schema/builtin_types",
|
|
13
|
+
)
|
|
11
14
|
end
|
|
12
15
|
end
|
|
13
16
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lutaml
|
|
4
|
+
module Xml
|
|
5
|
+
# Mixin for XML element/attribute ordering state.
|
|
6
|
+
#
|
|
7
|
+
# Included by:
|
|
8
|
+
# - Lutaml::Xml::Serialization::InstanceMethods (Serialize instances)
|
|
9
|
+
# - Plain model classes via add_format_specific_model_methods
|
|
10
|
+
#
|
|
11
|
+
# Enables Lutaml::Model to check ordering capability with is_a? instead
|
|
12
|
+
# of respond_to?, following proper OOP type-checking.
|
|
13
|
+
module XmlOrderable
|
|
14
|
+
attr_accessor :element_order, :attribute_order, :ordered, :mixed
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/lutaml/xml.rb
CHANGED
|
@@ -42,16 +42,13 @@ module Lutaml
|
|
|
42
42
|
# XML Schema modules
|
|
43
43
|
autoload :Schema, "#{__dir__}/xml/schema"
|
|
44
44
|
|
|
45
|
-
# Detect available XML adapter
|
|
46
|
-
#
|
|
45
|
+
# Detect available XML adapter.
|
|
46
|
+
# Delegates to moxml, which is the authority on XML adapter
|
|
47
|
+
# availability and platform constraints.
|
|
48
|
+
#
|
|
49
|
+
# @return [Symbol] adapter type name
|
|
47
50
|
def self.detect_xml_adapter
|
|
48
|
-
|
|
49
|
-
return :nokogiri if Lutaml::Model::Utils.safe_load("nokogiri", :Nokogiri)
|
|
50
|
-
return :ox if Lutaml::Model::Utils.safe_load("ox", :Ox)
|
|
51
|
-
return :oga if Lutaml::Model::Utils.safe_load("oga", :Oga)
|
|
52
|
-
return :rexml if Lutaml::Model::Utils.safe_load("rexml", :REXML)
|
|
53
|
-
|
|
54
|
-
nil
|
|
51
|
+
Moxml::Config.runtime_default_adapter
|
|
55
52
|
end
|
|
56
53
|
|
|
57
54
|
# Get the current XML adapter
|
|
@@ -174,8 +171,8 @@ Lutaml::Model::FormatRegistry.register(
|
|
|
174
171
|
],
|
|
175
172
|
adapter_options: if Lutaml::Model::RuntimeCompatibility.opal?
|
|
176
173
|
{
|
|
177
|
-
available: %i[
|
|
178
|
-
default: :
|
|
174
|
+
available: %i[rexml],
|
|
175
|
+
default: :rexml,
|
|
179
176
|
}
|
|
180
177
|
else
|
|
181
178
|
{
|
|
@@ -4,7 +4,7 @@ module Lutaml
|
|
|
4
4
|
module Yamls
|
|
5
5
|
module Adapter
|
|
6
6
|
class Mapping < Lutaml::KeyValue::Mapping
|
|
7
|
-
|
|
7
|
+
attr_accessor :yamls_sequence
|
|
8
8
|
|
|
9
9
|
def initialize
|
|
10
10
|
super(:yaml)
|
|
@@ -15,9 +15,13 @@ module Lutaml
|
|
|
15
15
|
@yamls_sequence.instance_eval(&)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
def dup_instance
|
|
19
|
+
self.class.new
|
|
20
|
+
end
|
|
21
|
+
|
|
18
22
|
def deep_dup
|
|
19
|
-
|
|
20
|
-
new_mapping.
|
|
23
|
+
super.tap do |new_mapping|
|
|
24
|
+
new_mapping.yamls_sequence = @yamls_sequence&.dup
|
|
21
25
|
end
|
|
22
26
|
end
|
|
23
27
|
end
|
data/lutaml-model.gemspec
CHANGED
|
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
|
|
|
36
36
|
spec.add_dependency "canon"
|
|
37
37
|
spec.add_dependency "concurrent-ruby"
|
|
38
38
|
spec.add_dependency "liquid", ">= 4.0", "< 6.0"
|
|
39
|
-
spec.add_dependency "moxml", ">= 0.1.
|
|
39
|
+
spec.add_dependency "moxml", ">= 0.1.22"
|
|
40
40
|
spec.add_dependency "ostruct"
|
|
41
41
|
spec.add_dependency "rubyzip", "~> 2.3"
|
|
42
42
|
spec.add_dependency "thor"
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "Opal compatibility", if: RUBY_ENGINE == "opal" do
|
|
6
|
+
it "includes Serialize in a class" do
|
|
7
|
+
klass = Class.new { include Lutaml::Model::Serialize }
|
|
8
|
+
expect(klass.include?(Lutaml::Model::Serialize)).to be true
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "defines attributes and serializes to hash" do
|
|
12
|
+
person = Class.new do
|
|
13
|
+
include Lutaml::Model::Serialize
|
|
14
|
+
|
|
15
|
+
attribute :name, :string
|
|
16
|
+
attribute :age, :integer
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
instance = person.new(name: "Alice", age: 30)
|
|
20
|
+
expect(instance.to_hash).to eq({ "name" => "Alice", "age" => 30 })
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "round-trips JSON serialization" do
|
|
24
|
+
person = Class.new do
|
|
25
|
+
include Lutaml::Model::Serialize
|
|
26
|
+
|
|
27
|
+
attribute :name, :string
|
|
28
|
+
attribute :age, :integer
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
instance = person.from_json('{"name":"Bob","age":25}')
|
|
32
|
+
expect(instance.name).to eq("Bob")
|
|
33
|
+
expect(instance.age).to eq(25)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "handles collections" do
|
|
37
|
+
team = Class.new do
|
|
38
|
+
include Lutaml::Model::Serialize
|
|
39
|
+
|
|
40
|
+
attribute :members, :string, collection: true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
instance = team.new(members: %w[Alice Bob Carol])
|
|
44
|
+
expect(instance.members).to eq(%w[Alice Bob Carol])
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "handles defaults" do
|
|
48
|
+
widget = Class.new do
|
|
49
|
+
include Lutaml::Model::Serialize
|
|
50
|
+
|
|
51
|
+
attribute :name, :string
|
|
52
|
+
attribute :active, :boolean, default: -> { true }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
instance = widget.new(name: "test")
|
|
56
|
+
expect(instance.active).to be true
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "handles type coercion" do
|
|
60
|
+
record = Class.new do
|
|
61
|
+
include Lutaml::Model::Serialize
|
|
62
|
+
|
|
63
|
+
attribute :count, :integer
|
|
64
|
+
attribute :ratio, :float
|
|
65
|
+
attribute :flag, :boolean
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
instance = record.new(count: "42", ratio: "3.14", flag: "true")
|
|
69
|
+
expect(instance.count).to eq(42)
|
|
70
|
+
expect(instance.ratio).to eq(3.14)
|
|
71
|
+
expect(instance.flag).to be true
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "handles nested models" do
|
|
75
|
+
address = Class.new do
|
|
76
|
+
include Lutaml::Model::Serialize
|
|
77
|
+
|
|
78
|
+
attribute :city, :string
|
|
79
|
+
attribute :zip, :string
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
person = Class.new do
|
|
83
|
+
include Lutaml::Model::Serialize
|
|
84
|
+
|
|
85
|
+
attribute :name, :string
|
|
86
|
+
attribute :address, address
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
instance = person.new(name: "Alice",
|
|
90
|
+
address: address.new(
|
|
91
|
+
city: "NYC", zip: "10001",
|
|
92
|
+
))
|
|
93
|
+
expect(instance.address.city).to eq("NYC")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "handles YAML serialization" do
|
|
97
|
+
config = Class.new do
|
|
98
|
+
include Lutaml::Model::Serialize
|
|
99
|
+
|
|
100
|
+
attribute :host, :string
|
|
101
|
+
attribute :port, :integer
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
instance = config.from_yaml("host: localhost\nport: 8080\n")
|
|
105
|
+
expect(instance.host).to eq("localhost")
|
|
106
|
+
expect(instance.port).to eq(8080)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "RuntimeCompatibility detects Opal" do
|
|
110
|
+
expect(Lutaml::Model::RuntimeCompatibility.opal?).to be true
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "AdapterResolver auto-detects REXML" do
|
|
114
|
+
adapter = Lutaml::Model::AdapterResolver.detect_xml_adapter
|
|
115
|
+
expect(adapter).to eq(:rexml)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "XML with REXML under Opal", if: RUBY_ENGINE == "opal" do
|
|
6
|
+
before do
|
|
7
|
+
Lutaml::Model::Config.xml_adapter_type = :rexml
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "round-trips XML through parse and serialize" do
|
|
11
|
+
klass = Class.new do
|
|
12
|
+
include Lutaml::Model::Serialize
|
|
13
|
+
|
|
14
|
+
attribute :name, :string
|
|
15
|
+
xml do
|
|
16
|
+
root "person"
|
|
17
|
+
map_element "name", to: :name
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
instance = klass.from_xml("<person><name>Alice</name></person>")
|
|
22
|
+
expect(instance.name).to eq("Alice")
|
|
23
|
+
expect(instance.to_xml).to include("<name>Alice</name>")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "handles XML attributes" do
|
|
27
|
+
klass = Class.new do
|
|
28
|
+
include Lutaml::Model::Serialize
|
|
29
|
+
|
|
30
|
+
attribute :id, :string
|
|
31
|
+
attribute :value, :string
|
|
32
|
+
xml do
|
|
33
|
+
root "item"
|
|
34
|
+
map_attribute "id", to: :id
|
|
35
|
+
map_element "value", to: :value
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
instance = klass.from_xml('<item id="42"><value>test</value></item>')
|
|
40
|
+
expect(instance.id).to eq("42")
|
|
41
|
+
expect(instance.value).to eq("test")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "handles nested elements" do
|
|
45
|
+
address = Class.new do
|
|
46
|
+
include Lutaml::Model::Serialize
|
|
47
|
+
|
|
48
|
+
attribute :city, :string
|
|
49
|
+
xml do
|
|
50
|
+
root "address"
|
|
51
|
+
map_element "city", to: :city
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
person = Class.new do
|
|
56
|
+
include Lutaml::Model::Serialize
|
|
57
|
+
|
|
58
|
+
attribute :name, :string
|
|
59
|
+
attribute :address, address
|
|
60
|
+
xml do
|
|
61
|
+
root "person"
|
|
62
|
+
map_element "name", to: :name
|
|
63
|
+
map_element "address", to: :address
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
instance = person.from_xml("<person><name>Alice</name><address><city>NYC</city></address></person>")
|
|
68
|
+
expect(instance.name).to eq("Alice")
|
|
69
|
+
expect(instance.address.city).to eq("NYC")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "handles element collections" do
|
|
73
|
+
list = Class.new do
|
|
74
|
+
include Lutaml::Model::Serialize
|
|
75
|
+
|
|
76
|
+
attribute :items, :string, collection: true
|
|
77
|
+
xml do
|
|
78
|
+
root "list"
|
|
79
|
+
map_element "item", to: :items
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
instance = list.from_xml("<list><item>a</item><item>b</item><item>c</item></list>")
|
|
84
|
+
expect(instance.items).to eq(%w[a b c])
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "handles mixed content" do
|
|
88
|
+
paragraph = Class.new do
|
|
89
|
+
include Lutaml::Model::Serialize
|
|
90
|
+
|
|
91
|
+
attribute :content, :string, collection: true
|
|
92
|
+
xml do
|
|
93
|
+
root "p"
|
|
94
|
+
mixed_content
|
|
95
|
+
map_content to: :content
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
instance = paragraph.from_xml("<p>Hello <b>world</b> end</p>")
|
|
100
|
+
expect(instance.content.join).to include("Hello")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "serializes to XML with correct structure" do
|
|
104
|
+
item = Class.new do
|
|
105
|
+
include Lutaml::Model::Serialize
|
|
106
|
+
|
|
107
|
+
attribute :title, :string
|
|
108
|
+
attribute :count, :integer
|
|
109
|
+
xml do
|
|
110
|
+
root "item"
|
|
111
|
+
map_element "title", to: :title
|
|
112
|
+
map_element "count", to: :count
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
instance = item.new(title: "Widget", count: 5)
|
|
117
|
+
xml = instance.to_xml
|
|
118
|
+
expect(xml).to include("<title>Widget</title>")
|
|
119
|
+
expect(xml).to include("<count>5</count>")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "handles XmlOrderable on plain model classes" do
|
|
123
|
+
plain_model = Class.new do
|
|
124
|
+
attr_accessor :data
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
Class.new do
|
|
128
|
+
include Lutaml::Model::Serialize
|
|
129
|
+
|
|
130
|
+
const_set(:MODEL_CLASS, plain_model)
|
|
131
|
+
model plain_model
|
|
132
|
+
attribute :data, :string
|
|
133
|
+
xml do
|
|
134
|
+
root "data"
|
|
135
|
+
map_element "data", to: :data
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
expect(plain_model.ancestors).to include(Lutaml::Xml::XmlOrderable)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "uses REXML adapter by default under Opal" do
|
|
143
|
+
expect(Lutaml::Model::Config.xml_adapter_type).to eq(:rexml)
|
|
144
|
+
end
|
|
145
|
+
end
|
data/spec/lutaml/xml/xml_spec.rb
CHANGED
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
|
+
require "open3"
|
|
4
5
|
require "lutaml/xml"
|
|
5
6
|
|
|
6
7
|
RSpec.describe Lutaml::Xml do
|
|
7
|
-
|
|
8
|
-
let(:lib_path) { File.expand_path("../../../lib", __dir__) }
|
|
8
|
+
let(:lib_path) { File.expand_path("../../../lib", __dir__) }
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
def run_ruby(script)
|
|
11
|
+
stdout, stderr, status = Open3.capture3(
|
|
12
|
+
RbConfig.ruby, "-I#{lib_path}", "-e", script
|
|
13
|
+
)
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
[stdout + stderr, status]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "standalone loading" do
|
|
19
|
+
it "lazy-loads the schema namespace from the XML entry point" do
|
|
20
|
+
script = <<~RUBY
|
|
21
|
+
require "lutaml/xml"
|
|
22
|
+
abort "missing Schema autoload" unless Lutaml::Xml.autoload?(:Schema)
|
|
23
|
+
unless Lutaml::Xml::Schema.const_defined?(:Xsd, false)
|
|
24
|
+
abort "missing Xsd autoload"
|
|
25
|
+
end
|
|
26
|
+
puts :ok
|
|
27
|
+
RUBY
|
|
28
|
+
|
|
29
|
+
result, status = run_ruby(script)
|
|
30
|
+
|
|
31
|
+
expect(status.success?).to be(true), result
|
|
16
32
|
expect(result).to include("ok")
|
|
17
33
|
end
|
|
18
34
|
end
|
|
@@ -22,6 +38,44 @@ RSpec.describe Lutaml::Xml do
|
|
|
22
38
|
expect(described_class::Schema.const_defined?(:Xsd, false))
|
|
23
39
|
.to be(!Lutaml::Model::RuntimeCompatibility.opal?)
|
|
24
40
|
end
|
|
41
|
+
|
|
42
|
+
it "does not autoload schema constants when loaded under Opal" do
|
|
43
|
+
script = <<~'RUBY'
|
|
44
|
+
require "lutaml/model/runtime_compatibility"
|
|
45
|
+
|
|
46
|
+
module Lutaml
|
|
47
|
+
module Model
|
|
48
|
+
module RuntimeCompatibility
|
|
49
|
+
def self.opal?
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
require "lutaml/xml/schema"
|
|
57
|
+
|
|
58
|
+
schema_constants = %i[
|
|
59
|
+
Xsd XsdSchema RelaxngSchema Builder BuiltinTypes
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
loaded_constants = schema_constants.select do |constant_name|
|
|
63
|
+
Lutaml::Xml::Schema.autoload?(constant_name) ||
|
|
64
|
+
Lutaml::Xml::Schema.const_defined?(constant_name, false)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if loaded_constants.any?
|
|
68
|
+
abort "loaded schema constants: #{loaded_constants.join(', ')}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
puts :ok
|
|
72
|
+
RUBY
|
|
73
|
+
|
|
74
|
+
result, status = run_ruby(script)
|
|
75
|
+
|
|
76
|
+
expect(status.success?).to be(true), result
|
|
77
|
+
expect(result).to include("ok")
|
|
78
|
+
end
|
|
25
79
|
end
|
|
26
80
|
|
|
27
81
|
describe "schema methods" do
|
|
@@ -66,9 +120,6 @@ RSpec.describe Lutaml::Xml do
|
|
|
66
120
|
hide_const("Ox") if Object.const_defined?(:Ox)
|
|
67
121
|
hide_const("Oga") if Object.const_defined?(:Oga)
|
|
68
122
|
hide_const("REXML") if Object.const_defined?(:REXML)
|
|
69
|
-
|
|
70
|
-
# Stub require to prevent any actual requires during testing
|
|
71
|
-
allow(Lutaml::Model::Utils).to receive(:require).and_return(true)
|
|
72
123
|
end
|
|
73
124
|
|
|
74
125
|
context "when Nokogiri is available" do
|
|
@@ -101,9 +152,9 @@ RSpec.describe Lutaml::Xml do
|
|
|
101
152
|
end
|
|
102
153
|
end
|
|
103
154
|
|
|
104
|
-
context "when no adapters are
|
|
105
|
-
it "
|
|
106
|
-
expect(described_class.detect_xml_adapter).to
|
|
155
|
+
context "when no adapters are detected" do
|
|
156
|
+
it "falls back to moxml default (:nokogiri)" do
|
|
157
|
+
expect(described_class.detect_xml_adapter).to eq(:nokogiri)
|
|
107
158
|
end
|
|
108
159
|
end
|
|
109
160
|
|