diff --git a/config/reek.yml b/config/reek.yml index 59810dc7..ef930a64 100644 --- a/config/reek.yml +++ b/config/reek.yml @@ -36,7 +36,7 @@ ControlParameter: - Axiom::Function::Connective::Conjunction#self.call - Axiom::Function::Connective::Disjunction#self.call - Axiom::Function::Predicate::Enumerable#self.compare_method - - Axiom::Relation::Operation::Limit::Methods#assert_no_more_than_one_tuple + - Axiom::Relation#assert_no_more_than_one_tuple DataClump: enabled: true exclude: diff --git a/lib/axiom/relation.rb b/lib/axiom/relation.rb index 4e616a66..69a3e4cb 100644 --- a/lib/axiom/relation.rb +++ b/lib/axiom/relation.rb @@ -7,6 +7,12 @@ class Relation include Enumerable, Visitable, Adamantium::Flat include Equalizer.new(:header, :to_set) + # Default block used in #one + DEFAULT_ONE_BLOCK = -> {} + + # Maximum number of tuples to take in #one + ONE_LIMIT = 2 + # The relation header # # @return [Header] @@ -145,6 +151,32 @@ def replace(other) delete(difference(other)).insert(other.difference(self)) end + # Return a tuple if the relation contains exactly one tuple + # + # @example without a block + # tuple = relation.one + # + # @example with a block + # tuple = relation.one { ... } + # + # @yieldreturn [Object] + # + # @return [Tuple] + # + # @raise [NoTuplesError] + # raised if no tuples are returned + # @raise [ManyTuplesError] + # raised if more than one tuple is returned + # + # @api public + def one(&block) + block ||= DEFAULT_ONE_BLOCK + tuples = sort.take(ONE_LIMIT).to_a + assert_no_more_than_one_tuple(tuples.size) + tuples.first or block.yield or + fail NoTuplesError, 'one tuple expected, but was an empty set' + end + # Return a relation with each tuple materialized # # @example @@ -245,5 +277,21 @@ def self.coerce(header, object) end end + # Assert no more than one tuple is returned + # + # @return [undefined] + # + # @raise [ManyTuplesError] + # raised if more than one tuple is returned + # + # @api private + def assert_no_more_than_one_tuple(size) + return if size <= 1 + fail( + ManyTuplesError, + "one tuple expected, but set contained #{count} tuples" + ) + end + end # class Relation end # module Axiom diff --git a/lib/axiom/relation/operation/limit.rb b/lib/axiom/relation/operation/limit.rb index 6ac7eb8f..40226e32 100644 --- a/lib/axiom/relation/operation/limit.rb +++ b/lib/axiom/relation/operation/limit.rb @@ -150,12 +150,6 @@ def delete(*) module Methods - # Default block used in #one - DEFAULT_ONE_BLOCK = -> {} - - # Maximum number of tuples to take in #one - ONE_LIMIT = 2 - # Return a relation with n tuples # # @example @@ -207,50 +201,6 @@ def last(limit = 1) reverse.take(limit).reverse end - # Return a tuple if the relation contains exactly one tuple - # - # @example without a block - # tuple = relation.one - # - # @example with a block - # tuple = relation.one { ... } - # - # @yieldreturn [Object] - # - # @return [Tuple] - # - # @raise [NoTuplesError] - # raised if no tuples are returned - # @raise [ManyTuplesError] - # raised if more than one tuple is returned - # - # @api public - def one(&block) - block ||= DEFAULT_ONE_BLOCK - tuples = take(ONE_LIMIT).to_a - assert_no_more_than_one_tuple(tuples.size) - tuples.first or block.yield or - fail NoTuplesError, 'one tuple expected, but was an empty set' - end - - private - - # Assert no more than one tuple is returned - # - # @return [undefined] - # - # @raise [ManyTuplesError] - # raised if more than one tuple is returned - # - # @api private - def assert_no_more_than_one_tuple(size) - return if size <= 1 - fail( - ManyTuplesError, - "one tuple expected, but set contained #{count} tuples" - ) - end - end # module Methods Relation.class_eval { include Methods } diff --git a/spec/unit/axiom/relation/operation/limit/methods/one_spec.rb b/spec/unit/axiom/relation/one_spec.rb similarity index 91% rename from spec/unit/axiom/relation/operation/limit/methods/one_spec.rb rename to spec/unit/axiom/relation/one_spec.rb index 18573001..7308771b 100644 --- a/spec/unit/axiom/relation/operation/limit/methods/one_spec.rb +++ b/spec/unit/axiom/relation/one_spec.rb @@ -2,10 +2,10 @@ require 'spec_helper' -describe Relation::Operation::Limit::Methods, '#one' do +describe Relation, '#one' do subject { object.one } - let(:object) { Relation.new(header, body).sort } + let(:object) { Relation.new(header, body) } let(:header) { Relation::Header.coerce([[:id, Integer]]) } context 'with a relation having no tuples without a block' do