diff --git a/.rspec-opal b/.rspec-opal new file mode 100644 index 000000000..cafdac1a0 --- /dev/null +++ b/.rspec-opal @@ -0,0 +1,7 @@ +--default-path=spec +--format documentation +--color +--require spec_helper +-q oga/setup_opal +-q ll/setup_opal +--opal-opt=-s,tmpdir diff --git a/Opalfile b/Opalfile new file mode 100644 index 000000000..50b8d6111 --- /dev/null +++ b/Opalfile @@ -0,0 +1,6 @@ +add_load_path "lib" + +add_gem_dependency "moxml" +add_gem_dependency "equivalent-xml" +add_gem_dependency "toml-rb" +add_gem_dependency "lutaml-xsd" diff --git a/lib/lutaml/model.rb b/lib/lutaml/model.rb index 929e286ab..fe6022ea1 100644 --- a/lib/lutaml/model.rb +++ b/lib/lutaml/model.rb @@ -1,6 +1,13 @@ # frozen_string_literal: true require "moxml" +if RUBY_ENGINE == 'opal' + require 'corelib/array/pack' + require 'corelib/trace_point' + require 'moxml' + require 'lutaml/model/xml/oga_adapter' + require 'lutaml/model/schema/xml_compiler' +end require_relative "model/uninitialized_class" require_relative "model/errors" require_relative "model/services" diff --git a/lib/lutaml/model/attribute.rb b/lib/lutaml/model/attribute.rb index 5b9d032ae..b21763132 100644 --- a/lib/lutaml/model/attribute.rb +++ b/lib/lutaml/model/attribute.rb @@ -69,9 +69,13 @@ def self.cast_from_string!(type) raise ArgumentError, "Unknown Lutaml::Model::Type: #{type}" end + def reserved_methods + Lutaml::Model::Serializable.instance_methods - %i[open] + end + def initialize(name, type, options = {}) validate_name!( - name, reserved_methods: Lutaml::Model::Serializable.instance_methods + name, reserved_methods: reserved_methods ) @name = name diff --git a/lib/lutaml/model/register.rb b/lib/lutaml/model/register.rb index 774ff106a..8f44cf668 100644 --- a/lib/lutaml/model/register.rb +++ b/lib/lutaml/model/register.rb @@ -71,11 +71,9 @@ def get_class_without_register(klass_name) private def get_type_class(klass_name) - if klass_name.is_a?(String) - Lutaml::Model::Type.const_get(klass_name) - elsif klass_name.is_a?(Symbol) - Lutaml::Model::Type.lookup(klass_name) - end + Lutaml::Model::Type.lookup(klass_name) + rescue UnknownTypeError + Lutaml::Model::Type.const_get(klass_name) end def built_in_type?(type) diff --git a/lib/lutaml/model/schema/xml_compiler.rb b/lib/lutaml/model/schema/xml_compiler.rb index ba02172ad..7acd7b467 100644 --- a/lib/lutaml/model/schema/xml_compiler.rb +++ b/lib/lutaml/model/schema/xml_compiler.rb @@ -2,7 +2,7 @@ require "erb" require "tmpdir" -require "lutaml/xsd" +require "lutaml/xsd" unless RUBY_ENGINE == 'opal' require_relative "xml_compiler/complex_content_restriction" require_relative "xml_compiler/attribute_group" require_relative "xml_compiler/complex_content" diff --git a/lib/lutaml/model/serialize.rb b/lib/lutaml/model/serialize.rb index eeb5aeb69..6bb4761e9 100644 --- a/lib/lutaml/model/serialize.rb +++ b/lib/lutaml/model/serialize.rb @@ -502,8 +502,12 @@ def empty_object(attr) def ensure_utf8(value) case value when String - value.encode("UTF-8", invalid: :replace, undef: :replace, - replace: "") + if RUBY_ENGINE == 'opal' + value + else + value.encode("UTF-8", invalid: :replace, undef: :replace, + replace: "") + end when Array value.map { |v| ensure_utf8(v) } when ::Hash diff --git a/lib/lutaml/model/utils.rb b/lib/lutaml/model/utils.rb index 00ac7223c..a31e04098 100644 --- a/lib/lutaml/model/utils.rb +++ b/lib/lutaml/model/utils.rb @@ -19,9 +19,10 @@ def classify(str) str = str.sub(/^[a-z\d]*/) { |match| camel_case(match) || match } str.gsub("::", "/").gsub(%r{(?:_|-|(/))([a-z\d]*)}i) do - word = Regexp.last_match(2) + match1, match2 = Regexp.last_match(1), Regexp.last_match(2) + word = match2 substituted = camel_case(word) || word - Regexp.last_match(1) ? "::#{substituted}" : substituted + match1 ? "::#{substituted}" : substituted end end diff --git a/spec/lutaml/model/attribute_spec.rb b/spec/lutaml/model/attribute_spec.rb index a1eae4cc7..4db5d0a03 100644 --- a/spec/lutaml/model/attribute_spec.rb +++ b/spec/lutaml/model/attribute_spec.rb @@ -114,7 +114,7 @@ it "raise exception if option is not allowed" do expect do validate_options.call({ foo: "bar" }) - end.to raise_error(Lutaml::Model::InvalidAttributeOptionsError, "Invalid options given for `name` [:foo]") + end.to raise_error(Lutaml::Model::InvalidAttributeOptionsError, sym_normal("Invalid options given for `name` [:foo]")) end it "raise exception if pattern is given with non string type" do diff --git a/spec/lutaml/model/choice_spec.rb b/spec/lutaml/model/choice_spec.rb index da4f1cdb3..8d7e2620a 100644 --- a/spec/lutaml/model/choice_spec.rb +++ b/spec/lutaml/model/choice_spec.rb @@ -119,7 +119,7 @@ class Person < Lutaml::Model::Serializable expect do valid_instance.validate! end.to raise_error(Lutaml::Model::ValidationError) do |error| - expect(error.error_messages.join("\n")).to include("Attributes `[:signed, :unsigned, :watermarked, :encrypted]` count exceeds the upper bound `3`") + expect(error.error_messages.join("\n")).to include(sym_normal("Attributes `[:signed, :unsigned, :watermarked, :encrypted]` count exceeds the upper bound `3`")) end end end @@ -160,7 +160,7 @@ class Person < Lutaml::Model::Serializable expect do valid_instance.validate! end.to raise_error(Lutaml::Model::ValidationError) do |error| - expect(error.error_messages.join("\n")).to eq("Attributes `[:email, :phone, :check]` count exceeds the upper bound `2`") + expect(error.error_messages.join("\n")).to eq(sym_normal("Attributes `[:email, :phone, :check]` count exceeds the upper bound `2`")) end end diff --git a/spec/lutaml/model/custom_vobject_adapter_spec.rb b/spec/lutaml/model/custom_vobject_adapter_spec.rb index 7ab97c25e..0f45a6790 100644 --- a/spec/lutaml/model/custom_vobject_adapter_spec.rb +++ b/spec/lutaml/model/custom_vobject_adapter_spec.rb @@ -126,8 +126,7 @@ def initialize(data) def parse @data.each_line do |line| - line.chomp! - process_line(line) + process_line(line.chomp) end @objects end diff --git a/spec/lutaml/model/liquefiable_spec.rb b/spec/lutaml/model/liquefiable_spec.rb index 13175e54b..aa691befc 100644 --- a/spec/lutaml/model/liquefiable_spec.rb +++ b/spec/lutaml/model/liquefiable_spec.rb @@ -1,3 +1,5 @@ +unless RUBY_ENGINE == 'opal' + require "spec_helper" require "liquid" require_relative "../../fixtures/address" @@ -257,3 +259,5 @@ class CeramicCollection < Lutaml::Model::Serializable end end end + +end diff --git a/spec/lutaml/model/multiple_mapping_spec.rb b/spec/lutaml/model/multiple_mapping_spec.rb index ce6ae22ec..4fce497dc 100644 --- a/spec/lutaml/model/multiple_mapping_spec.rb +++ b/spec/lutaml/model/multiple_mapping_spec.rb @@ -253,11 +253,11 @@ def desc_from_xml(model, values) context "with Nokogiri adapter" do it_behaves_like "xml adapter with multiple mappings", Lutaml::Model::Xml::NokogiriAdapter - end + end unless RUBY_ENGINE == 'opal' context "with Ox adapter" do it_behaves_like "xml adapter with multiple mappings", Lutaml::Model::Xml::OxAdapter - end + end unless RUBY_ENGINE == 'opal' end context "with CustomModel" do @@ -331,11 +331,11 @@ def desc_from_xml(model, values) context "with Nokogiri adapter" do it_behaves_like "xml adapter with custom methods", Lutaml::Model::Xml::NokogiriAdapter - end + end unless RUBY_ENGINE == 'opal' context "with Ox adapter" do it_behaves_like "xml adapter with custom methods", Lutaml::Model::Xml::OxAdapter - end + end unless RUBY_ENGINE == 'opal' end end end diff --git a/spec/lutaml/model/root_mappings_spec.rb b/spec/lutaml/model/root_mappings_spec.rb index 980f6d8ff..941aa7a6c 100644 --- a/spec/lutaml/model/root_mappings_spec.rb +++ b/spec/lutaml/model/root_mappings_spec.rb @@ -293,5 +293,5 @@ class CeramicCollectionWithoutCollectionTrue < Lutaml::Model::Serializable describe Lutaml::Model::Toml::TomlRbAdapter do it_behaves_like "having root mappings", :toml - end + end unless RUBY_ENGINE == 'opal' # Until toml-rb is ported. end diff --git a/spec/lutaml/model/serializable_spec.rb b/spec/lutaml/model/serializable_spec.rb index ce9703318..99aee447d 100644 --- a/spec/lutaml/model/serializable_spec.rb +++ b/spec/lutaml/model/serializable_spec.rb @@ -229,7 +229,7 @@ def address_from_xml(model, value) it "raises an error for invalid options" do expect { RestrictTestClass.restrict(:foo, new_option: :bar) } - .to raise_error(Lutaml::Model::InvalidAttributeOptionsError, "Invalid options given for `foo` [:new_option]") + .to raise_error(Lutaml::Model::InvalidAttributeOptionsError, sym_normal("Invalid options given for `foo` [:new_option]")) end it "raises an error if the attribute does not exist" do @@ -553,8 +553,8 @@ def address_from_xml(model, value) end describe "invalid format handling for XML" do - it_behaves_like "invalid format error", :xml, :nokogiri, :from_xml, :xml - it_behaves_like "invalid format error", :xml, :ox, :from_xml, :xml + it_behaves_like "invalid format error", :xml, :nokogiri, :from_xml, :xml unless RUBY_ENGINE == 'opal' + it_behaves_like "invalid format error", :xml, :ox, :from_xml, :xml unless RUBY_ENGINE == 'opal' it_behaves_like "invalid format error", :xml, :oga, :from_xml, :xml end @@ -567,10 +567,10 @@ def address_from_xml(model, value) end describe "invalid format handling for invalid TOML" do - it_behaves_like "invalid format error", :toml, :toml_rb, :from_toml, :toml + it_behaves_like "invalid format error", :toml, :toml_rb, :from_toml, :toml unless RUBY_ENGINE == 'opal' # Only test Tomlib if not on problematic platform (Windows Ruby < 3.3) - if RUBY_PLATFORM.include?("mingw") && RUBY_VERSION < "3.3" + if RUBY_ENGINE != 'opal' && RUBY_PLATFORM.include?("mingw") && RUBY_VERSION < "3.3" # NOTE: Skipped Tomlib case because it causes segmentation fault on # Windows with Ruby < 3.3 it "skips Tomlib test on Windows Ruby < 3.3 due to segfault risk" do diff --git a/spec/lutaml/model/toml_adapter_spec.rb b/spec/lutaml/model/toml_adapter_spec.rb index 8d90c3bdc..0604fbc5c 100644 --- a/spec/lutaml/model/toml_adapter_spec.rb +++ b/spec/lutaml/model/toml_adapter_spec.rb @@ -1,3 +1,5 @@ +unless RUBY_ENGINE == 'opal' + require "spec_helper" require "lutaml/model/toml/toml_rb_adapter" require "lutaml/model/toml/tomlib_adapter" @@ -39,3 +41,5 @@ it_behaves_like "a TOML adapter", described_class end end + +end diff --git a/spec/lutaml/model/type/string_spec.rb b/spec/lutaml/model/type/string_spec.rb index 36d029a6b..ecd6c2cb3 100644 --- a/spec/lutaml/model/type/string_spec.rb +++ b/spec/lutaml/model/type/string_spec.rb @@ -67,7 +67,9 @@ context "with hash" do let(:value) { { a: 1, b: 2 } } let(:expected_value) do - if RUBY_VERSION < "3.4.0" + if RUBY_ENGINE == 'opal' + '{"a"=>1, "b"=>2}' + elsif RUBY_VERSION < "3.4.0" "{:a=>1, :b=>2}" else "{a: 1, b: 2}" diff --git a/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb b/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb index 04124518e..dbfe6c371 100644 --- a/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +++ b/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb @@ -356,11 +356,11 @@ class OwnedEnd < Lutaml::Model::Serializable describe Lutaml::Model::Xml::NokogiriAdapter do it_behaves_like "an XML namespace parser", described_class - end + end unless RUBY_ENGINE == 'opal' describe Lutaml::Model::Xml::OxAdapter do it_behaves_like "an XML namespace parser", described_class - end + end unless RUBY_ENGINE == 'opal' describe Lutaml::Model::Xml::OgaAdapter do it_behaves_like "an XML namespace parser", described_class diff --git a/spec/lutaml/model/xml_adapter_spec.rb b/spec/lutaml/model/xml_adapter_spec.rb index a1f054862..09968ecff 100644 --- a/spec/lutaml/model/xml_adapter_spec.rb +++ b/spec/lutaml/model/xml_adapter_spec.rb @@ -198,11 +198,11 @@ class Maths < Lutaml::Model::Serializable describe Lutaml::Model::Xml::NokogiriAdapter do it_behaves_like "an XML adapter", described_class - end + end unless RUBY_ENGINE == 'opal' describe Lutaml::Model::Xml::OxAdapter do it_behaves_like "an XML adapter", described_class - end + end unless RUBY_ENGINE == 'opal' describe Lutaml::Model::Xml::OgaAdapter do it_behaves_like "an XML adapter", described_class diff --git a/spec/lutaml/model/xml_mapping_spec.rb b/spec/lutaml/model/xml_mapping_spec.rb index 02e250c9e..eba4451d3 100644 --- a/spec/lutaml/model/xml_mapping_spec.rb +++ b/spec/lutaml/model/xml_mapping_spec.rb @@ -374,7 +374,7 @@ class Schema < Lutaml::Model::Serializable end # Skipping for OX because it does not handle namespaces - context "when overriding child namespace prefix", skip: adapter_class == Lutaml::Model::Xml::OxAdapter do + context "when overriding child namespace prefix", skip: adapter_class.name == "Lutaml::Model::Xml::OxAdapter" do let(:input_xml) do <<~XML