rubocop -a

This commit is contained in:
Rob Hanlon 2020-03-10 20:13:41 -07:00
parent 016b634b8c
commit 9161759d83
69 changed files with 732 additions and 732 deletions

36
Gemfile
View File

@ -1,37 +1,37 @@
# frozen_string_literal: true
source 'https://rubygems.org'
source "https://rubygems.org"
eval_gemfile 'Gemfile.devtools'
eval_gemfile "Gemfile.devtools"
gemspec
if ENV['DRY_CONFIGURABLE_FROM_MASTER'].eql?('true')
gem 'dry-configurable', github: 'dry-rb/dry-configurable', branch: 'master'
if ENV["DRY_CONFIGURABLE_FROM_MASTER"].eql?("true")
gem "dry-configurable", github: "dry-rb/dry-configurable", branch: "master"
end
gem 'dry-schema', github: 'dry-rb/dry-schema', branch: 'master'
gem "dry-schema", github: "dry-rb/dry-schema", branch: "master"
if ENV['DRY_TYPES_FROM_MASTER'].eql?('true')
gem 'dry-types', github: 'dry-rb/dry-types', branch: 'master'
if ENV["DRY_TYPES_FROM_MASTER"].eql?("true")
gem "dry-types", github: "dry-rb/dry-types", branch: "master"
end
group :test do
gem 'dry-monads', '~> 1.0'
gem 'i18n', require: false
gem "dry-monads", "~> 1.0"
gem "i18n", require: false
end
group :tools do
gem 'pry', platform: :jruby
gem 'pry-byebug', platform: :mri
gem "pry", platform: :jruby
gem "pry-byebug", platform: :mri
end
group :benchmarks do
gem 'actionpack'
gem 'activemodel'
gem 'activerecord'
gem 'benchmark-ips'
gem 'hotch', platform: :mri
gem 'sqlite3'
gem 'virtus'
gem "actionpack"
gem "activemodel"
gem "activerecord"
gem "benchmark-ips"
gem "hotch", platform: :mri
gem "sqlite3"
gem "virtus"
end

View File

@ -1,22 +1,22 @@
#!/usr/bin/env rake
# frozen_string_literal: true
require 'bundler/gem_tasks'
require "bundler/gem_tasks"
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "lib"))
require 'rspec/core'
require 'rspec/core/rake_task'
require "rspec/core"
require "rspec/core/rake_task"
require 'dry/validation'
require "dry/validation"
RSpec::Core::RakeTask.new(:spec)
extensions = Dir['./spec/extensions/*'].map { |path| Pathname(path).basename.to_s.to_sym }
extensions = Dir["./spec/extensions/*"].map { |path| Pathname(path).basename.to_s.to_sym }
desc 'Run only core specs without extensions specs'
RSpec::Core::RakeTask.new('spec:core') do |t|
t.rspec_opts = 'spec/unit spec/integration --pattern **/*_spec.rb'
desc "Run only core specs without extensions specs"
RSpec::Core::RakeTask.new("spec:core") do |t|
t.rspec_opts = "spec/unit spec/integration --pattern **/*_spec.rb"
end
extensions.each do |ext|
@ -30,18 +30,18 @@ extensions.each do |ext|
end
end
desc 'Run all specs with all extensions enabled'
task 'spec:extensions' do
desc "Run all specs with all extensions enabled"
task "spec:extensions" do
puts "Loading extensions: #{extensions.inspect}"
Dry::Validation.load_extensions(*extensions)
Rake::Task[:spec].invoke
end
desc 'Run all specs in isolation with extension enabled'
task 'spec:isolation' => ['spec:core', *extensions.map { |ext| "spec:#{ext}" }]
desc "Run all specs in isolation with extension enabled"
task "spec:isolation" => ["spec:core", *extensions.map { |ext| "spec:#{ext}" }]
desc 'Run CI build'
desc "Run CI build"
task ci: %w[spec:core spec:isolation spec:extensions]
task default: :ci

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'active_record'
require "active_record"
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Schema.define do
create_table :users do |table|
@ -16,6 +16,6 @@ module AR
self.table_name = :users
validates :email, :age, presence: true
validates :age, numericality: { greater_than: 18 }
validates :age, numericality: {greater_than: 18}
end
end

View File

@ -1,13 +1,13 @@
# frozen_string_literal: true
require 'benchmark/ips'
require 'active_model'
require "benchmark/ips"
require "active_model"
require 'i18n'
require 'dry-validation'
require 'byebug'
require "i18n"
require "dry-validation"
require "byebug"
require_relative 'active_record_setup'
require_relative "active_record_setup"
module AM
class User
@ -16,10 +16,10 @@ module AM
attr_reader :email, :age
validates :email, :age, presence: true
validates :age, numericality: { greater_than: 18 }
validates :age, numericality: {greater_than: 18}
def initialize(attrs)
@email, @age = attrs.values_at('email', 'age')
@email, @age = attrs.values_at("email", "age")
end
end
end
@ -33,30 +33,30 @@ contract = Dry::Validation::Contract.build do
end
rule(:age) do
key.failure('must be greater than 18') if values[:age] <= 18
key.failure("must be greater than 18") if values[:age] <= 18
end
end
params = { 'email' => '', 'age' => '18' }
params = {"email" => "", "age" => "18"}
puts contract.(params).inspect
puts AR::User.new(params).validate
puts AM::User.new(params).validate
Benchmark.ips do |x|
x.report('ActiveModel') do
x.report("ActiveModel") do
user = AM::User.new(params)
user.validate
user.errors
end
x.report('ActiveRecord') do
x.report("ActiveRecord") do
user = AR::User.new(params)
user.validate
user.errors
end
x.report('dry-validation') do
x.report("dry-validation") do
contract.(params).errors
end

View File

@ -1,20 +1,20 @@
# frozen_string_literal: true
require 'benchmark/ips'
require 'active_model'
require "benchmark/ips"
require "active_model"
require 'i18n'
require 'dry-validation'
require 'byebug'
require "i18n"
require "dry-validation"
require "byebug"
COUNT = (ENV['COUNT'] || 100).to_i
COUNT = (ENV["COUNT"] || 100).to_i
FIELDS = COUNT.times.map { |i| :"field_#{i}" }
class User
include ActiveModel::Validations
attr_reader(*FIELDS)
validates(*FIELDS, presence: true, numericality: { greater_than: FIELDS.size / 2 })
validates(*FIELDS, presence: true, numericality: {greater_than: FIELDS.size / 2})
def initialize(attrs)
attrs.each do |field, value|
@ -39,13 +39,13 @@ puts contract.(params).inspect
puts User.new(params).validate
Benchmark.ips do |x|
x.report('ActiveModel::Validations') do
x.report("ActiveModel::Validations") do
user = User.new(params)
user.validate
user.errors
end
x.report('dry-validation / schema') do
x.report("dry-validation / schema") do
contract.(params).errors
end

View File

@ -1,12 +1,12 @@
# frozen_string_literal: true
require 'benchmark/ips'
require 'active_model'
require "benchmark/ips"
require "active_model"
require 'i18n'
require 'dry-validation'
require "i18n"
require "dry-validation"
require_relative 'active_record_setup'
require_relative "active_record_setup"
module AM
class User
@ -15,10 +15,10 @@ module AM
attr_reader :email, :age
validates :email, :age, presence: true
validates :age, presence: true, numericality: { greater_than: 18 }
validates :age, presence: true, numericality: {greater_than: 18}
def initialize(attrs)
@email, @age = attrs.values_at('email', 'age')
@email, @age = attrs.values_at("email", "age")
end
end
end
@ -32,29 +32,29 @@ contract = Dry::Validation::Contract.build {
end
rule(:age) do
failure('must be greater than 18') if values[:age] <= 18
failure("must be greater than 18") if values[:age] <= 18
end
}
params = { 'email' => 'jane@doe.org', 'age' => '19' }
params = {"email" => "jane@doe.org", "age" => "19"}
puts contract.(params).inspect
puts AM::User.new(params).validate
Benchmark.ips do |x|
x.report('ActiveModel::Validations') do
x.report("ActiveModel::Validations") do
user = AM::User.new(params)
user.validate
user.errors
end
x.report('ActiveRecord') do
x.report("ActiveRecord") do
user = AR::User.new(params)
user.validate
user.errors
end
x.report('dry-validation') do
x.report("dry-validation") do
contract.(params).errors
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_relative 'suite'
require_relative "suite"
class TestContract < Dry::Validation::Contract
config.messages.backend = :i18n
@ -12,12 +12,12 @@ class TestContract < Dry::Validation::Contract
end
rule(:age) do
key.failure('must be greater than 18') if values[:age] <= 18
key.failure("must be greater than 18") if values[:age] <= 18
end
end
contract = TestContract.new
input = { email: '', age: 18, address: {} }
input = {email: "", age: 18, address: {}}
profile do
10_000.times do

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_relative 'suite'
require_relative "suite"
class TestContract < Dry::Validation::Contract
config.messages.backend = :i18n
@ -12,11 +12,11 @@ class TestContract < Dry::Validation::Contract
end
rule(:age) do
key.failure('must be greater than 18') if values[:age] <= 18
key.failure("must be greater than 18") if values[:age] <= 18
end
end
input = { 'email' => 'jane@doe.org', 'age' => 19, 'address' => { 'city' => 'Krakow' } }
input = {"email" => "jane@doe.org", "age" => 19, "address" => {"city" => "Krakow"}}
contract = TestContract.new
profile do

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require_relative 'suite'
require 'hotch'
require_relative "suite"
require "hotch"
Hotch() do
1000.times do

View File

@ -1,14 +1,14 @@
# frozen_string_literal: true
require_relative 'suite'
require 'hotch'
require_relative "suite"
require "hotch"
require 'dry-validation'
require "dry-validation"
I18n.locale = :en
I18n.backend.load_translations
COUNT = ENV['COUNT'].to_i
COUNT = ENV["COUNT"].to_i
FIELDS = COUNT.times.map { |i| :"field_#{i}" }
schema = Dry::Validation.Schema do

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require_relative 'suite'
require 'hotch'
require_relative "suite"
require "hotch"
schema = Dry::Validation.Schema do
configure { config.messages = :i18n }
@ -11,7 +11,7 @@ schema = Dry::Validation.Schema do
required(:address).filled(:hash?)
end
input = { email: '', age: 18, address: {} }
input = {email: "", age: 18, address: {}}
puts schema.(input).inspect

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
require 'hotch'
require 'i18n'
require "hotch"
require "i18n"
require 'dry-validation'
require "dry-validation"
def profile(&block)
Hotch(filter: 'Dry', &block)
Hotch(filter: "Dry", &block)
end

View File

@ -2,9 +2,9 @@
# frozen_string_literal: true
require 'pry'
require 'bundler/setup'
require 'dry-validation'
require "pry"
require "bundler/setup"
require "dry-validation"
module Types
include Dry::Types()
@ -28,4 +28,4 @@ class Context
end
end
Pry.start(Context.new, prompt: [proc { 'dry-validation> ' }, proc { 'dry-validation*> ' }])
Pry.start(Context.new, prompt: [proc { "dry-validation> " }, proc { "dry-validation*> " }])

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry-validation'
require "dry-validation"
schema = Dry::Validation.Schema do
required(:email).filled
@ -8,7 +8,7 @@ schema = Dry::Validation.Schema do
required(:age).filled(:int?, gt?: 18)
end
errors = schema.call(email: 'jane@doe.org', age: 19).messages
errors = schema.call(email: "jane@doe.org", age: 19).messages
puts errors.inspect

View File

