# frozen_string_literal: true RSpec.shared_examples_for "Dry::Types::Nominal without primitive" do def be_boolean satisfy { |x| x == true || x == false } end describe "#constrained?" do it "returns a boolean value" do expect(type.constrained?).to be_boolean end end describe "#default?" do it "returns a boolean value" do expect(type.default?).to be_boolean end end describe "#valid?" do it "returns a boolean value" do expect(type.valid?(1)).to be_boolean end end describe "#eql?" do it "has #eql? defined" do expect(type).to eql(type) end end describe "#==" do it "has #== defined" do expect(type).to eql(type) end end describe "#optional?" do it "returns a boolean value" do expect(type.optional?).to be_boolean end end describe "#to_s" do it "returns a custom string representation" do expect(type.to_s).to start_with("#<Dry::Types") if type.class.name.start_with?("Dry::Types") end end describe "#to_proc" do subject(:callable) { type.to_proc } it "converts a type to a proc" do expect(callable).to be_a(Proc) end end end RSpec.shared_examples_for "Dry::Types::Nominal#meta" do describe "#meta" do it "allows setting meta information" do with_meta = type.meta(foo: :bar).meta(baz: "1") expect(with_meta).to be_instance_of(type.class) expect(with_meta.meta).to eql(foo: :bar, baz: "1") end it "equalizes on empty meta" do expect(type).to eql(type.meta({})) end it "equalizes on filled meta" do expect(type).to_not eql(type.meta(i_am: "different")) end it "is locally immutable" do expect(type.meta).to be_a Hash expect(type.meta).to be_frozen expect(type.meta).not_to have_key :immutable_test derived = type.meta(immutable_test: 1) expect(derived.meta).to be_frozen expect(derived.meta).to eql(immutable_test: 1) expect(type.meta).not_to have_key :immutable_test end end describe "#pristine" do it "erases meta" do expect(type.meta(foo: :bar).pristine).to eql(type) end end end RSpec.shared_examples_for Dry::Types::Nominal do it_behaves_like "Dry::Types::Nominal without primitive" describe "#primitive" do it "returns a class" do expect(type.primitive).to be_instance_of(Class) end end describe "#constructor" do it "returns a constructor" do constructor = type.constructor(&:to_s) expect(constructor).to be_a(Dry::Types::Type) end end end RSpec.shared_examples_for "a constrained type" do |options = {inputs: Object.new}| inputs = options[:inputs] let(:fallback) { Object.new } describe "#call" do it "yields a block on failure" do Array(inputs).each do |input| expect(type.(input) { fallback }).to be(fallback) end end it "throws an error on invalid input" do Array(inputs).each do |input| expect { type.(input) }.to raise_error(Dry::Types::CoercionError) end end end describe "#constructor" do let(:wrapping_constructor) do type.constructor { |input, type| type.(input) { fallback } } end it "can be wrapped" do Array(inputs).each do |input| expect(wrapping_constructor.(input)).to be(fallback) end end end end RSpec.shared_examples_for "a nominal type" do |inputs: Object.new| describe "#call" do it "always returns the input back" do Array(inputs).each do |input| expect(type.(input) { raise }).to be(input) expect(type.(input)).to be(input) end end end end RSpec.shared_examples_for "a composable constructor" do describe "#constructor" do it "has aliases for composition" do expect(type.method(:append)).to eql(type.method(:constructor)) expect(type.method(:prepend)).to eql(type.method(:constructor)) expect(type.method(:<<)).to eql(type.method(:constructor)) expect(type.method(:>>)).to eql(type.method(:constructor)) end end end