lutaml-lml 0.1.3 → 0.1.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/lib/lutaml/lml/data_processor/attribute_processing.rb +1 -0
- data/lib/lutaml/lml/data_processor/instance_processing.rb +11 -2
- data/lib/lutaml/lml/executor/condition_evaluator.rb +1 -1
- data/lib/lutaml/lml/executor.rb +3 -4
- data/lib/lutaml/lml/grammar/concerns/primitives.rb +10 -4
- data/lib/lutaml/lml/grammar/concerns/view_rules.rb +1 -3
- data/lib/lutaml/lml/literal_value.rb +32 -0
- data/lib/lutaml/lml/models/instance_collection.rb +1 -1
- data/lib/lutaml/lml/models/top_element_attribute.rb +64 -1
- data/lib/lutaml/lml/version.rb +1 -1
- data/lib/lutaml/lml.rb +3 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f72188a69457d2cf82445867f2b726dd621d63e82d79c7e56b01241e0d15ec84
|
|
4
|
+
data.tar.gz: 402135ddb2bf31953c21f6166c859c6b5f67d24d1a9e18e8369eb3646a413381
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d07e5279b6c0d983d1ba1384ef3579aa3d493fba0520aedadfd97ac11a42bfca1fd2e96e621e6551e8dd22bef52e30136779cdf88e8bbe81e611b762e1efa3cd
|
|
7
|
+
data.tar.gz: 20e402c37d1506fd86c4ded5fac0bb010dc58d3cdda8efcf3e92cd287ec8025331375310b7e40093741af136aaaf4f61d78a44456fe59b2d75dffe5e1d57568b
|
|
@@ -26,8 +26,7 @@ module Lutaml
|
|
|
26
26
|
key = INSTANCE_KEY_HANDLERS.keys.find { |k| instance.key?(k) }
|
|
27
27
|
next unless key
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
key == :instance ? (acc[:instances] << result) : (acc[key] = result)
|
|
29
|
+
append_result(acc, key, public_send(INSTANCE_KEY_HANDLERS[key], instance[key]))
|
|
31
30
|
end
|
|
32
31
|
end
|
|
33
32
|
|
|
@@ -57,6 +56,16 @@ module Lutaml
|
|
|
57
56
|
def handle_instance_template(value, result)
|
|
58
57
|
result[:template] = process_attributes(value[:attributes])
|
|
59
58
|
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def append_result(acc, key, result)
|
|
63
|
+
case key
|
|
64
|
+
when :instance then acc[:instances] << result
|
|
65
|
+
when :collections then (acc[:collections] ||= []) << result
|
|
66
|
+
else (acc[key] ||= []).concat(result)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
60
69
|
end
|
|
61
70
|
end
|
|
62
71
|
end
|
|
@@ -30,8 +30,8 @@ module Lutaml
|
|
|
30
30
|
# Evaluate all validation conditions against a collection of instances.
|
|
31
31
|
# Returns an array of error strings (empty if all pass).
|
|
32
32
|
def self.evaluate(collection, instances)
|
|
33
|
-
return [] unless collection.validations&.any?
|
|
34
33
|
return [] unless collection.is_a?(Collection)
|
|
34
|
+
return [] unless collection.validations&.any?
|
|
35
35
|
|
|
36
36
|
new(instances).evaluate_all(collection.validations)
|
|
37
37
|
end
|
data/lib/lutaml/lml/executor.rb
CHANGED
|
@@ -73,10 +73,9 @@ module Lutaml
|
|
|
73
73
|
def validate_collections(doc, instances)
|
|
74
74
|
return [] unless doc.instances&.collections
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
ConditionEvaluator.evaluate(collection, instances)
|
|
76
|
+
Array(doc.instances.collections).flat_map do |collection|
|
|
77
|
+
ConditionEvaluator.evaluate(collection, instances)
|
|
78
|
+
end
|
|
80
79
|
end
|
|
81
80
|
|
|
82
81
|
# --- Export ---
|
|
@@ -19,12 +19,18 @@ module Lutaml
|
|
|
19
19
|
rule(:whitespace?) { whitespace.maybe }
|
|
20
20
|
rule(:newline) { match('[\r\n]') }
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
# Body of a string delimited by `char`, captured as `label`.
|
|
23
|
+
def quoted(char, label)
|
|
24
|
+
str(char) >> (str(char).absent? >> any).repeat.as(label) >> str(char)
|
|
24
25
|
end
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
# A string in either quote style. Delimiters must match, so `"a'`
|
|
28
|
+
# stays a parse error.
|
|
29
|
+
def any_quoted(label)
|
|
30
|
+
quoted('"', label) | quoted("'", label)
|
|
27
31
|
end
|
|
32
|
+
|
|
33
|
+
rule(:quoted_string) { any_quoted(:string) }
|
|
28
34
|
rule(:boolean) { (str("true") | str("false")).as(:boolean) }
|
|
29
35
|
rule(:number) { (match("[0-9]").repeat(1) >> str(".") >> match("[0-9]").repeat(1)).as(:float) | match("[0-9]").repeat(1).as(:number) }
|
|
30
36
|
rule(:variable) { (quoted_string | match("[a-zA-Z0-9_]").repeat(1)) }
|
|
@@ -22,9 +22,7 @@ module Lutaml
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
rule(:view_import) do
|
|
25
|
-
kw_view_import >>
|
|
26
|
-
str('"') >> quoted_string_content.as(:path) >> str('"') >>
|
|
27
|
-
whitespace?
|
|
25
|
+
kw_view_import >> any_quoted(:path) >> whitespace?
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
# Entity names in show/hide lists must be space-free: general
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Lutaml
|
|
6
|
+
module Lml
|
|
7
|
+
# The type of an LML attribute literal: a scalar, a list, or a map.
|
|
8
|
+
#
|
|
9
|
+
# This exists as a subclass rather than using Lutaml::Model::Type::Value
|
|
10
|
+
# directly because lutaml-model's key-value serializer tests the declared
|
|
11
|
+
# attribute type with a strict `attribute_type < Type::Value`. Type::Value
|
|
12
|
+
# is not a strict subclass of itself, so declaring it hands the serializer
|
|
13
|
+
# the raw wrapper object: JSON calls to_json(state) on it and raises
|
|
14
|
+
# ArgumentError, and Psych emits a !ruby/object tag that from_yaml then
|
|
15
|
+
# refuses to load. A subclass puts the attribute on the working path, where
|
|
16
|
+
# the serializer asks the wrapper for its value instead.
|
|
17
|
+
#
|
|
18
|
+
# Deleting this class needs two upstream changes, not one: that `<` widened
|
|
19
|
+
# to `<=`, and the serializer no longer re-wrapping a value it already
|
|
20
|
+
# wrapped. Widening `<` alone still leaves the nested wrapper below.
|
|
21
|
+
class LiteralValue < Lutaml::Model::Type::Value
|
|
22
|
+
# The serializer re-wraps an already-wrapped value before asking it for a
|
|
23
|
+
# format, so #value has to see through that extra layer. Every to_<format>
|
|
24
|
+
# method lutaml-model generates reads through here, which is why this is
|
|
25
|
+
# one override rather than one per format.
|
|
26
|
+
def value
|
|
27
|
+
wrapped = super
|
|
28
|
+
wrapped.is_a?(LiteralValue) ? wrapped.value : wrapped
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -6,7 +6,7 @@ module Lutaml
|
|
|
6
6
|
attribute :instances, "Lutaml::Lml::Instance", collection: true, default: []
|
|
7
7
|
attribute :imports, "Lutaml::Lml::InstancesImport", collection: true, default: []
|
|
8
8
|
attribute :exports, "Lutaml::Lml::InstancesExport", collection: true, default: []
|
|
9
|
-
attribute :collections, "Lutaml::Lml::Collection", default: []
|
|
9
|
+
attribute :collections, "Lutaml::Lml::Collection", collection: true, default: []
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -22,10 +22,73 @@ module Lutaml
|
|
|
22
22
|
|
|
23
23
|
# LML-specific attributes
|
|
24
24
|
attribute :properties, "Lutaml::Lml::TopElementAttribute", collection: true, default: -> { [] }
|
|
25
|
-
attribute :value,
|
|
25
|
+
attribute :value, LiteralValue
|
|
26
26
|
attribute :attributes, "Lutaml::Lml::TopElementAttribute", collection: true, default: -> { [] }
|
|
27
27
|
attribute :extended, :boolean
|
|
28
28
|
attribute :instances, "Lutaml::Lml::Instance", collection: true, default: -> { [] }
|
|
29
|
+
|
|
30
|
+
# Declared in full because a mapping block replaces the defaults. The
|
|
31
|
+
# rules below are the defaults, 1:1, except for `value`.
|
|
32
|
+
#
|
|
33
|
+
# `value` needs custom methods because a list literal reaches the model
|
|
34
|
+
# as a bare Array, and lutaml-model refuses one on a non-collection
|
|
35
|
+
# attribute: Attribute#cast splits it, then valid_collection! raises
|
|
36
|
+
# CollectionTrueMissingError. A custom `from` returns before that check,
|
|
37
|
+
# so a non-empty list survives a round trip without changing the
|
|
38
|
+
# serialized form. An empty list still does not: the transform skips a
|
|
39
|
+
# blank value before reaching the custom method, so `[]` reloads as nil.
|
|
40
|
+
key_value do
|
|
41
|
+
map "name", to: :name
|
|
42
|
+
map "visibility", to: :visibility
|
|
43
|
+
map "type", to: :type
|
|
44
|
+
map "id", to: :id
|
|
45
|
+
map "contain", to: :contain
|
|
46
|
+
map "static", to: :static
|
|
47
|
+
map "cardinality", to: :cardinality
|
|
48
|
+
map "keyword", to: :keyword
|
|
49
|
+
map "is_derived", to: :is_derived
|
|
50
|
+
map "is_static", to: :is_static
|
|
51
|
+
map "is_read_only", to: :is_read_only
|
|
52
|
+
map "stereotype", to: :stereotype
|
|
53
|
+
map "definition", to: :definition
|
|
54
|
+
map "association", to: :association
|
|
55
|
+
map "default", to: :default
|
|
56
|
+
map "properties", to: :properties
|
|
57
|
+
map "value", to: :value, with: { to: :value_to, from: :value_from }
|
|
58
|
+
map "attributes", to: :attributes
|
|
59
|
+
map "extended", to: :extended
|
|
60
|
+
map "instances", to: :instances
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Public because lutaml-model invokes mapping methods via public_send.
|
|
64
|
+
#
|
|
65
|
+
# Skipping nil keeps the key out of the output, which is what the default
|
|
66
|
+
# mapping does. `false` is a real literal, so the guard tests for nil
|
|
67
|
+
# rather than truthiness.
|
|
68
|
+
def value_to(model, doc)
|
|
69
|
+
literal = model.value
|
|
70
|
+
return if literal.nil?
|
|
71
|
+
|
|
72
|
+
doc["value"] = unwrap_literal(literal)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# lutaml-model runs this on a throwaway mapper instance, so `self` is not
|
|
76
|
+
# the object being deserialized - `model` is. Writing to `self.value`
|
|
77
|
+
# here would update an object that is discarded a moment later.
|
|
78
|
+
def value_from(model, value)
|
|
79
|
+
model.value = value
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
# A LiteralValue sits at the top level for a map literal, and inside the
|
|
85
|
+
# array for a list of references. Writing one through unwrapped raises
|
|
86
|
+
# ArgumentError in the adapter.
|
|
87
|
+
def unwrap_literal(value)
|
|
88
|
+
return value.map { |item| unwrap_literal(item) } if value.is_a?(::Array)
|
|
89
|
+
|
|
90
|
+
value.is_a?(LiteralValue) ? value.value : value
|
|
91
|
+
end
|
|
29
92
|
end
|
|
30
93
|
end
|
|
31
94
|
end
|
data/lib/lutaml/lml/version.rb
CHANGED
data/lib/lutaml/lml.rb
CHANGED
|
@@ -52,6 +52,9 @@ module Lutaml
|
|
|
52
52
|
autoload :HasAttributes, "lutaml/lml/has_attributes"
|
|
53
53
|
autoload :VERSION, "lutaml/lml/version"
|
|
54
54
|
|
|
55
|
+
# Type classes (Lutaml::Model::Type::Value subclasses, not models)
|
|
56
|
+
autoload :LiteralValue, "lutaml/lml/literal_value"
|
|
57
|
+
|
|
55
58
|
# Model classes (in Lutaml::Lml namespace, files in models/ directory)
|
|
56
59
|
autoload :Action, "lutaml/lml/models/action"
|
|
57
60
|
autoload :Association, "lutaml/lml/models/association"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lutaml-lml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -123,6 +123,7 @@ files:
|
|
|
123
123
|
- lib/lutaml/lml/layout.rb
|
|
124
124
|
- lib/lutaml/lml/layout/engine.rb
|
|
125
125
|
- lib/lutaml/lml/layout/graph_viz_engine.rb
|
|
126
|
+
- lib/lutaml/lml/literal_value.rb
|
|
126
127
|
- lib/lutaml/lml/model_compiler.rb
|
|
127
128
|
- lib/lutaml/lml/models/action.rb
|
|
128
129
|
- lib/lutaml/lml/models/association.rb
|