Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
17 changes: 14 additions & 3 deletions lib/unitsml/unitsdb/database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,29 @@
module Unitsml
module Unitsdb
class Database < ::Unitsdb::Database
DATABASE = nil
def self.load_opal_payload(payload)
@opal_payload = payload
end

def self.from_db(dir_path, context: Unitsml::Configuration.context.id)
return super unless RUBY_ENGINE == "opal"

context_id = context.to_sym
raise Unitsml::Errors::OpalPayloadNotBundledError unless DATABASE
raise Unitsml::Errors::OpalPayloadNotBundledError unless opal_payload

# Ensure the UnitsML context is registered when context: is direct.
Unitsml::Configuration.context

from_hash(DATABASE, register: context_id)
from_hash(opal_payload, register: context_id)
end

def self.opal_payload
return @opal_payload if instance_variable_defined?(:@opal_payload)
return unless const_defined?(:DATABASE, false)

@opal_payload = const_get(:DATABASE, false)
end
private_class_method :opal_payload

Configuration.register_model(self, id: :database)
end
Expand Down
88 changes: 87 additions & 1 deletion spec/unitsml/unitsdb/database_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,57 @@
end

context "when running on opal" do
before { stub_const("RUBY_ENGINE", "opal") }
def clear_opal_payload
return unless described_class.instance_variable_defined?(:@opal_payload)

described_class.remove_instance_variable(:@opal_payload)
end

before do
stub_const("RUBY_ENGINE", "opal")
clear_opal_payload
end

after do
clear_opal_payload
end

def allow_from_hash(database_class)
allow(database_class).to receive(:from_hash).and_return(:database)
end

def expect_loaded_payload(database_class, payload)
expect(database_class).to have_received(:from_hash)
.with(payload, register: :unitsml_ruby)
end

it "raises a clear error when the bundled payload is missing" do
expect do
described_class.from_db("/does/not/matter", context: :unitsml_ruby)
end.to raise_error(Unitsml::Errors::OpalPayloadNotBundledError,
/not bundled/)
end

it "loads the bundled Opal payload" do
payload = { "units" => [] }
described_class.load_opal_payload(payload)
allow_from_hash(described_class)

expect(described_class.from_db("/does/not/matter",
context: :unitsml_ruby)).to eq(:database)
expect_loaded_payload(described_class, payload)
end

it "falls back to a legacy DATABASE constant" do
payload = { "units" => [:from_const] }
subclass = Class.new(described_class)
subclass.const_set(:DATABASE, payload)
allow_from_hash(subclass)

expect(subclass.from_db("/does/not/matter",
context: :unitsml_ruby)).to eq(:database)
expect_loaded_payload(subclass, payload)
end
end
end

Expand Down Expand Up @@ -58,6 +101,49 @@
end
end

context "when running on opal with a loaded payload" do
let(:payload) { { "units" => [] } }

before do
stub_const("RUBY_ENGINE", "opal")
allow(Unitsml::Configuration).to receive(:context).and_call_original
clear_unitsdb_database_cache
clear_unitsml_database_cache
Unitsml::Configuration.context(force_populate: true)
Unitsml::Unitsdb::Database.load_opal_payload(payload)
allow(Unitsml::Unitsdb::Database)
.to receive(:from_hash)
.and_return(:opal_database)
end

after do
clear_unitsdb_database_cache
clear_unitsml_database_cache
clear_opal_payload
end

def clear_unitsdb_database_cache
Unitsdb.instance_variable_set(:@databases, nil)
end

def clear_unitsml_database_cache
described_class.instance_variable_set(:@database, nil)
end

def clear_opal_payload
database_class = Unitsml::Unitsdb::Database
return unless database_class.instance_variable_defined?(:@opal_payload)

database_class.remove_instance_variable(:@opal_payload)
end

it "loads the UnitsML database through the real unitsdb-ruby loader" do
expect(described_class.database).to eq(:opal_database)
expect(Unitsml::Unitsdb::Database).to have_received(:from_hash)
.with(payload, register: :unitsml_ruby)
end
end

context "when unitsdb-ruby exposes a database loader" do
before do
stub_const("RUBY_ENGINE", "ruby")
Expand Down
26 changes: 26 additions & 0 deletions spec/unitsml_spec.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
# frozen_string_literal: true

require "open3"
require "rbconfig"

RSpec.describe Unitsml do
it "has a version number" do
expect(Unitsml::VERSION).not_to be_nil
end

it "does not change an existing global XML adapter when required" do
lib_path = File.expand_path("../lib", __dir__)
script = <<~RUBY
require "lutaml/model"
Lutaml::Model::Config.xml_adapter_type = :nokogiri
require "unitsml"

unless Lutaml::Model::Config.xml_adapter_type == :nokogiri
abort "expected :nokogiri, got \#{Lutaml::Model::Config.xml_adapter_type.inspect}"
end
RUBY

_stdout, stderr, status = Open3.capture3(
RbConfig.ruby,
"-I",
lib_path,
"-e",
script,
)

expect(status).to be_success, stderr
end

it "parses a basic unit expression" do
formula = described_class.parse("mm")
expect(formula).to be_a(Unitsml::Formula)
Expand Down
Loading