Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/lutaml/lml/data_processor/attribute_processing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def process_attributes(obj)
end

def process_attributes_array(obj)
return [] if obj.empty?
return obj.map { |item| process_attributes(item) } unless single_key_hashes?(obj)

obj.each_with_object({}) do |item, hash|
Expand Down
13 changes: 11 additions & 2 deletions lib/lutaml/lml/data_processor/instance_processing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ def process_instances(obj)
key = INSTANCE_KEY_HANDLERS.keys.find { |k| instance.key?(k) }
next unless key

result = public_send(INSTANCE_KEY_HANDLERS[key], instance[key])
key == :instance ? (acc[:instances] << result) : (acc[key] = result)
append_result(acc, key, public_send(INSTANCE_KEY_HANDLERS[key], instance[key]))
end
end

Expand Down Expand Up @@ -57,6 +56,16 @@ def handle_instance_attributes(value, result)
def handle_instance_template(value, result)
result[:template] = process_attributes(value[:attributes])
end

private

def append_result(acc, key, result)
case key
when :instance then acc[:instances] << result
when :collections then (acc[:collections] ||= []) << result
else (acc[key] ||= []).concat(result)
end
end
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/lutaml/lml/grammar/concerns/primitives.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ module Primitives
rule(:newline) { match('[\r\n]') }

rule(:quoted_string) do
str('"') >> (str('"').absent? >> any).repeat.as(:string) >> str('"')
(str('"') >> (str('"').absent? >> any).repeat.as(:string) >> str('"')) |
(str("'") >> (str("'").absent? >> any).repeat.as(:string) >> str("'"))
end
rule(:boolean) { (str("true") | str("false")).as(:boolean) }
rule(:number) { (match("[0-9]").repeat(1) >> str(".") >> match("[0-9]").repeat(1)).as(:float) | match("[0-9]").repeat(1).as(:number) }
Expand Down
2 changes: 1 addition & 1 deletion lib/lutaml/lml/models/instance_collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class InstanceCollection < Lutaml::Model::Serializable
attribute :instances, "Lutaml::Lml::Instance", collection: true, default: []
attribute :imports, "Lutaml::Lml::InstancesImport", collection: true, default: []
attribute :exports, "Lutaml::Lml::InstancesExport", collection: true, default: []
attribute :collections, "Lutaml::Lml::Collection", default: []
attribute :collections, "Lutaml::Lml::Collection", collection: true, default: []
end
Comment thread
HassanAkbar marked this conversation as resolved.
end
end
2 changes: 1 addition & 1 deletion lib/lutaml/lml/models/top_element_attribute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class TopElementAttribute < Lutaml::Model::Serializable

# LML-specific attributes
attribute :properties, "Lutaml::Lml::TopElementAttribute", collection: true, default: []
attribute :value, "Lutaml::Lml::TopElementAttribute", collection: true
attribute :value, Lutaml::Model::Type::Value
attribute :attributes, "Lutaml::Lml::TopElementAttribute", collection: true, default: []
attribute :extended, :boolean
attribute :instances, "Lutaml::Lml::Instance", collection: true, default: []
Expand Down
6 changes: 6 additions & 0 deletions spec/fixtures/mixed_lml/instances.lml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ instances {
}
}

collection "test_suite_2" {
includes [
"gaming_pc"
]
}

import {
xml "test_data/products.xml" {
map_to Product
Expand Down
23 changes: 23 additions & 0 deletions spec/lutaml/lml/data_processor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@
expect(result).to have_key(:instances)
expect(result[:instances].length).to eq(1)
end

it "returns an empty array for an empty attributes body" do
expect(processor.process_attributes_array([])).to eq([])
end
end

describe "#process_requires" do
Expand Down Expand Up @@ -227,6 +231,25 @@
end
end

describe "#process_instances" do
it "accumulates repeated collection, import, and export blocks" do
input = [
{ collections: { name: { string: "c1" }, includes: [{ string: "x" }] } },
{ collections: { name: { string: "c2" }, includes: [{ string: "y" }] } },
{ imports: [{ format_type: "xml", file: "a.xml" }] },
{ imports: [{ format_type: "csv", file: "b.csv" }] },
{ exports: [{ format_type: "xml" }] },
{ exports: [{ format_type: "step" }] }
]

result = processor.process_instances(input)

expect(result[:collections].map { |c| c[:name] }).to eq(%w[c1 c2])
expect(result[:imports].map { |i| i[:file] }).to eq(%w[a.xml b.csv])
expect(result[:exports].map { |e| e[:format_type] }).to eq(%w[xml step])
end
end

describe "ViewProcessing" do
describe "#process_show_list" do
it "extracts entity names from array of hashes" do
Expand Down
12 changes: 12 additions & 0 deletions spec/lutaml/lml/grammar_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,18 @@ class ValidationCheck {
expect(doc.requires).to include("deps.lml")
file.close!
end

it "parses single-quoted require statements" do
file = Tempfile.new(%w[test .lml])
file.write <<~LML
require 'deps.lml'
models Test { class Foo {} }
LML
file.rewind
doc = parser.parse(file)
expect(doc.requires).to include("deps.lml")
file.close!
end
end

describe "Grammar composition" do
Expand Down
23 changes: 18 additions & 5 deletions spec/lutaml/lml/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,13 @@ def parse_lml(fname)
expect(doc.instances).to be_a(Lutaml::Lml::InstanceCollection)
end

it "maps collections correctly" do
it "maps every collection block, in order" do
collections = doc.instances.collections
expect(collections).to be_a(Lutaml::Lml::Collection)
expect(collections.name).to eq("test_suite_1")
expect(collections.includes).to eq(["laptop_123", "desktop_1", "desktop_2"])
expect(collections.validations).to eq(["count >= 3", "all? { |i| i.components.count > 0 }"])
expect(collections.map(&:name)).to eq(%w[test_suite_1 test_suite_2])
suite = collections.first
expect(suite.includes).to eq(["laptop_123", "desktop_1", "desktop_2"])
expect(suite.validations).to eq(["count >= 3", "all? { |i| i.components.count > 0 }"])
expect(collections.last.includes).to eq(["gaming_pc"])
end

it "maps imports correctly" do
Expand All @@ -256,6 +257,18 @@ def parse_lml(fname)
expect(csv_import.attributes.map(&:name)).to include("map_to", "columns")
end

it "preserves a map-valued attribute without dropping keys" do
csv_import = doc.instances.imports.find { |imp| imp.format_type == "csv" }
columns = csv_import.attributes.find { |a| a.name == "columns" }
expect(columns.value.value).to eq(
id: "component_id", type: "component_type", quantity: "count",
)
end

it "serializes parsed instance data without type errors" do
expect { doc.to_yaml }.not_to raise_error
end

it "maps exports correctly" do
exports = doc.instances.exports
expect(exports.size).to eq(2)
Expand Down
Loading