@ -1,16 +1,16 @@
# frozen_string_literal: true
require 'byebug'
require 'dry-validation'
require "byebug"
require "dry-validation"
schema = Dry::Validation.Schema do
key(:phone_numbers).each(:str?)
end
errors = schema.call(phone_numbers: '').messages
errors = schema.call(phone_numbers: "").messages
puts errors.inspect
errors = schema.call(phone_numbers: ['123456789', 123_456_789]).messages
errors = schema.call(phone_numbers: ["123456789", 123_456_789]).messages
puts errors.inspect

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'json'
require 'dry-validation'
require "json"
require "dry-validation"
contract = Class.new(Dry::Validation::Contract) do
json do

View File

@ -1,14 +1,14 @@
# frozen_string_literal: true
require 'dry-validation'
require "dry-validation"
schema = Dry::Validation.Schema do
configure do
def self.messages
super.merge(en: {
errors: {
john_email?: '%{value} is not a john email',
example_email?: '%{value} is not a example email'
john_email?: "%{value} is not a john email",
example_email?: "%{value} is not a example email"
}
})
end
@ -17,14 +17,14 @@ schema = Dry::Validation.Schema do
required(:email).filled
validate(example_email?: :email) do |value|
value.end_with?('@example.com')
value.end_with?("@example.com")
end
validate(john_email?: :email) do |value|
value.start_with?('john')
value.start_with?("john")
end
end
errors = schema.call(email: 'jane@doe.org').messages
errors = schema.call(email: "jane@doe.org").messages
puts errors.inspect

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry-validation'
require "dry-validation"
schema = Dry::Validation.Schema do
required(:address).schema do
@ -19,6 +19,6 @@ errors = schema.call({}).messages
puts errors.inspect
errors = schema.call(address: { city: 'NYC' }).messages
errors = schema.call(address: {city: "NYC"}).messages
puts errors.inspect

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry-validation'
require "dry-validation"
contract = Class.new(Dry::Validation::Contract) do
params do
@ -9,6 +9,6 @@ contract = Class.new(Dry::Validation::Contract) do
end
end.new
result = contract.('email' => '', 'age' => '19')
result = contract.("email" => "", "age" => "19")
puts result.inspect

View File

@ -1,3 +1,3 @@
# frozen_string_literal: true
require 'dry/validation'
require "dry/validation"

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'dry/validation/constants'
require 'dry/validation/contract'
require 'dry/validation/macros'
require "dry/validation/constants"
require "dry/validation/contract"
require "dry/validation/macros"
# Main namespace
#
@ -16,15 +16,15 @@ module Dry
extend Macros::Registrar
register_extension(:monads) do
require 'dry/validation/extensions/monads'
require "dry/validation/extensions/monads"
end
register_extension(:hints) do
require 'dry/validation/extensions/hints'
require "dry/validation/extensions/hints"
end
register_extension(:predicates_as_macros) do
require 'dry/validation/extensions/predicates_as_macros'
require "dry/validation/extensions/predicates_as_macros"
end
# Define a contract and build its instance

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'dry/schema/config'
require 'dry/validation/macros'
require "dry/schema/config"
require "dry/validation/macros"
module Dry
module Validation

View File

@ -1,22 +1,22 @@
# frozen_string_literal: true
require 'pathname'
require 'dry/core/constants'
require "pathname"
require "dry/core/constants"
module Dry
module Validation
include Dry::Core::Constants
DOT = '.'
DOT = "."
# Root path is used for base errors in hash representation of error messages
ROOT_PATH = [nil].freeze
# Path to the default errors locale file
DEFAULT_ERRORS_NAMESPACE = 'dry_validation'
DEFAULT_ERRORS_NAMESPACE = "dry_validation"
# Path to the default errors locale file
DEFAULT_ERRORS_PATH = Pathname(__FILE__).join('../../../../config/errors.yml').realpath.freeze
DEFAULT_ERRORS_PATH = Pathname(__FILE__).join("../../../../config/errors.yml").realpath.freeze
# Mapping for block kwarg options used by block_options
#

View File

@ -1,18 +1,18 @@
# frozen_string_literal: true
require 'concurrent/map'
require "concurrent/map"
require 'dry/equalizer'
require 'dry/initializer'
require 'dry/schema/path'
require "dry/equalizer"
require "dry/initializer"
require "dry/schema/path"
require 'dry/validation/config'
require 'dry/validation/constants'
require 'dry/validation/rule'
require 'dry/validation/evaluator'
require 'dry/validation/messages/resolver'
require 'dry/validation/result'
require 'dry/validation/contract/class_interface'
require "dry/validation/config"
require "dry/validation/constants"
require "dry/validation/rule"
require "dry/validation/evaluator"
require "dry/validation/messages/resolver"
require "dry/validation/result"
require "dry/validation/contract/class_interface"
module Dry
module Validation

View File

@ -1,13 +1,13 @@
# frozen_string_literal: true
require 'dry/schema'
require 'dry/schema/messages'
require 'dry/schema/path'
require 'dry/schema/key_map'
require "dry/schema"
require "dry/schema/messages"
require "dry/schema/path"
require "dry/schema/key_map"
require 'dry/validation/constants'
require 'dry/validation/macros'
require 'dry/validation/schema_ext'
require "dry/validation/constants"
require "dry/validation/macros"
require "dry/validation/schema_ext"
module Dry
module Validation
@ -23,7 +23,7 @@ module Dry
# @api private
def inherited(klass)
super
klass.instance_variable_set('@config', config.dup)
klass.instance_variable_set("@config", config.dup)
end
# Configuration
@ -190,7 +190,7 @@ module Dry
# @api private
def core_schema_opts
{ parent: superclass&.__schema__, config: config }
{parent: superclass&.__schema__, config: config}
end
# @api private
@ -198,7 +198,7 @@ module Dry
return __schema__ if external_schemas.empty? && block.nil?
unless __schema__.nil?
raise ::Dry::Validation::DuplicateSchemaError, 'Schema has already been defined'
raise ::Dry::Validation::DuplicateSchemaError, "Schema has already been defined"
end
schema_opts = core_schema_opts

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
require 'dry/initializer'
require 'dry/core/deprecations'
require "dry/initializer"
require "dry/core/deprecations"
require 'dry/validation/constants'
require 'dry/validation/failures'
require "dry/validation/constants"
require "dry/validation/failures"
module Dry
module Validation

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry/monads/result'
require "dry/monads/result"
module Dry
module Validation

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry/monads/result'
require "dry/monads/result"
module Dry
module Validation

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'dry/schema/predicate_registry'
require 'dry/validation/contract'
require "dry/schema/predicate_registry"
require "dry/validation/contract"
module Dry
module Validation

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'dry/schema/path'
require 'dry/validation/constants'
require "dry/schema/path"
require "dry/validation/constants"
module Dry
module Validation
@ -57,7 +57,7 @@ module Dry
#
# @api public
def failure(message, tokens = EMPTY_HASH)
opts << { message: message, tokens: tokens, path: path }
opts << {message: message, tokens: tokens, path: path}
self
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'dry/initializer'
require 'dry/validation/constants'
require "dry/initializer"
require "dry/validation/constants"
module Dry
module Validation

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'dry/validation/constants'
require 'dry/validation/function'
require "dry/validation/constants"
require "dry/validation/function"
module Dry
module Validation

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'dry/container'
require 'dry/validation/macro'
require "dry/container"
require "dry/validation/macro"
module Dry
module Validation

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require 'dry/equalizer'
require "dry/equalizer"
require 'dry/schema/constants'
require 'dry/schema/message'
require "dry/schema/constants"
require "dry/schema/message"
module Dry
module Validation

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require 'dry/schema/message_set'
require "dry/schema/message_set"
require 'dry/validation/constants'
require 'dry/validation/message'
require "dry/validation/constants"
require "dry/validation/message"
module Dry
module Validation

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry/validation/message'
require "dry/validation/message"
module Dry
module Validation
@ -95,7 +95,7 @@ module Dry
def parse_token(token)
case token
when Array
token.join(', ')
token.join(", ")
else
token
end

View File

@ -1,11 +1,11 @@
# frozen_string_literal: true
require 'concurrent/map'
require 'dry/equalizer'
require "concurrent/map"
require "dry/equalizer"
require 'dry/validation/constants'
require 'dry/validation/message_set'
require 'dry/validation/values'
require "dry/validation/constants"
require "dry/validation/message_set"
require "dry/validation/values"
module Dry
module Validation
@ -179,7 +179,7 @@ module Dry
super
end
if RUBY_VERSION >= '2.7'
if RUBY_VERSION >= "2.7"
# Pattern matching
#
# @api private

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require 'dry/equalizer'
require "dry/equalizer"
require 'dry/validation/constants'
require 'dry/validation/function'
require "dry/validation/constants"
require "dry/validation/function"
module Dry
module Validation

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry/schema/path'
require "dry/schema/path"
module Dry
module Schema

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'dry/equalizer'
require 'dry/schema/path'
require 'dry/validation/constants'
require "dry/equalizer"
require "dry/schema/path"
require "dry/validation/constants"
module Dry
module Validation
@ -53,7 +53,7 @@ module Dry
vals = self.class.new(data.dig(*keys))
vals.fetch_values(*last) { nil }
else
raise ArgumentError, '+key+ must be a valid path specification'
raise ArgumentError, "+key+ must be a valid path specification"
end
end

View File

@ -2,6 +2,6 @@
module Dry
module Validation
VERSION = '1.4.2'
VERSION = "1.4.2"
end
end

View File

@ -10,53 +10,53 @@ RSpec.describe Dry::Validation::Result do
end
rule(:name) do
key.failure('oops') if values[:name] != 'Jane'
key.failure("oops") if values[:name] != "Jane"
end
end.new
end
let(:result) { schema.(input) }
context 'with valid input' do
let(:input) { { name: 'Jane' } }
context "with valid input" do
let(:input) { {name: "Jane"} }
describe '#success?' do
it 'returns true' do
describe "#success?" do
it "returns true" do
expect(result).to be_success
end
end
describe '#hints' do
it 'returns an empty array' do
describe "#hints" do
it "returns an empty array" do
expect(result.hints).to be_empty
end
end
end
context 'with invalid input' do
let(:input) { { name: '' } }
context "with invalid input" do
let(:input) { {name: ""} }
describe '#failure?' do
it 'returns true' do
describe "#failure?" do
it "returns true" do
expect(result).to be_failure
end
end
describe '#hints' do
it 'returns hint messages excluding errors' do
expect(result.hints.to_h).to eql(name: ['length must be within 2 - 4'])
describe "#hints" do
it "returns hint messages excluding errors" do
expect(result.hints.to_h).to eql(name: ["length must be within 2 - 4"])
end
end
describe '#messages' do
it 'returns hints + error messages' do
expect(result.messages.to_h).to eql(name: ['must be filled', 'length must be within 2 - 4'])
describe "#messages" do
it "returns hints + error messages" do
expect(result.messages.to_h).to eql(name: ["must be filled", "length must be within 2 - 4"])
end
end
describe '#errors' do
it 'returns errors excluding hints' do
expect(result.errors.to_h).to eql(name: ['must be filled'])
describe "#errors" do
it "returns errors excluding hints" do
expect(result.errors.to_h).to eql(name: ["must be filled"])
end
end
end

View File

