Skip to content

Commit

Permalink
Implement Scopes::Container.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepingkingstudios committed Dec 27, 2023
1 parent a45c05a commit 007f6f8
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 9 deletions.
95 changes: 86 additions & 9 deletions lib/cuprum/collections/rspec/contracts/scope_contracts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,83 @@
module Cuprum::Collections::RSpec::Contracts
# Contracts for asserting on scope objects.
module ScopeContracts
# Contract validating the behavior of a Container scope.
module ShouldBeAContainerScopeContract
extend RSpec::SleepingKingStudios::Contract

# @!method apply(example_group)
# Adds the contract to the example group.
#
# @param example_group [RSpec::Core::ExampleGroup] the example group to
# which the contract is applied.
contract do
shared_context 'with scopes' do
let(:scopes) do
[
described_class.new(scopes: []),
described_class.new(scopes: []),
described_class.new(scopes: [])
]
end
end

describe '.new' do
it 'should define the constructor' do
expect(described_class)
.to be_constructible
.with(0).arguments
.and_keywords(:scopes)
.and_any_keywords
end
end

describe '#scopes' do
include_examples 'should define reader', :scopes, -> { scopes }

wrap_context 'with scopes' do
it { expect(subject.scopes).to be == scopes }
end
end

describe '#with_scopes' do
let(:new_scopes) do
[
described_class.new(scopes: []),
described_class.new(scopes: [])
]
end

it { expect(subject).to respond_to(:with_scopes).with(1).arguments }

it 'should return a scope' do
expect(subject.with_scopes(new_scopes)).to be_a described_class
end

it "should not change the original scope's child scopes" do
expect { subject.with_scopes(new_scopes) }
.not_to change(subject, :scopes)
end

it "should set the copied scope's child scopes" do
expect(subject.with_scopes(new_scopes).scopes)
.to be == new_scopes
end

wrap_context 'with scopes' do
it "should not change the original scope's child scopes" do
expect { subject.with_scopes(new_scopes) }
.not_to change(subject, :scopes)
end

it "should set the copied scope's child scopes" do
expect(subject.with_scopes(new_scopes).scopes)
.to be == new_scopes
end
end
end
end
end

# Contract validating the behavior of a Criteria scope implementation.
module ShouldBeACriteriaScopeContract
extend RSpec::SleepingKingStudios::Contract
Expand Down Expand Up @@ -79,37 +156,37 @@ def parse_criteria(*args, &block)
include_examples 'should define reader', :criteria, -> { criteria }

wrap_context 'with criteria' do
it { expect(scope.criteria).to be == criteria }
it { expect(subject.criteria).to be == criteria }
end
end

describe '#with_criteria' do
let(:new_criteria) { ['author', 'eq', 'Ursula K. LeGuin'] }

it { expect(scope).to respond_to(:with_criteria).with(1).argument }
it { expect(subject).to respond_to(:with_criteria).with(1).argument }

it 'should return a scope' do
expect(scope.with_criteria(new_criteria)).to be_a described_class
expect(subject.with_criteria(new_criteria)).to be_a described_class
end

it "should not change the original scope's criteria" do
expect { scope.with_criteria(new_criteria) }
.not_to change(scope, :criteria)
expect { subject.with_criteria(new_criteria) }
.not_to change(subject, :criteria)
end

it "should set the copied scope's criteria" do
expect(scope.with_criteria(new_criteria).criteria)
expect(subject.with_criteria(new_criteria).criteria)
.to be == new_criteria
end

wrap_context 'with criteria' do
it "should not change the original scope's criteria" do
expect { scope.with_criteria(new_criteria) }
.not_to change(scope, :criteria)
expect { subject.with_criteria(new_criteria) }
.not_to change(subject, :criteria)
end

it "should set the copied scope's criteria" do
expect(scope.with_criteria(new_criteria).criteria)
expect(subject.with_criteria(new_criteria).criteria)
.to be == new_criteria
end
end
Expand Down
32 changes: 32 additions & 0 deletions lib/cuprum/collections/scopes/container.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

require 'cuprum/collections/scopes'

module Cuprum::Collections::Scopes
# Functionality for implementing a scope container.
module Container
# @param scopes [Array<Scope>] the scopes wrapped by the scope.
# @param options [Hash] additional options for the scope.
def initialize(scopes:, **options)
super(**options)

@scopes = scopes
end

# @return [Array<Scope>] the scopes wrapped by the scope.
attr_reader :scopes

# Creates a copy of the scope with the given child scopes.
#
# @param scopes [Array] the child scopes.
#
# @return [Scope] the copied scope.
def with_scopes(scopes)
dup.tap { |copy| copy.scopes = scopes }
end

protected

attr_writer :scopes
end
end
1 change: 1 addition & 0 deletions lib/cuprum/collections/scopes/criteria.rb
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ def included(other)
end

# @param criteria [Array] the criteria used for filtering query data.
# @param options [Hash] additional options for the scope.
def initialize(criteria:, **options)
super(**options)

Expand Down
20 changes: 20 additions & 0 deletions spec/cuprum/collections/scopes/container_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

require 'cuprum/collections/scope'
require 'cuprum/collections/scopes/container'
require 'cuprum/collections/rspec/contracts/scope_contracts'

RSpec.describe Cuprum::Collections::Scopes::Container do
include Cuprum::Collections::RSpec::Contracts::ScopeContracts

subject(:scope) { described_class.new(scopes: scopes) }

let(:described_class) { Spec::ExampleScope }
let(:scopes) { [] }

example_class 'Spec::ExampleScope', Cuprum::Collections::Scope do |klass|
klass.include Cuprum::Collections::Scopes::Container # rubocop:disable RSpec/DescribedClass
end

include_contract 'should be a container scope'
end

0 comments on commit 007f6f8

Please sign in to comment.