spec/unit/rule/key_spec.rb in dry-logic-0.1.4 vs spec/unit/rule/key_spec.rb in dry-logic-0.2.0
- old
+ new
@@ -1,27 +1,121 @@
require 'dry/logic/rule'
-RSpec.describe Dry::Logic::Rule::Key do
+RSpec.describe Rule::Key do
include_context 'predicates'
- subject(:rule) { Dry::Logic::Rule::Key.new(:name, key?) }
+ subject(:rule) do
+ Rule::Key.new(predicate, name: :user)
+ end
+ let(:predicate) do
+ key?.curry(:name)
+ end
+
describe '#call' do
- it 'applies predicate to the value' do
- expect(rule.(name: 'Jane')).to be_success
- expect(rule.({})).to be_failure
+ context 'with a plain predicate' do
+ it 'applies predicate to the value' do
+ expect(rule.(user: { name: 'Jane' })).to be_success
+ expect(rule.(user: {})).to be_failure
+ end
+
+ context 'with a custom predicate' do
+ let(:predicate) { -> input { double(success?: true, to_ast: [:foo]) } }
+
+ let(:result) { rule.(test: true) }
+
+ it 'delegates to_ast to response' do
+ expect(result.to_ast).to eql([:foo])
+ end
+ end
end
+
+ context 'with a set rule as predicate' do
+ subject(:rule) do
+ Rule::Key.new(predicate, name: :address)
+ end
+
+ let(:predicate) do
+ Rule::Set.new(
+ [Rule::Value.new(key?.curry(:city)), Rule::Value.new(key?.curry(:zipcode))]
+ )
+ end
+
+ it 'applies set rule to the value that passes' do
+ result = rule.(address: { city: 'NYC', zipcode: '123' })
+
+ expect(result).to be_success
+ end
+
+ it 'applies set rule to the value that fails' do
+ result = rule.(address: { city: 'NYC' })
+
+ expect(result).to be_failure
+
+ expect(result.to_ast).to eql([
+ :input, [
+ :address,
+ [:result, [
+ { city: "NYC" },
+ [:set, [[:result, [{ city: 'NYC' }, [:val, [:predicate, [:key?, [:zipcode]]]]]]]]
+ ]]
+ ]
+ ])
+ end
+ end
+
+ context 'with an each rule as predicate' do
+ subject(:rule) do
+ Rule::Key.new(predicate, name: :nums)
+ end
+
+ let(:predicate) do
+ Rule::Each.new(Rule::Value.new(str?))
+ end
+
+ it 'applies each rule to the value that passses' do
+ result = rule.(nums: %w(1 2 3))
+
+ expect(result).to be_success
+
+ expect(result.to_ast).to eql([
+ :input, [:nums, [:result, [%w(1 2 3), [:each, []]]]]
+ ])
+ end
+
+ it 'applies each rule to the value that fails' do
+ failure = rule.(nums: [1, '3', 3])
+
+ expect(failure).to be_failure
+
+ expect(failure.to_ast).to eql([
+ :input, [
+ :nums, [
+ :result, [
+ [1, '3', 3],
+ [:each, [
+ [:el, [0, [:result, [1, [:val, [:predicate, [:str?, []]]]]]]],
+ [:el, [2, [:result, [3, [:val, [:predicate, [:str?, []]]]]]]]
+ ]]
+ ]
+ ]
+ ]
+ ])
+ end
+ end
end
describe '#and' do
- let(:other) { Dry::Logic::Rule::Value.new(:name, str?) }
+ let(:other) do
+ Rule::Key.new(str?, name: [:user, :name])
+ end
it 'returns conjunction rule where value is passed to the right' do
present_and_string = rule.and(other)
- expect(present_and_string.(name: 'Jane')).to be_success
+ expect(present_and_string.(user: { name: 'Jane' })).to be_success
- expect(present_and_string.({})).to be_failure
- expect(present_and_string.(name: 1)).to be_failure
+ expect(present_and_string.(user: {})).to be_failure
+ expect(present_and_string.(user: { name: 1 })).to be_failure
end
end
end