@ -13,11 +13,11 @@ RSpec.describe Dry::Validation::Result do
let(:result) { schema.(input) }
context 'with valid input' do
let(:input) { { name: 'Jane' } }
context "with valid input" do
let(:input) { {name: "Jane"} }
describe '#to_monad' do
it 'returns a Success value' do
describe "#to_monad" do
it "returns a Success value" do
monad = result.to_monad
expect(monad).to be_a Dry::Monads::Result
@ -27,11 +27,11 @@ RSpec.describe Dry::Validation::Result do
end
end
context 'with invalid input' do
let(:input) { { name: '' } }
context "with invalid input" do
let(:input) { {name: ""} }
describe '#to_monad' do
it 'returns a Failure value' do
describe "#to_monad" do
it "returns a Failure value" do
monad = result.to_monad
expect(monad).to be_a_failure

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require 'dry/validation/extensions/predicates_as_macros'
require "dry/validation/extensions/predicates_as_macros"
RSpec.describe Dry::Validation::Contract do
context 'with predicates_as_macros extension' do
context "with predicates_as_macros extension" do
before { Dry::Validation.load_extensions(:predicates_as_macros) }
subject(:contract) do
@ -26,7 +26,7 @@ RSpec.describe Dry::Validation::Contract do
end
end
it 'macros succeed on predicate success' do
it "macros succeed on predicate success" do
age_contract = Class.new(contract) do
schema do
required(:age).filled(:integer)
@ -38,7 +38,7 @@ RSpec.describe Dry::Validation::Contract do
expect(age_contract.(age: 19)).to be_success
end
it 'macros fail on predicate failure' do
it "macros fail on predicate failure" do
age_contract = Class.new(contract) do
schema do
required(:age).filled(:integer)
@ -50,7 +50,7 @@ RSpec.describe Dry::Validation::Contract do
expect(age_contract.(age: 17)).to be_failure
end
it 'failure message is built from predicate name and arguments' do
it "failure message is built from predicate name and arguments" do
age_contract = Class.new(contract) do
schema do
required(:age).filled(:integer)
@ -63,7 +63,7 @@ RSpec.describe Dry::Validation::Contract do
expect(
result.errors.first.text
).to eq('must be greater than or equal to 18')
).to eq("must be greater than or equal to 18")
end
end
end

View File

@ -1,12 +1,12 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, '#call' do
RSpec.describe Dry::Validation::Contract, "#call" do
subject(:contract) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
params do
@ -27,111 +27,111 @@ RSpec.describe Dry::Validation::Contract, '#call' do
rule(:login) do
if key?
key.failure('too short') if value.length < 3
key.failure("too short") if value.length < 3
end
end
rule(address: { geolocation: [:lon, :lat] }) do
rule(address: {geolocation: [:lon, :lat]}) do
if key?
lon, lat = value
key('address.geolocation.lat').failure('invalid') if lat < 10
key('address.geolocation.lon').failure('invalid') if lon < 10
key("address.geolocation.lat").failure("invalid") if lat < 10
key("address.geolocation.lon").failure("invalid") if lon < 10
end
end
rule(:password) do
key.failure('is required') if values[:login] && !values[:password]
key.failure("is required") if values[:login] && !values[:password]
end
rule(:age) do
key.failure('must be greater or equal 18') if value < 18
key.failure("must be greater or equal 18") if value < 18
end
rule(:age) do
key.failure('must be greater than 0') if value < 0
key.failure("must be greater than 0") if value < 0
end
rule(address: :zip) do
address = values[:address]
if address && address[:country] == 'Russia' && address[:zip] != /\A\d{6}\z/
key.failure('must have 6 digit')
if address && address[:country] == "Russia" && address[:zip] != /\A\d{6}\z/
key.failure("must have 6 digit")
end
end
rule('address.geolocation.lon') do
key.failure('invalid longitude') if key? && !(-180.0...180.0).cover?(value)
rule("address.geolocation.lon") do
key.failure("invalid longitude") if key? && !(-180.0...180.0).cover?(value)
end
end.new
end
it 'applies rule to input processed by the schema' do
result = contract.(email: 'john@doe.org', age: 19)
it "applies rule to input processed by the schema" do
result = contract.(email: "john@doe.org", age: 19)
expect(result).to be_success
expect(result.errors.to_h).to eql({})
end
it 'applies rule to an optional field when value is present' do
result = contract.(email: 'john@doe.org', age: 19, login: 'ab')
it "applies rule to an optional field when value is present" do
result = contract.(email: "john@doe.org", age: 19, login: "ab")
expect(result).to be_failure
expect(result.errors.to_h).to eql(login: ['too short'], password: ['is required'])
expect(result.errors.to_h).to eql(login: ["too short"], password: ["is required"])
end
it 'applies rule to an optional nested field when value is present' do
it "applies rule to an optional nested field when value is present" do
result = contract.(
email: 'john@doe.org',
email: "john@doe.org",
age: 19,
address: {
geolocation: { lat: 11, lon: 1 },
country: 'Poland',
zip: '12345'
geolocation: {lat: 11, lon: 1},
country: "Poland",
zip: "12345"
}
)
expect(result).to be_failure
expect(result.errors.to_h).to eql(address: { geolocation: { lon: ['invalid'] } })
expect(result.errors.to_h).to eql(address: {geolocation: {lon: ["invalid"]}})
end
it 'returns rule errors' do
result = contract.(email: 'john@doe.org', login: 'jane', age: 19)
it "returns rule errors" do
result = contract.(email: "john@doe.org", login: "jane", age: 19)
expect(result).to be_failure
expect(result.errors.to_h).to eql(password: ['is required'])
expect(result.errors.to_h).to eql(password: ["is required"])
end
it "doesn't execute rules when basic checks failed" do
result = contract.(email: 'john@doe.org', age: 'not-an-integer')
result = contract.(email: "john@doe.org", age: "not-an-integer")
expect(result).to be_failure
expect(result.errors.to_h).to eql(age: ['must be an integer'])
expect(result.errors.to_h).to eql(age: ["must be an integer"])
end
it 'gathers errors from multiple rules for the same key' do
result = contract.(email: 'john@doe.org', age: -1)
it "gathers errors from multiple rules for the same key" do
result = contract.(email: "john@doe.org", age: -1)
expect(result).to be_failure
expect(result.errors.to_h).to eql(age: ['must be greater or equal 18', 'must be greater than 0'])
expect(result.errors.to_h).to eql(age: ["must be greater or equal 18", "must be greater than 0"])
end
it 'builds nested message keys for nested rules' do
result = contract.(email: 'john@doe.org', age: 20, address: { country: 'Russia', zip: 'abc' })
it "builds nested message keys for nested rules" do
result = contract.(email: "john@doe.org", age: 20, address: {country: "Russia", zip: "abc"})
expect(result).to be_failure
expect(result.errors.to_h).to eql(address: { zip: ['must have 6 digit'] })
expect(result.errors.to_h).to eql(address: {zip: ["must have 6 digit"]})
end
it 'builds deeply nested messages for deeply nested rules' do
it "builds deeply nested messages for deeply nested rules" do
result = contract.(
email: 'john@doe.org',
email: "john@doe.org",
age: 20,
address: {
country: 'UK', zip: 'irrelevant',
geolocation: { lon: '365', lat: '78' }
country: "UK", zip: "irrelevant",
geolocation: {lon: "365", lat: "78"}
}
)
expect(result).to be_failure
expect(result.errors.to_h).to eql(address: { geolocation: { lon: ['invalid longitude'] } })
expect(result.errors.to_h).to eql(address: {geolocation: {lon: ["invalid longitude"]}})
end
end

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation, '.Contract' do
RSpec.describe Dry::Validation, ".Contract" do
subject(:contract) do
Dry::Validation.Contract do
params do
@ -11,7 +11,7 @@ RSpec.describe Dry::Validation, '.Contract' do
end
end
it 'returns an instance of Dry::Validation::Contract' do
it "returns an instance of Dry::Validation::Contract" do
expect(contract).to be_a(Dry::Validation::Contract)
end
end

View File

@ -1,25 +1,25 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, 'setting default locale' do
RSpec.describe Dry::Validation::Contract, "setting default locale" do
subject(:contract) do
Dry::Validation.Contract do
config.messages.default_locale = :pl
config.messages.backend = :i18n
config.messages.load_paths << SPEC_ROOT.join('fixtures/messages/errors.pl.yml')
config.messages.load_paths << SPEC_ROOT.join("fixtures/messages/errors.pl.yml")
params do
required(:email).filled(:string)
end
rule(:email) do
key.failure(:invalid) unless values[:email].include?('@')
key.failure(:invalid) unless values[:email].include?("@")
end
end
end
it 'uses configured default locale' do
expect(contract.(email: 'foo').errors.to_h).to eql(email: ['oh nie zły email'])
it "uses configured default locale" do
expect(contract.(email: "foo").errors.to_h).to eql(email: ["oh nie zły email"])
end
end

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, '.json' do
RSpec.describe Dry::Validation::Contract, ".json" do
subject(:contract_class) do
Class.new(Dry::Validation::Contract) do
json do
@ -11,19 +11,19 @@ RSpec.describe Dry::Validation::Contract, '.json' do
end
end
it 'defines a JSON schema' do
it "defines a JSON schema" do
expect(contract_class.schema).to be_a(Dry::Schema::JSON)
expect(contract_class.json).to be_a(Dry::Schema::JSON)
expect(contract_class.schema).to be(contract_class.json)
end
it 'returns nil if schema is not defined' do
it "returns nil if schema is not defined" do
contract_class = Class.new(Dry::Validation::Contract)
expect(contract_class.schema).to be(nil)
end
it 'raises an error if schema is already defined' do
it "raises an error if schema is already defined" do
expect do
contract_class.json do
required(:login).filled(:string)

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, '.params' do
RSpec.describe Dry::Validation::Contract, ".params" do
subject(:contract_class) do
Class.new(Dry::Validation::Contract) do
params do
@ -11,19 +11,19 @@ RSpec.describe Dry::Validation::Contract, '.params' do
end
end
it 'defines a Params schema' do
it "defines a Params schema" do
expect(contract_class.schema).to be_a(Dry::Schema::Params)
expect(contract_class.params).to be_a(Dry::Schema::Params)
expect(contract_class.schema).to be(contract_class.params)
end
it 'returns nil if schema is not defined' do
it "returns nil if schema is not defined" do
contract_class = Class.new(Dry::Validation::Contract)
expect(contract_class.schema).to be(nil)
end
it 'raises an error if schema is already defined' do
it "raises an error if schema is already defined" do
expect do
contract_class.params do
required(:login).filled(:string)

View File

