mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
qualified naming
This commit is contained in:
parent
346d9c6bde
commit
d7b89d957d
26 changed files with 283 additions and 60 deletions
|
@ -33,6 +33,7 @@ require 'sql_algebra/predicates/match_predicate'
|
|||
|
||||
require 'sql_algebra/extensions/range'
|
||||
require 'sql_algebra/extensions/object'
|
||||
require 'sql_algebra/extensions/array'
|
||||
|
||||
require 'sql_algebra/sql_builder/sql_builder'
|
||||
require 'sql_algebra/sql_builder/select_builder'
|
||||
|
|
5
lib/sql_algebra/extensions/array.rb
Normal file
5
lib/sql_algebra/extensions/array.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class Array
|
||||
def to_hash
|
||||
Hash[*flatten]
|
||||
end
|
||||
end
|
|
@ -3,12 +3,12 @@ class ActiveRecord::Base
|
|||
object = cache.get(record % klass.primary_key) { Klass.instantiate(record % Klass.attributes) }
|
||||
includes.each do |include|
|
||||
case include
|
||||
when Symbol
|
||||
object.send(association = include).bring_forth(record)
|
||||
when Hash
|
||||
include.each do |association, nested_associations|
|
||||
object.send(association).bring_forth(record, nested_associations)
|
||||
end
|
||||
when Symbol
|
||||
object.send(association = include).bring_forth(record)
|
||||
when Hash
|
||||
include.each do |association, nested_associations|
|
||||
object.send(association).bring_forth(record, nested_associations)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
class Object
|
||||
def qualify
|
||||
self
|
||||
end
|
||||
|
||||
def to_sql(builder = EqualsConditionBuilder.new)
|
||||
me = self
|
||||
builder.call do
|
||||
|
|
|
@ -10,6 +10,10 @@ class BinaryPredicate < Predicate
|
|||
(attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2))
|
||||
end
|
||||
|
||||
def qualify
|
||||
self.class.new(attribute1.qualify, attribute2.qualify)
|
||||
end
|
||||
|
||||
def to_sql(builder = ConditionsBuilder.new)
|
||||
builder.call do
|
||||
send(predicate_name) do
|
||||
|
|
|
@ -4,7 +4,7 @@ class EqualityPredicate < BinaryPredicate
|
|||
((attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) or
|
||||
(attribute1.eql?(other.attribute2) and attribute2.eql?(other.attribute1)))
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def predicate_name
|
||||
:equals
|
||||
|
|
|
@ -1,45 +1,56 @@
|
|||
class Attribute
|
||||
attr_reader :relation, :attribute_name, :aliaz
|
||||
attr_reader :relation, :name, :aliaz
|
||||
|
||||
def initialize(relation, attribute_name, aliaz = nil)
|
||||
@relation, @attribute_name, @aliaz = relation, attribute_name, aliaz
|
||||
def initialize(relation, name, aliaz = nil)
|
||||
@relation, @name, @aliaz = relation, name, aliaz
|
||||
end
|
||||
|
||||
def aliazz(aliaz)
|
||||
Attribute.new(relation, attribute_name, aliaz)
|
||||
Attribute.new(relation, name, aliaz)
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
relation == other.relation and attribute_name == other.attribute_name
|
||||
def qualified_name
|
||||
"#{relation.table}.#{name}"
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
EqualityPredicate.new(self, other)
|
||||
def qualify
|
||||
aliazz(qualified_name)
|
||||
end
|
||||
|
||||
module Predications
|
||||
def eql?(other)
|
||||
relation == other.relation and name == other.name and aliaz == other.aliaz
|
||||
end
|
||||
|
||||
def <(other)
|
||||
LessThanPredicate.new(self, other)
|
||||
end
|
||||
def ==(other)
|
||||
EqualityPredicate.new(self, other)
|
||||
end
|
||||
|
||||
def <=(other)
|
||||
LessThanOrEqualToPredicate.new(self, other)
|
||||
end
|
||||
def <(other)
|
||||
LessThanPredicate.new(self, other)
|
||||
end
|
||||
|
||||
def >(other)
|
||||
GreaterThanPredicate.new(self, other)
|
||||
end
|
||||
def <=(other)
|
||||
LessThanOrEqualToPredicate.new(self, other)
|
||||
end
|
||||
|
||||
def >=(other)
|
||||
GreaterThanOrEqualToPredicate.new(self, other)
|
||||
end
|
||||
def >(other)
|
||||
GreaterThanPredicate.new(self, other)
|
||||
end
|
||||
|
||||
def =~(regexp)
|
||||
MatchPredicate.new(self, regexp)
|
||||
def >=(other)
|
||||
GreaterThanOrEqualToPredicate.new(self, other)
|
||||
end
|
||||
|
||||
def =~(regexp)
|
||||
MatchPredicate.new(self, regexp)
|
||||
end
|
||||
end
|
||||
include Predications
|
||||
|
||||
def to_sql(builder = SelectsBuilder.new)
|
||||
builder.call do
|
||||
column relation.table, attribute_name, aliaz
|
||||
column relation.table, name, aliaz
|
||||
end
|
||||
end
|
||||
end
|
|
@ -16,7 +16,7 @@ class JoinRelation < Relation
|
|||
end
|
||||
|
||||
def selects
|
||||
relation1.selects + relation2.selects
|
||||
relation1.send(:selects) + relation2.send(:selects)
|
||||
end
|
||||
|
||||
def attributes
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class OrderRelation < Relation
|
||||
class OrderRelation < CompoundRelation
|
||||
attr_reader :relation, :attributes
|
||||
|
||||
def initialize(relation, *attributes)
|
||||
|
@ -9,6 +9,10 @@ class OrderRelation < Relation
|
|||
relation == other.relation and attributes.eql?(other.attributes)
|
||||
end
|
||||
|
||||
def qualify
|
||||
OrderRelation.new(relation.qualify, *attributes.collect { |a| a.qualify })
|
||||
end
|
||||
|
||||
def to_sql(builder = SelectBuilder.new)
|
||||
relation.to_sql(builder).call do
|
||||
attributes.each do |attribute|
|
||||
|
|
|
@ -9,6 +9,10 @@ class ProjectionRelation < Relation
|
|||
relation == other.relation and attributes.eql?(other.attributes)
|
||||
end
|
||||
|
||||
def qualify
|
||||
ProjectionRelation.new(relation.qualify, *attributes.collect(&:qualify))
|
||||
end
|
||||
|
||||
def to_sql(builder = SelectBuilder.new)
|
||||
relation.to_sql(builder).call do
|
||||
select do
|
||||
|
|
|
@ -34,7 +34,7 @@ class Relation
|
|||
end
|
||||
|
||||
def rename(attribute, aliaz)
|
||||
RenameRelation.new(self, attribute, aliaz)
|
||||
RenameRelation.new(self, attribute => aliaz)
|
||||
end
|
||||
end
|
||||
include Operations
|
||||
|
|
34
lib/sql_algebra/relations/rename_relation.rb
Normal file
34
lib/sql_algebra/relations/rename_relation.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
class RenameRelation < CompoundRelation
|
||||
attr_reader :relation, :schmattribute, :aliaz
|
||||
|
||||
def initialize(relation, renames)
|
||||
@schmattribute, @aliaz = renames.shift
|
||||
@relation = renames.empty?? relation : RenameRelation.new(relation, renames)
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
relation == other.relation and schmattribute.eql?(other.schmattribute) and aliaz == other.aliaz
|
||||
end
|
||||
|
||||
def attributes
|
||||
relation.attributes.collect { |a| substitute(a) }
|
||||
end
|
||||
|
||||
def qualify
|
||||
RenameRelation.new(relation.qualify, schmattribute.qualify => aliaz)
|
||||
end
|
||||
|
||||
protected
|
||||
def attribute(name)
|
||||
case
|
||||
when name == aliaz then schmattribute.aliazz(aliaz)
|
||||
when relation[name].eql?(schmattribute) then nil
|
||||
else relation[name]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def substitute(a)
|
||||
a.eql?(schmattribute) ? a.aliazz(aliaz) : a
|
||||
end
|
||||
end
|
|
@ -10,6 +10,11 @@ class SelectionRelation < CompoundRelation
|
|||
relation == other.relation and predicate == other.predicate
|
||||
end
|
||||
|
||||
def qualify
|
||||
SelectionRelation.new(relation.qualify, predicate.qualify)
|
||||
end
|
||||
|
||||
protected
|
||||
def selects
|
||||
[predicate]
|
||||
end
|
||||
|
|
|
@ -8,6 +8,10 @@ class TableRelation < Relation
|
|||
def attributes
|
||||
attributes_by_name.values
|
||||
end
|
||||
|
||||
def qualify
|
||||
RenameRelation.new self, qualifications
|
||||
end
|
||||
|
||||
protected
|
||||
def attribute(name)
|
||||
|
@ -20,4 +24,8 @@ class TableRelation < Relation
|
|||
attributes_by_name.merge(column.name => Attribute.new(self, column.name.to_sym))
|
||||
end
|
||||
end
|
||||
|
||||
def qualifications
|
||||
attributes.zip(attributes.collect(&:qualified_name)).to_hash
|
||||
end
|
||||
end
|
|
@ -33,4 +33,9 @@ describe 'Relational Algebra' do
|
|||
users.id = 1
|
||||
""")
|
||||
end
|
||||
|
||||
it '' do
|
||||
#
|
||||
# @users.rename()
|
||||
end
|
||||
end
|
|
@ -4,8 +4,8 @@ describe BinaryPredicate do
|
|||
before do
|
||||
@relation1 = TableRelation.new(:foo)
|
||||
@relation2 = TableRelation.new(:bar)
|
||||
@attribute1 = Attribute.new(@relation1, :attribute_name1)
|
||||
@attribute2 = Attribute.new(@relation2, :attribute_name2)
|
||||
@attribute1 = Attribute.new(@relation1, :name1)
|
||||
@attribute2 = Attribute.new(@relation2, :name2)
|
||||
class ConcreteBinaryPredicate < BinaryPredicate
|
||||
def predicate_name
|
||||
:equals
|
||||
|
@ -31,12 +31,19 @@ describe BinaryPredicate do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#qualify' do
|
||||
it "manufactures an equality predicate with qualified attributes" do
|
||||
ConcreteBinaryPredicate.new(@attribute1, @attribute2).qualify. \
|
||||
should == ConcreteBinaryPredicate.new(@attribute1.qualify, @attribute2.qualify)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_sql' do
|
||||
it 'manufactures correct sql' do
|
||||
ConcreteBinaryPredicate.new(@attribute1, @attribute2).to_sql.should == ConditionsBuilder.new do
|
||||
equals do
|
||||
column :foo, :attribute_name1
|
||||
column :bar, :attribute_name2
|
||||
column :foo, :name1
|
||||
column :bar, :name2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,11 +4,11 @@ describe EqualityPredicate do
|
|||
before do
|
||||
@relation1 = TableRelation.new(:foo)
|
||||
@relation2 = TableRelation.new(:bar)
|
||||
@attribute1 = Attribute.new(@relation1, :attribute_name)
|
||||
@attribute2 = Attribute.new(@relation2, :attribute_name)
|
||||
@attribute1 = Attribute.new(@relation1, :name)
|
||||
@attribute2 = Attribute.new(@relation2, :name)
|
||||
end
|
||||
|
||||
describe EqualityPredicate, '==' do
|
||||
describe '==' do
|
||||
it "obtains if attribute1 and attribute2 are identical" do
|
||||
EqualityPredicate.new(@attribute1, @attribute2).should == EqualityPredicate.new(@attribute1, @attribute2)
|
||||
EqualityPredicate.new(@attribute1, @attribute2).should_not == EqualityPredicate.new(@attribute1, @attribute1)
|
||||
|
|
|
@ -6,24 +6,41 @@ describe Attribute do
|
|||
@relation2 = TableRelation.new(:bar)
|
||||
end
|
||||
|
||||
describe 'aliaz' do
|
||||
describe '#aliazz' do
|
||||
it "manufactures an aliased attributed" do
|
||||
pending
|
||||
end
|
||||
|
||||
it "should be renamed to #alias!" do
|
||||
pending
|
||||
@relation1.alias
|
||||
end
|
||||
end
|
||||
|
||||
describe '#qualified_name' do
|
||||
it "manufactures an attribute name prefixed with the relation's name" do
|
||||
@relation1[:id].qualified_name.should == 'foo.id'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#qualify' do
|
||||
it "manufactures an attribute aliased with that attributes qualified name" do
|
||||
@relation1[:id].qualify == @relation1[:id].qualify
|
||||
end
|
||||
end
|
||||
|
||||
describe '#eql?' do
|
||||
it "obtains if the relation and attribute name are identical" do
|
||||
Attribute.new(@relation1, :attribute_name).should be_eql(Attribute.new(@relation1, :attribute_name))
|
||||
Attribute.new(@relation1, :attribute_name).should_not be_eql(Attribute.new(@relation1, :another_attribute_name))
|
||||
Attribute.new(@relation1, :attribute_name).should_not be_eql(Attribute.new(@relation2, :attribute_name))
|
||||
Attribute.new(@relation1, :name).should be_eql(Attribute.new(@relation1, :name))
|
||||
Attribute.new(@relation1, :name).should_not be_eql(Attribute.new(@relation1, :another_name))
|
||||
Attribute.new(@relation1, :name).should_not be_eql(Attribute.new(@relation2, :name))
|
||||
end
|
||||
end
|
||||
|
||||
describe 'predications' do
|
||||
before do
|
||||
@attribute1 = Attribute.new(@relation1, :attribute_name)
|
||||
@attribute2 = Attribute.new(@relation2, :attribute_name)
|
||||
@attribute1 = Attribute.new(@relation1, :name)
|
||||
@attribute2 = Attribute.new(@relation2, :name)
|
||||
end
|
||||
|
||||
describe '==' do
|
||||
|
@ -63,11 +80,10 @@ describe Attribute do
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
describe '#to_sql' do
|
||||
it "manufactures a column" do
|
||||
Attribute.new(@relation1, :attribute_name, :alias).to_sql.should == SelectsBuilder.new do
|
||||
column :foo, :attribute_name, :alias
|
||||
Attribute.new(@relation1, :name, :alias).to_sql.should == SelectsBuilder.new do
|
||||
column :foo, :name, :alias
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,6 +16,13 @@ describe OrderRelation do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#qualify' do
|
||||
it "manufactures an order relation with qualified attributes and qualified relation" do
|
||||
OrderRelation.new(@relation1, @attribute1).qualify. \
|
||||
should == OrderRelation.new(@relation1.qualify, @attribute1.qualify)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_sql' do
|
||||
it "manufactures sql with an order clause" do
|
||||
OrderRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do
|
||||
|
|
|
@ -16,6 +16,13 @@ describe ProjectionRelation do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#qualify' do
|
||||
it "manufactures a projection relation with qualified attributes and qualified relation" do
|
||||
ProjectionRelation.new(@relation1, @attribute1).qualify. \
|
||||
should == ProjectionRelation.new(@relation1.qualify, @attribute1.qualify)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_sql' do
|
||||
it "manufactures sql with a limited select clause" do
|
||||
ProjectionRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do
|
||||
|
|
|
@ -16,6 +16,12 @@ describe RangeRelation do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#qualify' do
|
||||
it "manufactures a range relation with a qualified relation and a qualified range" do
|
||||
pending
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_sql' do
|
||||
it "manufactures sql with limit and offset" do
|
||||
range_size = @range2.last - @range2.first + 1
|
||||
|
|
|
@ -8,21 +8,21 @@ describe Relation do
|
|||
@attribute2 = Attribute.new(@relation1, :name)
|
||||
end
|
||||
|
||||
describe Relation, 'joins' do
|
||||
describe Relation, '<=>' do
|
||||
describe 'joins' do
|
||||
describe '<=>' do
|
||||
it "manufactures an inner join operation between those two relations" do
|
||||
(@relation1 <=> @relation2).should == InnerJoinOperation.new(@relation1, @relation2)
|
||||
end
|
||||
end
|
||||
|
||||
describe Relation, '<<' do
|
||||
describe '<<' do
|
||||
it "manufactures a left outer join operation between those two relations" do
|
||||
(@relation1 << @relation2).should == LeftOuterJoinOperation.new(@relation1, @relation2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Relation, '[]' do
|
||||
describe '[]' do
|
||||
it "manufactures an attribute when given a symbol" do
|
||||
@relation1[:id].should be_eql(Attribute.new(@relation1, :id))
|
||||
end
|
||||
|
@ -32,13 +32,13 @@ describe Relation do
|
|||
end
|
||||
end
|
||||
|
||||
describe Relation, '#include?' do
|
||||
describe '#include?' do
|
||||
it "manufactures an inclusion predicate" do
|
||||
@relation1.include?(@attribute1).should == RelationInclusionPredicate.new(@attribute1, @relation1)
|
||||
end
|
||||
end
|
||||
|
||||
describe Relation, '#project' do
|
||||
describe '#project' do
|
||||
it "collapses identical projections" do
|
||||
pending
|
||||
end
|
||||
|
@ -48,13 +48,13 @@ describe Relation do
|
|||
end
|
||||
end
|
||||
|
||||
describe Relation, '#rename' do
|
||||
describe '#rename' do
|
||||
it "manufactures a rename relation" do
|
||||
@relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1, :foo)
|
||||
@relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1 => :foo)
|
||||
end
|
||||
end
|
||||
|
||||
describe Relation, '#select' do
|
||||
describe '#select' do
|
||||
before do
|
||||
@predicate = EqualityPredicate.new(@attribute1, @attribute2)
|
||||
end
|
||||
|
@ -64,7 +64,7 @@ describe Relation do
|
|||
end
|
||||
end
|
||||
|
||||
describe Relation, 'order' do
|
||||
describe 'order' do
|
||||
it "manufactures an order relation" do
|
||||
@relation1.order(@attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2)
|
||||
end
|
||||
|
|
68
spec/relations/rename_relation_spec.rb
Normal file
68
spec/relations/rename_relation_spec.rb
Normal file
|
@ -0,0 +1,68 @@
|
|||
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
||||
|
||||
describe RenameRelation do
|
||||
before do
|
||||
@relation = TableRelation.new(:foo)
|
||||
@renamed_relation = RenameRelation.new(@relation, @relation[:id] => :schmid)
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it "manufactures nested rename relations if multiple renames are provided" do
|
||||
RenameRelation.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \
|
||||
should == RenameRelation.new(RenameRelation.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty)
|
||||
end
|
||||
|
||||
it "make this test less brittle wrt/ hash order" do
|
||||
pending
|
||||
end
|
||||
|
||||
it "raises an exception if the alias provided is already used" do
|
||||
pending
|
||||
end
|
||||
end
|
||||
|
||||
describe '==' do
|
||||
it "obtains if the relation, attribute, and alias are identical" do
|
||||
pending
|
||||
end
|
||||
end
|
||||
|
||||
describe '#attributes' do
|
||||
it "manufactures a list of attributes with the renamed attribute aliased" do
|
||||
RenameRelation.new(@relation, @relation[:id] => :schmid).attributes.should ==
|
||||
(@relation.attributes - [@relation[:id]]) + [@relation[:id].aliazz(:schmid)]
|
||||
end
|
||||
end
|
||||
|
||||
describe '[]' do
|
||||
it 'indexes attributes by alias' do
|
||||
@renamed_relation[:id].should be_nil
|
||||
@renamed_relation[:schmid].should == @relation[:id]
|
||||
end
|
||||
end
|
||||
|
||||
describe '#schmattribute' do
|
||||
it "should be renamed" do
|
||||
pending
|
||||
end
|
||||
end
|
||||
|
||||
describe '#qualify' do
|
||||
it "manufactures a rename relation with an identical attribute and alias, but with a qualified relation" do
|
||||
RenameRelation.new(@relation, @relation[:id] => :schmid).qualify. \
|
||||
should == RenameRelation.new(@relation.qualify, @relation[:id].qualify => :schmid)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_sql' do
|
||||
it 'manufactures sql aliasing the attribute' do
|
||||
@renamed_relation.to_sql.to_s.should == SelectBuilder.new do
|
||||
select do
|
||||
column :foo, :name
|
||||
column :foo, :id, :schmid
|
||||
end
|
||||
from :foo
|
||||
end.to_s
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,6 +26,13 @@ describe SelectionRelation do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#qualify' do
|
||||
it "manufactures a selection relation with qualified predicates and qualified relation" do
|
||||
SelectionRelation.new(@relation1, @predicate1).qualify. \
|
||||
should == SelectionRelation.new(@relation1.qualify, @predicate1.qualify)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_sql' do
|
||||
it "manufactures sql with where clause conditions" do
|
||||
SelectionRelation.new(@relation1, @predicate1).to_sql.to_s.should == SelectBuilder.new do
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
||||
|
||||
describe TableRelation do
|
||||
before do
|
||||
@relation = TableRelation.new(:users)
|
||||
end
|
||||
|
||||
describe '#to_sql' do
|
||||
it "returns a simple SELECT query" do
|
||||
TableRelation.new(:users).to_sql.should == SelectBuilder.new do |s|
|
||||
@relation.to_sql.should == SelectBuilder.new do |s|
|
||||
select do
|
||||
column :users, :name
|
||||
column :users, :id
|
||||
|
@ -18,4 +22,12 @@ describe TableRelation do
|
|||
pending
|
||||
end
|
||||
end
|
||||
|
||||
describe '#qualify' do
|
||||
it 'manufactures a rename relation with all attribute names qualified' do
|
||||
@relation.qualify.should == RenameRelation.new(
|
||||
RenameRelation.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -14,6 +14,14 @@ ActiveRecord::Base.configurations = {
|
|||
}
|
||||
ActiveRecord::Base.establish_connection 'sql_algebra_test'
|
||||
|
||||
class Hash
|
||||
def shift
|
||||
returning to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash }.shift do |key, value|
|
||||
delete(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Runner.configure do |config|
|
||||
config.include(BeLikeMatcher)
|
||||
end
|
Loading…
Reference in a new issue