@ -1,15 +1,15 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, 'Rule#each' do
RSpec.describe Dry::Validation::Contract, "Rule#each" do
subject(:contract) { contract_class.new }
context 'using a block' do
context "using a block" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
params do
@ -20,11 +20,11 @@ RSpec.describe Dry::Validation::Contract, 'Rule#each' do
end
rule(:nums).each do
key.failure('invalid') if value < 3
key.failure("invalid") if value < 3
end
rule(hash: :another_nums).each do
key.failure('invalid') if value < 3
key.failure("invalid") if value < 3
end
rule(:nums).each do |context:|
@ -34,34 +34,34 @@ RSpec.describe Dry::Validation::Contract, 'Rule#each' do
end
end
it 'applies rule only when the value is an array' do
expect(contract.(nums: 'oops').errors.to_h).to eql(nums: ['must be an array'])
it "applies rule only when the value is an array" do
expect(contract.(nums: "oops").errors.to_h).to eql(nums: ["must be an array"])
end
it 'applies rule when an item passed schema checks' do
expect(contract.(nums: ['oops', 1, 4, 0]).errors.to_h)
.to eql(nums: { 0 => ['must be an integer'], 1 => ['invalid'], 3 => ['invalid'] })
it "applies rule when an item passed schema checks" do
expect(contract.(nums: ["oops", 1, 4, 0]).errors.to_h)
.to eql(nums: {0 => ["must be an integer"], 1 => ["invalid"], 3 => ["invalid"]})
end
it 'applies rule to nested values when an item passed schema checks' do
expect(contract.(nums: [4], hash: { another_nums: ['oops', 1, 4] }).errors.to_h)
.to eql(hash: { another_nums: { 0 => ['must be an integer'], 1 => ['invalid'] } })
it "applies rule to nested values when an item passed schema checks" do
expect(contract.(nums: [4], hash: {another_nums: ["oops", 1, 4]}).errors.to_h)
.to eql(hash: {another_nums: {0 => ["must be an integer"], 1 => ["invalid"]}})
end
it 'passes block options' do
it "passes block options" do
expect(contract.(nums: [10, 20]).context[:sum]).to eql(30)
end
end
context 'using a simple macro' do
context "using a simple macro" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:even?) do
key.failure('invalid') unless value.even?
key.failure("invalid") unless value.even?
end
params do
@ -72,34 +72,34 @@ RSpec.describe Dry::Validation::Contract, 'Rule#each' do
end
rule(:nums).each(:even?)
rule('hash.another_nums').each(:even?)
rule("hash.another_nums").each(:even?)
end
end
it 'applies rule when an item passed schema checks' do
it "applies rule when an item passed schema checks" do
expect(contract.(nums: [2, 3]).errors.to_h)
.to eql(nums: { 1 => ['invalid'] })
.to eql(nums: {1 => ["invalid"]})
end
it 'applies rule to nested values when an item passed schema checks' do
expect(contract.(nums: [4], hash: { another_nums: [2, 3] }).errors.to_h)
.to eql(hash: { another_nums: { 1 => ['invalid'] } })
it "applies rule to nested values when an item passed schema checks" do
expect(contract.(nums: [4], hash: {another_nums: [2, 3]}).errors.to_h)
.to eql(hash: {another_nums: {1 => ["invalid"]}})
end
end
context 'using multiple macros' do
context "using multiple macros" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:even?) do
key.failure('invalid') unless value.even?
key.failure("invalid") unless value.even?
end
register_macro(:below_ten?) do
key.failure('too big') unless value < 10
key.failure("too big") unless value < 10
end
params do
@ -114,27 +114,27 @@ RSpec.describe Dry::Validation::Contract, 'Rule#each' do
end
end
it 'applies rules when an item passed schema checks' do
it "applies rules when an item passed schema checks" do
expect(contract.(nums: [2, 15]).errors.to_h)
.to eql(nums: { 1 => ['invalid', 'too big'] })
.to eql(nums: {1 => ["invalid", "too big"]})
end
it 'applies rules for nested values when an item passed schema checks' do
expect(contract.(nums: [2], hash: { another_nums: [2, 15] }).errors.to_h)
.to eql(hash: { another_nums: { 1 => ['invalid', 'too big'] } })
it "applies rules for nested values when an item passed schema checks" do
expect(contract.(nums: [2], hash: {another_nums: [2, 15]}).errors.to_h)
.to eql(hash: {another_nums: {1 => ["invalid", "too big"]}})
end
end
context 'using a macro with args' do
context "using a macro with args" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:min) do |macro:|
min = macro.args[0]
key.failure('invalid') if value < min
key.failure("invalid") if value < min
end
params do
@ -149,27 +149,27 @@ RSpec.describe Dry::Validation::Contract, 'Rule#each' do
end
end
it 'applies rule when an item passed schema checks' do
expect(contract.(nums: ['oops', 1, 4, 0]).errors.to_h)
.to eql(nums: { 0 => ['must be an integer'], 1 => ['invalid'], 3 => ['invalid'] })
it "applies rule when an item passed schema checks" do
expect(contract.(nums: ["oops", 1, 4, 0]).errors.to_h)
.to eql(nums: {0 => ["must be an integer"], 1 => ["invalid"], 3 => ["invalid"]})
end
it 'applies rule to nested values when an item passed schema checks' do
expect(contract.(nums: [4], hash: { another_nums: ['oops', 1, 4] }).errors.to_h)
.to eql(hash: { another_nums: { 0 => ['must be an integer'], 1 => ['invalid'] } })
it "applies rule to nested values when an item passed schema checks" do
expect(contract.(nums: [4], hash: {another_nums: ["oops", 1, 4]}).errors.to_h)
.to eql(hash: {another_nums: {0 => ["must be an integer"], 1 => ["invalid"]}})
end
end
context 'using a macro with multiple args' do
context "using a macro with multiple args" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:between) do |macro:|
min, max = macro.args[0..1]
key.failure('invalid') unless (min..max).cover?(value)
key.failure("invalid") unless (min..max).cover?(value)
end
params do
@ -184,32 +184,32 @@ RSpec.describe Dry::Validation::Contract, 'Rule#each' do
end
end
it 'applies rule when an item passed schema checks' do
expect(contract.(nums: ['oops', 4, 0, 6]).errors.to_h)
.to eql(nums: { 0 => ['must be an integer'], 2 => ['invalid'], 3 => ['invalid'] })
it "applies rule when an item passed schema checks" do
expect(contract.(nums: ["oops", 4, 0, 6]).errors.to_h)
.to eql(nums: {0 => ["must be an integer"], 2 => ["invalid"], 3 => ["invalid"]})
end
it 'applies rule with nested values when an item passed schema checks' do
expect(contract.(nums: [4], hash: { another_nums: ['oops', 4, 0] }).errors.to_h)
.to eql(hash: { another_nums: { 0 => ['must be an integer'], 2 => ['invalid'] } })
it "applies rule with nested values when an item passed schema checks" do
expect(contract.(nums: [4], hash: {another_nums: ["oops", 4, 0]}).errors.to_h)
.to eql(hash: {another_nums: {0 => ["must be an integer"], 2 => ["invalid"]}})
end
end
context 'using multiple macros with args' do
context "using multiple macros with args" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:min) do |macro:|
min = macro.args[0]
key.failure('invalid') if value < min
key.failure("invalid") if value < min
end
register_macro(:max) do |macro:|
max = macro.args[0]
key.failure('invalid') if value > max
key.failure("invalid") if value > max
end
params do
@ -224,14 +224,14 @@ RSpec.describe Dry::Validation::Contract, 'Rule#each' do
end
end
it 'applies rules when an item passed schema checks' do
expect(contract.(nums: ['oops', 4, 0, 6]).errors.to_h)
.to eql(nums: { 0 => ['must be an integer'], 2 => ['invalid'], 3 => ['invalid'] })
it "applies rules when an item passed schema checks" do
expect(contract.(nums: ["oops", 4, 0, 6]).errors.to_h)
.to eql(nums: {0 => ["must be an integer"], 2 => ["invalid"], 3 => ["invalid"]})
end
it 'applies rules for nested values when an item passed schema checks' do
expect(contract.(nums: [4], hash: { another_nums: ['oops', 4, 0] }).errors.to_h)
.to eql(hash: { another_nums: { 0 => ['must be an integer'], 2 => ['invalid'] } })
it "applies rules for nested values when an item passed schema checks" do
expect(contract.(nums: [4], hash: {another_nums: ["oops", 4, 0]}).errors.to_h)
.to eql(hash: {another_nums: {0 => ["must be an integer"], 2 => ["invalid"]}})
end
end
end

View File

@ -1,11 +1,11 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, '.rule' do
RSpec.describe Dry::Validation::Contract, ".rule" do
subject(:contract) { contract_class.new }
context 'with a nested hash' do
context "with a nested hash" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
params do
@ -18,30 +18,30 @@ RSpec.describe Dry::Validation::Contract, '.rule' do
end
rule(:email) do
key.failure('invalid email') unless value.include?('@')
key.failure("invalid email") unless value.include?("@")
end
rule('address.zipcode') do
key.failure('bad format') unless value.include?('-')
rule("address.zipcode") do
key.failure("bad format") unless value.include?("-")
end
end
end
context 'when nested values fail both schema and rule checks' do
it 'produces schema and rule errors' do
expect(contract.(email: 'jane@doe.org', address: { city: 'NYC', zipcode: '123' }).errors.to_h)
.to eql(address: { street: ['is missing'], zipcode: ['bad format'] })
context "when nested values fail both schema and rule checks" do
it "produces schema and rule errors" do
expect(contract.(email: "jane@doe.org", address: {city: "NYC", zipcode: "123"}).errors.to_h)
.to eql(address: {street: ["is missing"], zipcode: ["bad format"]})
end
end
context 'when empty hash is provided' do
it 'produces missing-key errors' do
expect(contract.({}).errors.to_h).to eql(email: ['is missing'], address: ['is missing'])
context "when empty hash is provided" do
it "produces missing-key errors" do
expect(contract.({}).errors.to_h).to eql(email: ["is missing"], address: ["is missing"])
end
end
end
context 'with a rule that depends on two nested values' do
context "with a rule that depends on two nested values" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
params do
@ -52,19 +52,19 @@ RSpec.describe Dry::Validation::Contract, '.rule' do
end
rule(event: %i[active_from active_until]) do
key.failure('invalid dates') if value[0] < value[1]
key.failure("invalid dates") if value[0] < value[1]
end
end
end
it 'does not execute rule when the schema checks failed' do
result = contract.(event: { active_from: Date.today, active_until: nil })
it "does not execute rule when the schema checks failed" do
result = contract.(event: {active_from: Date.today, active_until: nil})
expect(result.errors.to_h).to eql(event: { active_until: ['must be a date'] })
expect(result.errors.to_h).to eql(event: {active_until: ["must be a date"]})
end
end
context 'with a nested array' do
context "with a nested array" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
params do
@ -73,21 +73,21 @@ RSpec.describe Dry::Validation::Contract, '.rule' do
end
end
rule('address.phones').each do
key.failure('invalid phone') unless value.start_with?('+48')
rule("address.phones").each do
key.failure("invalid phone") unless value.start_with?("+48")
end
end
end
context 'when one of the values fails' do
it 'produces an error for the invalid value' do
expect(contract.(address: { phones: ['+48123', '+47412', nil] }).errors.to_h)
.to eql(address: { phones: { 1 => ['invalid phone'], 2 => ['must be a string'] } })
context "when one of the values fails" do
it "produces an error for the invalid value" do
expect(contract.(address: {phones: ["+48123", "+47412", nil]}).errors.to_h)
.to eql(address: {phones: {1 => ["invalid phone"], 2 => ["must be a string"]}})
end
end
context 'with a path intersection' do
context 'when the longest path is a first' do
context "with a path intersection" do
context "when the longest path is a first" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
params do
@ -97,19 +97,19 @@ RSpec.describe Dry::Validation::Contract, '.rule' do
end
rule(:addresses).each do
key(path.keys + [:phone]).failure('invalid phone')
key.failure('invalid list')
key(path.keys + [:phone]).failure("invalid phone")
key.failure("invalid list")
end
end
it 'produces an error for all paths' do
expect(contract.(addresses: [{ phone: '+48123' }]).errors.to_h)
.to eql(addresses: { 0 => [['invalid list'], [{ phone: 'invalid phone' }]] })
it "produces an error for all paths" do
expect(contract.(addresses: [{phone: "+48123"}]).errors.to_h)
.to eql(addresses: {0 => [["invalid list"], [{phone: "invalid phone"}]]})
end
end
end
context 'when the longest path is a last' do
context "when the longest path is a last" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
params do
@ -119,14 +119,14 @@ RSpec.describe Dry::Validation::Contract, '.rule' do
end
rule(:addresses).each do
key.failure('invalid list')
key(path.keys + [:phone]).failure('invalid phone')
key.failure("invalid list")
key(path.keys + [:phone]).failure("invalid phone")
end
end
it 'produces an error for all paths' do
expect(contract.(addresses: [{ phone: '+48123' }]).errors.to_h)
.to eql(addresses: { 0 => [['invalid list'], [{ phone: 'invalid phone' }]] })
it "produces an error for all paths" do
expect(contract.(addresses: [{phone: "+48123"}]).errors.to_h)
.to eql(addresses: {0 => [["invalid list"], [{phone: "invalid phone"}]]})
end
end
end

View File

@ -1,15 +1,15 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, 'Rule#validate' do
RSpec.describe Dry::Validation::Contract, "Rule#validate" do
subject(:contract) { contract_class.new }
context 'using a block' do
context "using a block" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
params do
@ -17,26 +17,26 @@ RSpec.describe Dry::Validation::Contract, 'Rule#validate' do
end
rule(:num).validate do
key.failure('invalid') if value < 3
key.failure("invalid") if value < 3
end
end
end
it 'applies rule when an item passed schema checks' do
it "applies rule when an item passed schema checks" do
expect(contract.(num: 2).errors.to_h)
.to eql(num: ['invalid'])
.to eql(num: ["invalid"])
end
end
context 'using a simple macro' do
context "using a simple macro" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:even?) do
key.failure('invalid') unless value.even?
key.failure("invalid") unless value.even?
end
params do
@ -47,25 +47,25 @@ RSpec.describe Dry::Validation::Contract, 'Rule#validate' do
end
end
it 'applies first rule when an item passed schema checks' do
it "applies first rule when an item passed schema checks" do
expect(contract.(num: 3).errors.to_h)
.to eql(num: ['invalid'])
.to eql(num: ["invalid"])
end
end
context 'using multiple macros' do
context "using multiple macros" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:even?) do
key.failure('invalid') unless value.even?
key.failure("invalid") unless value.even?
end
register_macro(:below_ten?) do
key.failure('too big') unless value < 10
key.failure("too big") unless value < 10
end
params do
@ -76,22 +76,22 @@ RSpec.describe Dry::Validation::Contract, 'Rule#validate' do
end
end
it 'applies rules when an item passed schema checks' do
it "applies rules when an item passed schema checks" do
expect(contract.(num: 15).errors.to_h)
.to eql(num: ['invalid', 'too big'])
.to eql(num: ["invalid", "too big"])
end
end
context 'using a macro with args' do
context "using a macro with args" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:min) do |macro:|
min = macro.args[0]
key.failure('invalid') if value < min
key.failure("invalid") if value < min
end
params do
@ -102,22 +102,22 @@ RSpec.describe Dry::Validation::Contract, 'Rule#validate' do
end
end
it 'applies rule when an item passed schema checks' do
it "applies rule when an item passed schema checks" do
expect(contract.(num: 2).errors.to_h)
.to eql(num: ['invalid'])
.to eql(num: ["invalid"])
end
end
context 'using a macro with multiple args' do
context "using a macro with multiple args" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:between) do |macro:|
min, max = macro.args[0..1]
key.failure('invalid') unless (min..max).cover?(value)
key.failure("invalid") unless (min..max).cover?(value)
end
params do
@ -128,27 +128,27 @@ RSpec.describe Dry::Validation::Contract, 'Rule#validate' do
end
end
it 'applies rule when an item passed schema checks' do
it "applies rule when an item passed schema checks" do
expect(contract.(num: 2).errors.to_h)
.to eql(num: ['invalid'])
.to eql(num: ["invalid"])
end
end
context 'using multiple macros with args' do
context "using multiple macros with args" do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
register_macro(:min) do |macro:|
min = macro.args[0]
key.failure('too small') if value < min
key.failure("too small") if value < min
end
register_macro(:max) do |macro:|
max = macro.args[0]
key.failure('too big') if value > max
key.failure("too big") if value > max
end
params do
@ -159,14 +159,14 @@ RSpec.describe Dry::Validation::Contract, 'Rule#validate' do
end
end
it 'applies first rule when an item passed schema checks' do
it "applies first rule when an item passed schema checks" do
expect(contract.(num: 2).errors.to_h)
.to eql(num: ['too small'])
.to eql(num: ["too small"])
end
it 'applies second rule when an item passed schema checks' do
it "applies second rule when an item passed schema checks" do
expect(contract.(num: 6).errors.to_h)
.to eql(num: ['too big'])
.to eql(num: ["too big"])
end
end
end

View File

@ -1,14 +1,14 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, '.rule' do
RSpec.describe Dry::Validation::Contract, ".rule" do
subject(:contract) { contract_class.new }
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
def self.name
'TestContract'
"TestContract"
end
params do
@ -24,154 +24,154 @@ RSpec.describe Dry::Validation::Contract, '.rule' do
end
end
context 'when the name matches one of the keys' do
context "when the name matches one of the keys" do
before do
contract_class.rule(:login) do
key.failure('is too short') if values[:login].size < 3
key.failure("is too short") if values[:login].size < 3
end
end
it 'applies rule when value passed schema checks' do
expect(contract.(email: 'jane@doe.org', login: 'ab').errors.to_h)
.to eql(login: ['is too short'])
it "applies rule when value passed schema checks" do
expect(contract.(email: "jane@doe.org", login: "ab").errors.to_h)
.to eql(login: ["is too short"])
end
end
context 'when the name does not match one of the keys' do
context "when the name does not match one of the keys" do
before do
contract_class.rule do
key(:custom).failure('this works')
key(:custom).failure("this works")
end
end
it 'applies the rule regardless of the schema result' do
expect(contract.(email: 'jane@doe.org', login: 'jane').errors.to_h)
.to eql(custom: ['this works'])
it "applies the rule regardless of the schema result" do
expect(contract.(email: "jane@doe.org", login: "jane").errors.to_h)
.to eql(custom: ["this works"])
end
end
context 'with a hash as the key identifier' do
context "with a hash as the key identifier" do
before do
contract_class.rule(details: { address: :street }) do
key.failure('cannot be empty') if values[:details][:address][:street].strip.empty?
contract_class.rule(details: {address: :street}) do
key.failure("cannot be empty") if values[:details][:address][:street].strip.empty?
end
end
it 'applies the rule when nested value passed schema checks' do
expect(contract.(email: 'jane@doe.org', login: 'jane', details: nil).errors.to_h)
.to eql(details: ['must be a hash'])
it "applies the rule when nested value passed schema checks" do
expect(contract.(email: "jane@doe.org", login: "jane", details: nil).errors.to_h)
.to eql(details: ["must be a hash"])
expect(contract.(email: 'jane@doe.org', login: 'jane', details: { address: nil }).errors.to_h)
.to eql(details: { address: ['must be a hash'] })
expect(contract.(email: "jane@doe.org", login: "jane", details: {address: nil}).errors.to_h)
.to eql(details: {address: ["must be a hash"]})
expect(contract.(email: 'jane@doe.org', login: 'jane', details: { address: { street: ' ' } }).errors.to_h)
.to eql(details: { address: { street: ['cannot be empty'] } })
expect(contract.(email: "jane@doe.org", login: "jane", details: {address: {street: " "}}).errors.to_h)
.to eql(details: {address: {street: ["cannot be empty"]}})
end
end
context 'with a rule for nested hash and another rule for its member' do
context "with a rule for nested hash and another rule for its member" do
before do
contract_class.rule(details: :address) do
key.failure('invalid no matter what')
key.failure("invalid no matter what")
end
contract_class.rule(details: :address) do
key.failure('seriously invalid')
key.failure("seriously invalid")
end
contract_class.rule(details: { address: :street }) do
key.failure('cannot be empty') if values[:details][:address][:street].strip.empty?
contract_class.rule(details: {address: :street}) do
key.failure("cannot be empty") if values[:details][:address][:street].strip.empty?
end
contract_class.rule(details: { address: :street }) do
key.failure('must include a number') unless values[:details][:address][:street].match?(/\d+/)
contract_class.rule(details: {address: :street}) do
key.failure("must include a number") unless values[:details][:address][:street].match?(/\d+/)
end
end
it 'applies the rule when nested value passed schema checks' do
expect(contract.(email: 'jane@doe.org', login: 'jane', details: { address: { street: ' ' } }).errors.to_h)
it "applies the rule when nested value passed schema checks" do
expect(contract.(email: "jane@doe.org", login: "jane", details: {address: {street: " "}}).errors.to_h)
.to eql(
details: { address: [
['invalid no matter what', 'seriously invalid'],
{ street: ['cannot be empty', 'must include a number'] }
] }
details: {address: [
["invalid no matter what", "seriously invalid"],
{street: ["cannot be empty", "must include a number"]}
]}
)
end
end
context 'with a rule that sets a general base error for the whole input' do
context "with a rule that sets a general base error for the whole input" do
before do
contract_class.rule do
key.failure('this whole thing is invalid')
key.failure("this whole thing is invalid")
end
end
it 'sets a base error not attached to any key' do
expect(contract.(email: 'jane@doe.org', login: '').errors.to_h)
.to eql(login: ['must be filled'], nil => ['this whole thing is invalid'])
it "sets a base error not attached to any key" do
expect(contract.(email: "jane@doe.org", login: "").errors.to_h)
.to eql(login: ["must be filled"], nil => ["this whole thing is invalid"])
expect(contract.(email: 'jane@doe.org', login: '').errors.filter(:base?).map(&:to_s))
.to eql(['this whole thing is invalid'])
expect(contract.(email: "jane@doe.org", login: "").errors.filter(:base?).map(&:to_s))
.to eql(["this whole thing is invalid"])
end
end
context 'with a list of keys' do
context "with a list of keys" do
before do
contract_class.rule(:email, :login) do
if !values[:email].empty? && !values[:login].empty?
key(:login).failure('is not needed when email is provided')
key(:login).failure("is not needed when email is provided")
end
end
end
it 'applies the rule when all values passed schema checks' do
it "applies the rule when all values passed schema checks" do
expect(contract.(email: nil, login: nil).errors.to_h)
.to eql(email: ['must be filled'], login: ['must be filled'])
.to eql(email: ["must be filled"], login: ["must be filled"])
expect(contract.(email: 'jane@doe.org', login: 'jane').errors.to_h)
.to eql(login: ['is not needed when email is provided'])
expect(contract.(email: "jane@doe.org", login: "jane").errors.to_h)
.to eql(login: ["is not needed when email is provided"])
end
end
context 'when keys are missing in the schema' do
it 'raises error with a list of symbol keys' do
context "when keys are missing in the schema" do
it "raises error with a list of symbol keys" do
expect { contract_class.rule(:invalid, :wrong) }
.to raise_error(
Dry::Validation::InvalidKeysError,
'TestContract.rule specifies keys that are not defined by the schema: [:invalid, :wrong]'
"TestContract.rule specifies keys that are not defined by the schema: [:invalid, :wrong]"
)
end
it 'raises error with a hash path' do
it "raises error with a hash path" do
expect { contract_class.rule(invalid: :wrong) }
.to raise_error(
Dry::Validation::InvalidKeysError,
'TestContract.rule specifies keys that are not defined by the schema: [{:invalid=>:wrong}]'
"TestContract.rule specifies keys that are not defined by the schema: [{:invalid=>:wrong}]"
)
end
it 'raises error with a dot notation' do
expect { contract_class.rule('invalid.wrong') }
it "raises error with a dot notation" do
expect { contract_class.rule("invalid.wrong") }
.to raise_error(
Dry::Validation::InvalidKeysError,
'TestContract.rule specifies keys that are not defined by the schema: ["invalid.wrong"]'
)
end
it 'raises error with a hash path with multiple nested keys' do
it "raises error with a hash path with multiple nested keys" do
expect { contract_class.rule(invalid: %i[wrong not_here]) }
.to raise_error(
Dry::Validation::InvalidKeysError,
'TestContract.rule specifies keys that are not defined by the schema: [[:invalid, :wrong], [:invalid, :not_here]]'
"TestContract.rule specifies keys that are not defined by the schema: [[:invalid, :wrong], [:invalid, :not_here]]"
)
end
end
describe 'abstract contract' do
describe "abstract contract" do
let(:abstract_contract) do
Class.new(Dry::Validation::Contract) do
rule do
base.failure('error from abstract contract')
base.failure("error from abstract contract")
end
end
end
@ -184,9 +184,9 @@ RSpec.describe Dry::Validation::Contract, '.rule' do
end
end
it 'applies rules from the parent abstract contract' do
expect(contract.(name: '').errors.to_h).to eql(
nil => ['error from abstract contract'], name: ['must be filled']
it "applies rules from the parent abstract contract" do
expect(contract.(name: "").errors.to_h).to eql(
nil => ["error from abstract contract"], name: ["must be filled"]
)
end
end

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, '.schema' do
context 'defining a schema via block' do
RSpec.describe Dry::Validation::Contract, ".schema" do
context "defining a schema via block" do
subject(:contract_class) do
Class.new(Dry::Validation::Contract) do
schema do
@ -12,16 +12,16 @@ RSpec.describe Dry::Validation::Contract, '.schema' do
end
end
it 'defines a schema' do
it "defines a schema" do
expect(contract_class.schema).to be_a(Dry::Schema::Processor)
end
it 'returns nil if schema is not defined' do
it "returns nil if schema is not defined" do
contract_class = Class.new(Dry::Validation::Contract)
expect(contract_class.schema).to be(nil)
end
it 'raises an error if schema is already defined' do
it "raises an error if schema is already defined" do
expect do
contract_class.schema do
required(:login).filled(:string)
@ -30,7 +30,7 @@ RSpec.describe Dry::Validation::Contract, '.schema' do
end
end
context 'setting an external schema' do
context "setting an external schema" do
subject(:contract_class) do
Class.new(Dry::Validation::Contract) do
schema(Test::UserSchema) do
@ -45,30 +45,30 @@ RSpec.describe Dry::Validation::Contract, '.schema' do
end
end
it 'defines a schema' do
it "defines a schema" do
expect(contract_class.schema).to be_a(Dry::Schema::Processor)
end
it 'extends the schema' do
it "extends the schema" do
contract = contract_class.new
expect(contract.(email: '', name: '').errors.to_h)
.to eql(email: ['must be filled'], name: ['must be filled'])
expect(contract.(email: "", name: "").errors.to_h)
.to eql(email: ["must be filled"], name: ["must be filled"])
end
context 'schema without block argument' do
context "schema without block argument" do
subject(:contract_class) do
Class.new(Dry::Validation::Contract) do
schema Test::UserSchema
end
end
it 'uses the external schema' do
it "uses the external schema" do
expect(contract_class.schema).to be_a(Dry::Schema::Processor)
end
end
context 'setting multiple external schemas' do
context "setting multiple external schemas" do
subject(:contract_class) do
Class.new(Dry::Validation::Contract) do
schema(Test::UserSchema, Test::CompanySchema) do
@ -83,12 +83,12 @@ RSpec.describe Dry::Validation::Contract, '.schema' do
end
end
it 'extends the schemas' do
it "extends the schemas" do
contract = contract_class.new
expect(contract.(email: '', name: '', company: '').errors.to_h)
.to eql(email: ['must be filled'],
name: ['must be filled'],
company: ['must be filled'])
expect(contract.(email: "", name: "", company: "").errors.to_h)
.to eql(email: ["must be filled"],
name: ["must be filled"],
company: ["must be filled"])
end
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe Dry::Validation::Evaluator do
describe '#schema_error?' do
describe "#schema_error?" do
let(:contract) do
Class.new(Dry::Validation::Contract) do
schema do
@ -10,20 +10,20 @@ RSpec.describe Dry::Validation::Evaluator do
end
rule(:name) do
key.failure('first introduce a valid email') if schema_error?(:email)
key.failure("first introduce a valid email") if schema_error?(:email)
end
end
end
it 'checks for errors in given key' do
expect(contract.new.(email: nil, name: 'foo').errors.to_h).to eql(
email: ['must be a string'],
name: ['first introduce a valid email']
it "checks for errors in given key" do
expect(contract.new.(email: nil, name: "foo").errors.to_h).to eql(
email: ["must be a string"],
name: ["first introduce a valid email"]
)
end
end
describe '#rule_error?' do
describe "#rule_error?" do
let(:contract) do
Class.new(Dry::Validation::Contract) do
schema do
@ -31,15 +31,15 @@ RSpec.describe Dry::Validation::Evaluator do
end
rule(:foo) do
key.failure('failure added')
key.failure('failure added after checking') if rule_error?
key.failure("failure added")
key.failure("failure added after checking") if rule_error?
end
end
end
it 'checks for errors in current rule' do
expect(contract.new.(foo: 'some@email.com').errors.to_h).to eql(
foo: ['failure added', 'failure added after checking']
it "checks for errors in current rule" do
expect(contract.new.(foo: "some@email.com").errors.to_h).to eql(
foo: ["failure added", "failure added after checking"]
)
end
end

View File

@ -13,109 +13,109 @@ RSpec.describe Dry::Validation::Evaluator do
end
end
context 'setting key failures using default rule path' do
context "setting key failures using default rule path" do
before do
contract_class.rule(:email) do
key.failure('is invalid')
key.failure("is invalid")
end
end
it 'sets error under specified key' do
expect(contract.(email: 'foo').errors.to_h).to eql(email: ['is invalid'])
it "sets error under specified key" do
expect(contract.(email: "foo").errors.to_h).to eql(email: ["is invalid"])
end
end
context 'setting key failures using via explicit path' do
context 'with a string message' do
context "setting key failures using via explicit path" do
context "with a string message" do
before do
contract_class.rule(:email) do
key(:contact).failure('is invalid')
key(:contact).failure("is invalid")
end
end
it 'sets error under specified key' do
expect(contract.(email: 'foo').errors.to_h).to eql(contact: ['is invalid'])
it "sets error under specified key" do
expect(contract.(email: "foo").errors.to_h).to eql(contact: ["is invalid"])
end
end
context 'with a nested key as a hash and a string message' do
context "with a nested key as a hash and a string message" do
before do
contract_class.rule(:email) do
key(contact: :details).failure('is invalid')
key(contact: :details).failure("is invalid")
end
end
it 'sets error under specified key' do
expect(contract.(email: 'foo').errors.to_h).to eql(contact: { details: ['is invalid'] })
it "sets error under specified key" do
expect(contract.(email: "foo").errors.to_h).to eql(contact: {details: ["is invalid"]})
end
end
context 'with a symbol' do
context "with a symbol" do
before do
contract_class.config.messages.load_paths << SPEC_ROOT
.join('fixtures/messages/errors.en.yml').realpath
.join("fixtures/messages/errors.en.yml").realpath
contract_class.rule(:email) do
key(:contact).failure(:wrong)
end
end
it 'sets error under specified key' do
expect(contract.(email: 'foo').errors.to_h).to eql(contact: ['not right'])
it "sets error under specified key" do
expect(contract.(email: "foo").errors.to_h).to eql(contact: ["not right"])
end
end
end
context 'setting base failures' do
context "setting base failures" do
before do
contract_class.rule(:email) do
base.failure('is invalid')
base.failure("is invalid")
end
end
it 'sets error under specified key' do
expect(contract.(email: 'foo').errors.to_h).to eql(nil => ['is invalid'])
it "sets error under specified key" do
expect(contract.(email: "foo").errors.to_h).to eql(nil => ["is invalid"])
end
end
context 'setting failures with meta data' do
context "setting failures with meta data" do
before do
contract_class.rule(:email) do
key.failure(text: 'is invalid', code: 102)
key.failure(text: "is invalid", code: 102)
end
end
it 'sets error under specified key' do
errors = contract.(email: 'foo').errors
it "sets error under specified key" do
errors = contract.(email: "foo").errors
expect(errors.to_h).to eql(email: [text: 'is invalid', code: 102])
expect(errors.to_h).to eql(email: [text: "is invalid", code: 102])
expect(errors.first.meta).to eql(code: 102)
end
context 'without :text key' do
context "without :text key" do
before do
contract_class.rule(:email) do
key.failure(code: 102)
end
end
it 'raises argument error if no text key provided' do
it "raises argument error if no text key provided" do
expect {
contract.(email: 'foo').errors
contract.(email: "foo").errors
}.to raise_error(ArgumentError, /Hash must contain :text key/)
end
end
end
context 'when localized message id is invalid' do
context "when localized message id is invalid" do
before do
contract_class.rule(:email) do
key.failure([:oops_bad_id])
end
end
it 'raises a meaningful error' do
expect { contract.(email: 'foo') }.to raise_error(ArgumentError, /oops_bad_id/)
it "raises a meaningful error" do
expect { contract.(email: "foo") }.to raise_error(ArgumentError, /oops_bad_id/)
end
end
end

View File

@ -1,11 +1,11 @@
# frozen_string_literal: true
RSpec.describe Dry::Validation::Evaluator, 'using context' do
RSpec.describe Dry::Validation::Evaluator, "using context" do
before(:all) do
Dry::Validation.load_extensions(:hints)
end
context 'when key does not exist' do
context "when key does not exist" do
subject(:contract) do
Dry::Validation.Contract do
schema do
@ -15,25 +15,25 @@ RSpec.describe Dry::Validation::Evaluator, 'using context' do
rule(:user_id) do |context:|
if values[:user_id].equal?(312)
context[:user] = 'jane'
context[:user] = "jane"
else
key(:user).failure('must be jane')
key(:user).failure("must be jane")
end
end
rule(:email) do |context:|
key.failure('is invalid') if context[:user] == 'jane' && values[:email] != 'jane@doe.org'
key.failure("is invalid") if context[:user] == "jane" && values[:email] != "jane@doe.org"
end
end
end
it 'stores new values between rule execution' do
expect(contract.(user_id: 3, email: 'john@doe.org').errors.to_h).to eql(user: ['must be jane'])
expect(contract.(user_id: 312, email: 'john@doe.org').errors.to_h).to eql(email: ['is invalid'])
it "stores new values between rule execution" do
expect(contract.(user_id: 3, email: "john@doe.org").errors.to_h).to eql(user: ["must be jane"])
expect(contract.(user_id: 312, email: "john@doe.org").errors.to_h).to eql(email: ["is invalid"])
end
it 'exposes context in result' do
expect(contract.(user_id: 312, email: 'jane@doe.org').context[:user]).to eql('jane')
it "exposes context in result" do
expect(contract.(user_id: 312, email: "jane@doe.org").context[:user]).to eql("jane")
end
end
end

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract, '.option' do
RSpec.describe Dry::Validation::Contract, ".option" do
subject(:contract_class) do
Class.new(Dry::Validation::Contract) do
option :db
@ -12,18 +12,18 @@ RSpec.describe Dry::Validation::Contract, '.option' do
end
rule(:email) do
key.failure('is taken') unless db.unique?(values[:email])
key.failure("is taken") unless db.unique?(values[:email])
end
end
end
let(:db) { double(:db) }
it 'allows injecting objects to the constructor' do
expect(db).to receive(:unique?).with('jane@doe.org').and_return(false)
it "allows injecting objects to the constructor" do
expect(db).to receive(:unique?).with("jane@doe.org").and_return(false)
contract = contract_class.new(db: db)
expect(contract.(email: 'jane@doe.org').errors.to_h).to eql(email: ['is taken'])
expect(contract.(email: "jane@doe.org").errors.to_h).to eql(email: ["is taken"])
end
end

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require 'dry/schema/messages/i18n'
require "dry/validation/contract"
require "dry/schema/messages/i18n"
RSpec.describe Dry::Validation::Contract, '.inherited' do
RSpec.describe Dry::Validation::Contract, ".inherited" do
subject(:child_class) do
Class.new(parent_class) do
params do
@ -26,15 +26,15 @@ RSpec.describe Dry::Validation::Contract, '.inherited' do
end
end
it 'inherits schema params' do
it "inherits schema params" do
expect(child_class.__schema__.key_map.map(&:name).sort).to eql(%w[email name])
end
it 'inherits rules' do
it "inherits rules" do
expect(child_class.rules.map(&:keys).sort).to eql([[:email], [:name]])
end
it 'inherits configuration' do
it "inherits configuration" do
expect(child_class.config.messages.backend).to eql(parent_class.config.messages.backend)
expect(child_class.config.messages.load_paths).to eql(parent_class.config.messages.load_paths)
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
RSpec.describe Dry::Validation::Contract, '.macros' do
RSpec.describe Dry::Validation::Contract, ".macros" do
subject!(:contract_class) do
Class.new(parent_class) do
register_macro(:other_macro) {}
@ -13,14 +13,14 @@ RSpec.describe Dry::Validation::Contract, '.macros' do
end
end
it 'returns macros container inherited from the parent' do
it "returns macros container inherited from the parent" do
expect(contract_class.macros.key?(:check_things)).to be(true)
expect(contract_class.macros.key?(:other_macro)).to be(true)
expect(parent_class.macros.key?(:other_macro)).to be(false)
end
it 'does not mutate source macro container' do
it "does not mutate source macro container" do
expect(parent_class.superclass.macros.key?(:check_things)).to be(false)
end
end

View File

@ -1,95 +1,95 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract do
shared_context 'translated messages' do
shared_context "translated messages" do
subject(:contract) do
contract_class.new
end
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
config.messages.load_paths << SPEC_ROOT.join('fixtures/messages/errors.en.yml').realpath
config.messages.load_paths << SPEC_ROOT.join("fixtures/messages/errors.en.yml").realpath
params do
required(:email).filled(:string, min_size?: 3, max_size?: 100)
end
rule(:email) do
key.failure(:invalid) unless value.include?('@')
key.failure(:taken, values.to_h) if value == 'jane@doe.org'
key.failure(:invalid) unless value.include?("@")
key.failure(:taken, values.to_h) if value == "jane@doe.org"
end
end
end
it 'configures messages for the schema' do
it "configures messages for the schema" do
expect(contract.schema.config.messages.load_paths)
.to eql(contract.class.config.messages.load_paths)
end
describe 'result errors' do
it 'supports full: true option for schema errors' do
expect(contract.call(email: '').errors(full: true).map(&:to_s))
.to eql(['E-mail must be filled'])
describe "result errors" do
it "supports full: true option for schema errors" do
expect(contract.call(email: "").errors(full: true).map(&:to_s))
.to eql(["E-mail must be filled"])
end
it 'supports full: true option for contract errors' do
expect(contract.call(email: 'jane').errors(full: true).map(&:to_s))
.to eql(['E-mail oh noez bad email'])
it "supports full: true option for contract errors" do
expect(contract.call(email: "jane").errors(full: true).map(&:to_s))
.to eql(["E-mail oh noez bad email"])
end
end
describe 'failure' do
it 'uses messages for failures' do
expect(contract.call(email: 'foo').errors.to_h)
.to eql(email: ['oh noez bad email'])
describe "failure" do
it "uses messages for failures" do
expect(contract.call(email: "foo").errors.to_h)
.to eql(email: ["oh noez bad email"])
end
it 'passes tokens to message templates' do
expect(contract.call(email: 'jane@doe.org').errors.to_h)
.to eql(email: ['looks like jane@doe.org is taken'])
it "passes tokens to message templates" do
expect(contract.call(email: "jane@doe.org").errors.to_h)
.to eql(email: ["looks like jane@doe.org is taken"])
end
end
end
context 'using :yaml messages' do
context "using :yaml messages" do
before do
contract_class.config.messages.backend = :yaml
end
include_context 'translated messages'
include_context "translated messages"
end
context 'using :i18n messages' do
context "using :i18n messages" do
before do
I18n.available_locales = %i[en pl]
contract_class.config.messages.backend = :i18n
contract_class.config.messages.load_paths << SPEC_ROOT.join('fixtures/messages/errors.pl.yml').realpath
contract_class.config.messages.load_paths << SPEC_ROOT.join("fixtures/messages/errors.pl.yml").realpath
contract
end
include_context 'translated messages'
include_context "translated messages"
it 'respects I18n.with_locale' do
it "respects I18n.with_locale" do
I18n.with_locale(:pl) do
expect(contract.call(email: 'foo').errors.to_h).to eql(email: ['oh nie zły email'])
expect(contract.call(email: "foo").errors.to_h).to eql(email: ["oh nie zły email"])
end
I18n.with_locale(:en) do
expect(contract.call(email: 'foo').errors.to_h).to eql(email: ['oh noez bad email'])
expect(contract.call(email: "foo").errors.to_h).to eql(email: ["oh noez bad email"])
end
expect(contract.call(email: 'foo').errors(locale: :pl).to_h).to eql(email: ['oh nie zły email'])
expect(contract.call(email: 'foo').errors.to_h).to eql(email: ['oh noez bad email'])
expect(contract.call(email: "foo").errors(locale: :pl).to_h).to eql(email: ["oh nie zły email"])
expect(contract.call(email: "foo").errors.to_h).to eql(email: ["oh noez bad email"])
end
end
it 'parses array tokens as a comma separated list' do
it "parses array tokens as a comma separated list" do
contract = Class.new(Dry::Validation::Contract) do
config.messages.load_paths << SPEC_ROOT.join('fixtures/messages/errors.en.yml').realpath
config.messages.load_paths << SPEC_ROOT.join("fixtures/messages/errors.en.yml").realpath
params do
required(:age).filled(:integer)
@ -101,6 +101,6 @@ RSpec.describe Dry::Validation::Contract do
end
end
expect(contract.new.call(age: 4).errors.to_h).to eql(age: ['should be included in 1, 2, 3'])
expect(contract.new.call(age: 4).errors.to_h).to eql(age: ["should be included in 1, 2, 3"])
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry/validation/contract'
require "dry/validation/contract"
RSpec.describe Dry::Validation::Contract do
subject(:contract) do
@ -14,27 +14,27 @@ RSpec.describe Dry::Validation::Contract do
end
rule(:email) do
key.failure('must be unique')
key.failure("must be unique")
end
end
end
describe '#inspect' do
it 'returns a string representation' do
describe "#inspect" do
it "returns a string representation" do
expect(contract.inspect).to eql(
%(#<Test::NewUserContract schema=#<Dry::Schema::Params keys=["email"] rules={:email=>"key?(:email) AND key[email](filled? AND str?)"}> rules=[#<Dry::Validation::Rule keys=[:email]>]>)
)
end
end
describe '.new' do
it 'raises error when schema is not defined' do
Test::NewUserContract.instance_variable_set('@__schema__', nil)
describe ".new" do
it "raises error when schema is not defined" do
Test::NewUserContract.instance_variable_set("@__schema__", nil)
expect { Test::NewUserContract.new }
.to raise_error(
Dry::Validation::SchemaMissingError,
'Test::NewUserContract cannot be instantiated without a schema defined'
"Test::NewUserContract cannot be instantiated without a schema defined"
)
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry/validation/evaluator'
require "dry/validation/evaluator"
RSpec.describe Dry::Validation::Evaluator do
subject(:evaluator) do
@ -12,27 +12,27 @@ RSpec.describe Dry::Validation::Evaluator do
end
let(:options) do
{ keys: [:email], result: {}, values: values, _context: {} }
{keys: [:email], result: {}, values: values, _context: {}}
end
let(:values) do
{}
end
describe 'delegation' do
describe "delegation" do
let(:block) do
proc {
key.failure('it works') if works?
key.failure("it works") if works?
}
end
it 'delegates to the contract' do
it "delegates to the contract" do
expect(contract).to receive(:works?).and_return(true)
expect(evaluator.failures[0][:path].to_a).to eql([:email])
expect(evaluator.failures[0][:message]).to eql('it works')
expect(evaluator.failures[0][:message]).to eql("it works")
end
describe 'with custom methods defined on the contract' do
describe "with custom methods defined on the contract" do
let(:contract) do
double(contract: :my_contract)
end
@ -41,8 +41,8 @@ RSpec.describe Dry::Validation::Evaluator do
proc { key.failure("message with #{contract}") }
end
it 'forwards to the contract' do
expect(evaluator.failures[0][:message]).to eql('message with my_contract')
it "forwards to the contract" do
expect(evaluator.failures[0][:message]).to eql("message with my_contract")
end
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
RSpec.describe Dry::Validation::Macros, ':acceptance' do
RSpec.describe Dry::Validation::Macros, ":acceptance" do
subject(:contract) do
Dry::Validation::Contract.build do
schema do
@ -11,11 +11,11 @@ RSpec.describe Dry::Validation::Macros, ':acceptance' do
end
end
it 'succeeds when value is true' do
it "succeeds when value is true" do
expect(contract.(terms: true)).to be_success
end
it 'fails when value is not true' do
expect(contract.(terms: false).errors.to_h).to eql(terms: ['must accept terms'])
it "fails when value is not true" do
expect(contract.(terms: false).errors.to_h).to eql(terms: ["must accept terms"])
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
RSpec.describe 'Defining custom macros' do
RSpec.describe "Defining custom macros" do
subject(:contract) do
contract_class.new
end
@ -17,49 +17,49 @@ RSpec.describe 'Defining custom macros' do
class Test::BaseContract < Dry::Validation::Contract; end
end
context 'using a macro without options' do
shared_context 'a contract with a custom macro' do
context "using a macro without options" do
shared_context "a contract with a custom macro" do
before do
contract_class.rule(:numbers).validate(:even_numbers)
end
it 'succeeds with valid input' do
it "succeeds with valid input" do
expect(contract.(numbers: [2, 4, 6])).to be_success
end
it 'fails with invalid input' do
expect(contract.(numbers: [1, 2, 3]).errors.to_h).to eql(numbers: ['all numbers must be even'])
it "fails with invalid input" do
expect(contract.(numbers: [1, 2, 3]).errors.to_h).to eql(numbers: ["all numbers must be even"])
end
end
context 'using macro from the global registry' do
context "using macro from the global registry" do
before do
Dry::Validation.register_macro(:even_numbers) do
key.failure('all numbers must be even') unless values[key_name].all?(&:even?)
key.failure("all numbers must be even") unless values[key_name].all?(&:even?)
end
end
after do
Dry::Validation::Macros.container._container.delete('even_numbers')
Dry::Validation::Macros.container._container.delete("even_numbers")
end
include_context 'a contract with a custom macro'
include_context "a contract with a custom macro"
end
context 'using macro from contract itself' do
context "using macro from contract itself" do
before do
Test::BaseContract.register_macro(:even_numbers) do
key.failure('all numbers must be even') unless values[key_name].all?(&:even?)
key.failure("all numbers must be even") unless values[key_name].all?(&:even?)
end
end
after do
Test::BaseContract.macros._container.delete('even_numbers')
Test::BaseContract.macros._container.delete("even_numbers")
end
end
end
context 'using a macro with options' do
context "using a macro with options" do
before do
Test::BaseContract.register_macro(:min) do |context:, macro:|
num = macro.args[0]
@ -71,16 +71,16 @@ RSpec.describe 'Defining custom macros' do
end
after do
Test::BaseContract.macros._container.delete('min')
Test::BaseContract.macros._container.delete("min")
end
it 'fails with invalid input' do
it "fails with invalid input" do
expect(contract.(numbers: [1]).errors.to_h)
.to eql(numbers: ['must have at least 3 items'])
.to eql(numbers: ["must have at least 3 items"])
end
end
context 'using a macro with a range option' do
context "using a macro with a range option" do
before do
Test::BaseContract.register_macro(:in_range) do |macro:|
range = macro.args[0]
@ -93,14 +93,14 @@ RSpec.describe 'Defining custom macros' do
end
after do
Test::BaseContract.macros._container.delete('in_range')
Test::BaseContract.macros._container.delete("in_range")
end
it 'succeeds with valid input' do
it "succeeds with valid input" do
expect(contract.(numbers: [1, 2, 3])).to be_success
end
it 'fails with invalid input' do
it "fails with invalid input" do
expect(contract.(numbers: [1, 2, 6])).to be_failure
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe Dry::Validation::Messages::Resolver, '#message' do
shared_context 'resolving' do
RSpec.describe Dry::Validation::Messages::Resolver, "#message" do
shared_context "resolving" do
subject(:resolver) do
contract_class.new(schema: proc {}).message_resolver
end
@ -17,30 +17,30 @@ RSpec.describe Dry::Validation::Messages::Resolver, '#message' do
I18n.available_locales << :pl
end
context ':en' do
context ":en" do
let(:locale) { :en }
it 'returns message text for base rule' do
it "returns message text for base rule" do
expect(resolver.message(:not_weekend, path: [nil], locale: locale))
.to eql(['this only works on weekends', {}])
.to eql(["this only works on weekends", {}])
end
it 'returns message text for flat rule' do
expect(resolver.message(:taken, path: [:email], tokens: { email: 'jane@doe.org' }, locale: locale))
.to eql(['looks like jane@doe.org is taken', {}])
it "returns message text for flat rule" do
expect(resolver.message(:taken, path: [:email], tokens: {email: "jane@doe.org"}, locale: locale))
.to eql(["looks like jane@doe.org is taken", {}])
end
it 'returns message text for nested rule when it is defined under root' do
it "returns message text for nested rule when it is defined under root" do
expect(resolver.message(:invalid, path: %i[address city], locale: locale))
.to eql(['is not a valid city name', {}])
.to eql(["is not a valid city name", {}])
end
it 'returns message text for nested rule' do
it "returns message text for nested rule" do
expect(resolver.message(:invalid, path: %i[address street], locale: locale))
.to eql(["doesn't look good", {}])
end
it 'raises error when template was not found' do
it "raises error when template was not found" do
expect { resolver.message(:not_here, path: [:email]) }
.to raise_error(Dry::Validation::MissingMessageError, <<~STR)
Message template for :not_here under "email" was not found
@ -48,44 +48,44 @@ RSpec.describe Dry::Validation::Messages::Resolver, '#message' do
end
end
context ':pl' do
context ":pl" do
let(:locale) { :pl }
it 'returns message text for base rule' do
it "returns message text for base rule" do
expect(resolver.message(:not_weekend, path: [nil], locale: locale))
.to eql(['to działa tylko w weekendy', {}])
.to eql(["to działa tylko w weekendy", {}])
end
it 'returns message text for flat rule' do
expect(resolver.message(:taken, path: [:email], tokens: { email: 'jane@doe.org' }, locale: locale))
.to eql(['wygląda, że jane@doe.org jest zajęty', {}])
it "returns message text for flat rule" do
expect(resolver.message(:taken, path: [:email], tokens: {email: "jane@doe.org"}, locale: locale))
.to eql(["wygląda, że jane@doe.org jest zajęty", {}])
end
it 'returns message text for nested rule when it is defined under root' do
it "returns message text for nested rule when it is defined under root" do
expect(resolver.message(:invalid, path: %i[address city], locale: locale))
.to eql(['nie jest poprawną nazwą miasta', {}])
.to eql(["nie jest poprawną nazwą miasta", {}])
end
it 'returns message text for nested rule' do
it "returns message text for nested rule" do
expect(resolver.message(:invalid, path: %i[address street], locale: locale))
.to eql(['nie wygląda dobrze', {}])
.to eql(["nie wygląda dobrze", {}])
end
end
end
context 'using :yaml' do
context "using :yaml" do
before do
contract_class.config.messages.backend = :yaml
end
include_context 'resolving'
include_context "resolving"
end
context 'using :i18n' do
context "using :i18n" do
before do
contract_class.config.messages.backend = :i18n
end
include_context 'resolving'
include_context "resolving"
end
end

View File

@ -1,63 +1,63 @@
# frozen_string_literal: true
RSpec.describe Dry::Validation::Result do
describe '#inspect' do
describe "#inspect" do
let(:params) do
double(:params, message_set: [], to_h: { email: 'jane@doe.org' })
double(:params, message_set: [], to_h: {email: "jane@doe.org"})
end
it 'returns a string representation' do
it "returns a string representation" do
result = Dry::Validation::Result.new(params) do |r|
r.add_error(Dry::Validation::Message.new('not valid', path: :email))
r.add_error(Dry::Validation::Message.new("not valid", path: :email))
end
expect(result.inspect).to eql('#<Dry::Validation::Result{:email=>"jane@doe.org"} errors={:email=>["not valid"]}>')
end
end
describe '#errors' do
describe "#errors" do
subject(:errors) { result.errors }
let(:params) do
double(:params, message_set: [], to_h: { email: 'jane@doe.org' })
double(:params, message_set: [], to_h: {email: "jane@doe.org"})
end
let(:result) do
Dry::Validation::Result.new(params) do |r|
r.add_error(Dry::Validation::Message.new('root error', path: [nil]))
r.add_error(Dry::Validation::Message.new('email error', path: [:email]))
r.add_error(Dry::Validation::Message.new("root error", path: [nil]))
r.add_error(Dry::Validation::Message.new("email error", path: [:email]))
end
end
describe '#[]' do
it 'returns error messages for the provided key' do
expect(errors[:email]).to eql(['email error'])
describe "#[]" do
it "returns error messages for the provided key" do
expect(errors[:email]).to eql(["email error"])
end
it 'returns [] for base errors' do
expect(errors[nil]).to eql(['root error'])
it "returns [] for base errors" do
expect(errors[nil]).to eql(["root error"])
end
end
describe '#empty?' do
describe "#empty?" do
let(:result) { Dry::Validation::Result.new(params) }
it 'should return the correct value whilst adding errors' do
it "should return the correct value whilst adding errors" do
expect(result.errors).to be_empty
result.add_error(Dry::Validation::Message.new('root error', path: [nil]))
result.add_error(Dry::Validation::Message.new("root error", path: [nil]))
expect(result.errors).not_to be_empty
end
end
end
describe '#inspect' do
describe "#inspect" do
let(:params) do
double(:params, message_set: [], to_h: {})
end
let(:context) do
context = Concurrent::Map.new
context[:data] = 'foo'
context[:data] = "foo"
context
end
@ -65,7 +65,7 @@ RSpec.describe Dry::Validation::Result do
Dry::Validation::Result.new(params, context)
end
example 'results are inspectable' do
example "results are inspectable" do
expect(result.inspect).to be_a(String)
end
end

View File

@ -1,30 +1,30 @@
# frozen_string_literal: true
require_relative 'support/coverage'
require_relative 'support/warnings'
require_relative "support/coverage"
require_relative "support/warnings"
begin
require 'pry'
require 'pry-byebug'
require "pry"
require "pry-byebug"
rescue LoadError
end
require 'i18n'
require 'dry/validation'
require "i18n"
require "dry/validation"
SPEC_ROOT = Pathname(__dir__)
Dir[SPEC_ROOT.join('support/**/*.rb')].each(&method(:require))
Dir[SPEC_ROOT.join("support/**/*.rb")].each(&method(:require))
RSpec.configure do |config|
unless RUBY_VERSION >= '2.7'
config.exclude_pattern = '**/pattern_matching_spec.rb'
unless RUBY_VERSION >= "2.7"
config.exclude_pattern = "**/pattern_matching_spec.rb"
end
config.disable_monkey_patching!
config.before do
stub_const('Test', Module.new)
stub_const("Test", Module.new)
end
config.after do

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'dry/validation/values'
require "dry/validation/values"
RSpec.describe Dry::Validation::Values do
subject(:values) do
@ -8,92 +8,92 @@ RSpec.describe Dry::Validation::Values do
end
let(:data) do
{ name: 'Jane', address: { city: 'Paris', geo: { lat: 1, lon: 2 } }, phones: [123, 431] }
{name: "Jane", address: {city: "Paris", geo: {lat: 1, lon: 2}}, phones: [123, 431]}
end
describe '#[]' do
it 'works with a symbol' do
expect(values[:name]).to eql('Jane')
describe "#[]" do
it "works with a symbol" do
expect(values[:name]).to eql("Jane")
end
it 'works with a dot-notation path' do
expect(values['address.city']).to eql('Paris')
it "works with a dot-notation path" do
expect(values["address.city"]).to eql("Paris")
end
it 'works with a path' do
expect(values[:address, :city]).to eql('Paris')
it "works with a path" do
expect(values[:address, :city]).to eql("Paris")
end
it 'works with a hash' do
expect(values[address: :city]).to eql('Paris')
it "works with a hash" do
expect(values[address: :city]).to eql("Paris")
end
it 'works with a hash pointing to multiple values' do
expect(values[address: { geo: [:lat, :lon] }]).to eql([1, 2])
it "works with a hash pointing to multiple values" do
expect(values[address: {geo: [:lat, :lon]}]).to eql([1, 2])
end
it 'works with an array' do
expect(values[%i[address city]]).to eql('Paris')
it "works with an array" do
expect(values[%i[address city]]).to eql("Paris")
end
it 'raises on unpexpected argument type' do
it "raises on unpexpected argument type" do
expect { values[123] }
.to raise_error(
ArgumentError, '+key+ must be a valid path specification'
ArgumentError, "+key+ must be a valid path specification"
)
end
it 'accepts missing keys returning nil' do
expect(values[address: { geo: [:population, :lon] }]).to eql([nil, 2])
it "accepts missing keys returning nil" do
expect(values[address: {geo: [:population, :lon]}]).to eql([nil, 2])
end
end
describe '#key?' do
it 'returns true when a symbol key is present' do
describe "#key?" do
it "returns true when a symbol key is present" do
expect(values.key?(:name)).to be(true)
end
it 'returns false when a symbol key is not present' do
it "returns false when a symbol key is not present" do
expect(values.key?(:not_here)).to be(false)
end
it 'returns true when a nested key is present' do
it "returns true when a nested key is present" do
expect(values.key?([:address, :city])).to be(true)
end
it 'returns false when a nested key is not present' do
it "returns false when a nested key is not present" do
expect(values.key?([:address, :not_here])).to be(false)
end
it 'returns true when nested keys are all present' do
it "returns true when nested keys are all present" do
expect(values.key?([:address, :geo, [:lat, :lon]])).to be(true)
end
it 'returns false when nested keys are not all present' do
it "returns false when nested keys are not all present" do
expect(values.key?([:address, :geo, [:lat, :lon, :other]])).to be(false)
end
it 'returns true when a path to an array element is present' do
it "returns true when a path to an array element is present" do
expect(values.key?([:phones, 1])).to be(true)
end
it 'returns false when a path to an array element is not present' do
it "returns false when a path to an array element is not present" do
expect(values.key?([:phones, 5])).to be(false)
end
end
describe '#dig' do
it 'returns a value from a nested hash when it exists' do
expect(values.dig(:address, :city)).to eql('Paris')
describe "#dig" do
it "returns a value from a nested hash when it exists" do
expect(values.dig(:address, :city)).to eql("Paris")
end
it 'returns nil otherwise' do
it "returns nil otherwise" do
expect(values.dig(:oops, :not_here)).to be(nil)
end
end
describe '#method_missing' do
it 'forwards to data' do
describe "#method_missing" do
it "forwards to data" do
result = []
values.each do |k, v|
@ -103,14 +103,14 @@ RSpec.describe Dry::Validation::Values do
expect(result).to eql(values.to_a)
end
it 'raises NoMethodError when data does not respond to the meth' do
it "raises NoMethodError when data does not respond to the meth" do
expect { values.not_really_implemented }
.to raise_error(NoMethodError, /not_really_implemented/)
end
end
describe '#method' do
it 'returns Method objects for a forwarded method' do
describe "#method" do
it "returns Method objects for a forwarded method" do
expect(values.method(:dig)).to be_instance_of(Method)
end
end