ranked-model 0.4.0 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,17 +5,31 @@ describe Duck do
5
5
  before {
6
6
  200.times do |i|
7
7
  Duck.create \
8
- :name => "Duck #{i}"
8
+ :name => "Duck #{i + 1}"
9
9
  end
10
10
  }
11
11
 
12
+ describe "a large number of records" do
13
+ before { @ducks = Duck.all }
14
+
15
+ describe "the last two ducks' rows' difference" do
16
+ subject { @ducks[-1].row - @ducks[-2].row }
17
+ it { is_expected.not_to be_between(-1, 1) }
18
+ end
19
+
20
+ describe "the second to last two ducks' rows' difference" do
21
+ subject { @ducks[-2].row - @ducks[-3].row }
22
+ it { is_expected.not_to be_between(-1, 1) }
23
+ end
24
+ end
25
+
12
26
  describe "setting and fetching by position" do
13
27
 
14
28
  describe '137' do
15
29
 
16
30
  before {
17
31
  @last = Duck.last
18
- @last.update_attribute :row_position, 137
32
+ @last.update :row_position => 137
19
33
  }
20
34
 
21
35
  subject { Duck.ranker(:row).with(Duck.new).current_at_position(137).instance }
@@ -28,7 +42,7 @@ describe Duck do
28
42
 
29
43
  before {
30
44
  @last = Duck.last
31
- @last.update_attribute :row_position, 2
45
+ @last.update :row_position => 2
32
46
  }
33
47
 
34
48
  subject { Duck.ranker(:row).with(Duck.new).current_at_position(2).instance }
@@ -41,7 +55,7 @@ describe Duck do
41
55
 
42
56
  before {
43
57
  @last = Duck.last
44
- @last.update_attribute :row_position, :last
58
+ @last.update :row_position => :last
45
59
  }
46
60
 
47
61
  subject { Duck.rank(:row).last }
@@ -54,7 +68,7 @@ describe Duck do
54
68
 
55
69
  before {
56
70
  @last = Duck.last
57
- @last.update_attribute :row_position, :first
71
+ @last.update :row_position => :first
58
72
  }
59
73
 
60
74
  subject { Duck.rank(:row).first }
@@ -73,15 +87,15 @@ describe Duck do
73
87
  @first = Duck.first
74
88
  @second = Duck.offset(1).first
75
89
  @ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_in([@first.id, @second.id])).collect {|d| d.id }
76
- @first.update_attribute :row, RankedModel::MAX_RANK_VALUE
77
- @second.update_attribute :row, RankedModel::MAX_RANK_VALUE
90
+ @first.update :row => RankedModel::MAX_RANK_VALUE
91
+ @second.update :row => RankedModel::MAX_RANK_VALUE
78
92
  }
79
93
 
80
94
  context {
81
95
 
82
96
  subject { Duck.rank(:row).collect {|d| d.id } }
83
97
 
84
- it { should == (@ordered[0..-2] + [@ordered[-1], @first.id, @second.id]) }
98
+ it { is_expected.to eq(@ordered[0..-2] + [@ordered[-1], @first.id, @second.id]) }
85
99
 
86
100
  }
87
101
 
@@ -91,24 +105,24 @@ describe Duck do
91
105
 
92
106
  before {
93
107
  Duck.first(50).each_with_index do |d, index|
94
- d.update_attributes :age => index % 10, :pond => "Pond #{index / 10}"
108
+ d.update :age => index % 10, :pond => "Pond #{index / 10}"
95
109
  end
96
- @duck_11 = Duck.offset(10).first
97
- @duck_12 = Duck.offset(11).first
110
+ @duck_11 = Duck.where(:pond => 'Pond 1').rank(:age).first
111
+ @duck_12 = Duck.where(:pond => 'Pond 1').rank(:age).second
98
112
  @ordered = Duck.where(:pond => 'Pond 1').rank(:age).where(Duck.arel_table[:id].not_in([@duck_11.id, @duck_12.id])).collect {|d| d.id }
99
- @duck_11.update_attribute :age, RankedModel::MAX_RANK_VALUE
100
- @duck_12.update_attribute :age, RankedModel::MAX_RANK_VALUE
113
+ @duck_11.update :age => RankedModel::MAX_RANK_VALUE
114
+ @duck_12.update :age => RankedModel::MAX_RANK_VALUE
101
115
  }
102
116
 
103
117
  context {
104
118
  subject { Duck.where(:pond => 'Pond 1').rank(:age).collect {|d| d.id } }
105
119
 
106
- it { should == (@ordered[0..-2] + [@ordered[-1], @duck_11.id, @duck_12.id]) }
120
+ it { is_expected.to eq(@ordered[0..-2] + [@ordered[-1], @duck_11.id, @duck_12.id]) }
107
121
  }
108
122
 
109
123
  context {
110
124
  subject { Duck.first.age }
111
- it { should == 0}
125
+ it { is_expected.to eq(0)}
112
126
  }
113
127
 
114
128
  end
@@ -119,15 +133,15 @@ describe Duck do
119
133
  @first = Duck.first
120
134
  @second = Duck.offset(1).first
121
135
  @ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_in([@first.id, @second.id])).collect {|d| d.id }
122
- @first.update_attribute :row, RankedModel::MIN_RANK_VALUE
123
- @second.update_attribute :row, RankedModel::MIN_RANK_VALUE
136
+ @first.update :row => RankedModel::MIN_RANK_VALUE
137
+ @second.update :row => RankedModel::MIN_RANK_VALUE
124
138
  }
125
139
 
126
140
  context {
127
141
 
128
142
  subject { Duck.rank(:row).collect {|d| d.id } }
129
143
 
130
- it { should == ([@second.id, @first.id] + @ordered) }
144
+ it { is_expected.to eq([@second.id, @first.id] + @ordered) }
131
145
 
132
146
  }
133
147
 
@@ -135,32 +149,30 @@ describe Duck do
135
149
 
136
150
  describe "with no more gaps" do
137
151
 
138
- before {
139
- @first = Duck.first
140
- @second = Duck.where(:row => RankedModel::MAX_RANK_VALUE).first || Duck.offset(1).first
141
- @third = Duck.offset(2).first
142
- @fourth = Duck.offset(4).first
152
+ before do
153
+ @first = Duck.rank(:row).first
154
+ @second = Duck.rank(:row).offset(1).first
155
+ @third = Duck.rank(:row).offset(2).first
156
+ @fourth = Duck.rank(:row).offset(3).first
143
157
  @lower = Duck.rank(:row).
144
158
  where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
145
159
  where(Duck.arel_table[:row].lt(RankedModel::MAX_RANK_VALUE / 2)).
146
- collect {|d| d.id }
160
+ pluck(:id)
147
161
  @upper = Duck.rank(:row).
148
162
  where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
149
163
  where(Duck.arel_table[:row].gteq(RankedModel::MAX_RANK_VALUE / 2)).
150
- collect {|d| d.id }
151
- @first.update_attribute :row, RankedModel::MIN_RANK_VALUE
152
- @second.update_attribute :row, RankedModel::MAX_RANK_VALUE
153
- @third.update_attribute :row, (RankedModel::MAX_RANK_VALUE / 2)
154
- @fourth.update_attribute :row, @third.row
155
- }
156
-
157
- context {
158
-
159
- subject { Duck.rank(:row).collect {|d| d.id } }
160
-
161
- it { should == ([@first.id] + @lower + [@fourth.id, @third.id] + @upper + [@second.id]) }
162
-
163
- }
164
+ pluck(:id)
165
+ @first.update(row: RankedModel::MIN_RANK_VALUE)
166
+ @second.update(row: RankedModel::MAX_RANK_VALUE)
167
+ @third.update(row: (RankedModel::MAX_RANK_VALUE / 2))
168
+ @fourth.update(row: @third.row)
169
+ end
170
+
171
+ it 'works correctly' do
172
+ result = Duck.rank(:row).pluck(:id)
173
+ expected = [@first.id, *@lower, @fourth.id, @third.id, *@upper, @second.id]
174
+ expect(result).to eq(expected)
175
+ end
164
176
 
165
177
  end
166
178
 
@@ -23,3 +23,14 @@ describe WrongFieldDuck do
23
23
  end
24
24
 
25
25
  end
26
+
27
+ describe ReallyWrongFieldDuck do
28
+
29
+ it "should raise an error because of a specific unknown field" do
30
+
31
+ expect {
32
+ ReallyWrongFieldDuck.create(:name => 'Quicky', :pond => 'Shin')
33
+ }.to raise_error(RankedModel::InvalidField, 'No field called "non_existant_field" found in model')
34
+ end
35
+
36
+ end
@@ -10,7 +10,7 @@ describe Ego do
10
10
  }
11
11
  @egos.each { |name, ego|
12
12
  ego.reload
13
- ego.update_attribute :size_position, 0
13
+ ego.update :size_position => 0
14
14
  ego.save!
15
15
  }
16
16
  @egos.each {|name, ego| ego.reload }
@@ -19,8 +19,8 @@ describe Ego do
19
19
  describe "sorting on size alternative primary key" do
20
20
 
21
21
  before {
22
- @egos[:nick].update_attribute :size_position, 0
23
- @egos[:sally].update_attribute :size_position, 2
22
+ @egos[:nick].update :size_position => 0
23
+ @egos[:sally].update :size_position => 2
24
24
  }
25
25
 
26
26
  subject { Ego.rank(:size).to_a }
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Number do
4
+
5
+ before {
6
+ 200.times do |i|
7
+ Number.create :value => i
8
+ end
9
+ }
10
+
11
+ describe "a rearrangement with keyword column name" do
12
+
13
+ before {
14
+ @first = Number.first
15
+ @second = Number.offset(1).first
16
+ @ordered = Number.rank(:order).where(Number.arel_table[:id].not_in([@first.id, @second.id])).collect {|d| d.id }
17
+ @first.update :order => RankedModel::MAX_RANK_VALUE
18
+ @second.update :order => RankedModel::MAX_RANK_VALUE
19
+ }
20
+
21
+ context {
22
+
23
+ subject { Number.rank(:order).collect {|d| d.id } }
24
+
25
+ it { should == (@ordered[0..-2] + [@ordered[-1], @first.id, @second.id]) }
26
+
27
+ }
28
+
29
+ end
30
+
31
+ describe "getting a position with keyword column name" do
32
+
33
+ subject { Number.first }
34
+
35
+ its(:order_rank) { should == 0 }
36
+
37
+ end
38
+
39
+ end
@@ -16,7 +16,7 @@ describe Player do
16
16
 
17
17
  describe "setting the position of a record that already exists" do
18
18
  it "sets the rank without error" do
19
- expect{@players[:bob].update_attributes! :score_position => 1}.to_not raise_error
19
+ expect{@players[:bob].update! :score_position => 1}.to_not raise_error
20
20
  end
21
21
  end
22
22
  end
@@ -62,3 +62,21 @@ describe RankedModel::Ranker, 'unless as Proc' do
62
62
  }
63
63
  end
64
64
  end
65
+
66
+ describe RankedModel::Ranker, 'unless as lambda' do
67
+ context 'returns true' do
68
+ subject { RankedModel::Ranker.new(:overview, unless: ->(_) { true }).with(Class.new) }
69
+ its(:handle_ranking) { should == nil }
70
+ end
71
+
72
+ context 'returns false' do
73
+ subject { RankedModel::Ranker.new(:overview, unless: ->(_) { false }).with(Class.new) }
74
+
75
+ it {
76
+ subject.expects(:update_index_from_position).once
77
+ subject.expects(:assure_unique_position).once
78
+
79
+ subject.handle_ranking
80
+ }
81
+ end
82
+ end
@@ -2,6 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  describe RankedModel do
4
4
 
5
- it { should define_constant(:VERSION) }
5
+ it { is_expected.to define_constant(:VERSION) }
6
6
 
7
7
  end
data/spec/spec_helper.rb CHANGED
@@ -1,13 +1,18 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
+ require 'rspec/its'
3
4
 
4
5
  require 'ranked-model'
6
+ require 'pry'
5
7
 
6
8
  Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each {|f| require f}
7
9
 
8
10
  # After the DB connection is setup
9
11
  require 'database_cleaner'
10
12
 
13
+ # Uncomment this to see Active Record logging for tests
14
+ # ActiveRecord::Base.logger = Logger.new(STDOUT)
15
+
11
16
  RSpec.configure do |config|
12
17
  config.mock_with :mocha
13
18
 
@@ -24,6 +29,8 @@ RSpec.configure do |config|
24
29
  DatabaseCleaner.clean
25
30
  end
26
31
 
32
+ config.order = :random
33
+ Kernel.srand config.seed
27
34
  end
28
35
 
29
36
  RSpec::Matchers.define :define_constant do |expected|
@@ -12,7 +12,7 @@ describe Element do
12
12
  }
13
13
  @elements.each { |name, element|
14
14
  element.reload
15
- element.update_attribute :combination_order_position, 0
15
+ element.update :combination_order_position => 0
16
16
  }
17
17
  @elements.each {|name, element| element.reload }
18
18
  }
@@ -20,9 +20,9 @@ describe Element do
20
20
  describe "rebalancing on an STI class should not affect the other class" do
21
21
 
22
22
  before {
23
- @elements[:helium].update_attribute :combination_order_position, :first
24
- @elements[:xenon].update_attribute :combination_order_position, :first
25
- @elements[:argon].update_attribute :combination_order_position, :last
23
+ @elements[:helium].update :combination_order_position => :first
24
+ @elements[:xenon].update :combination_order_position => :first
25
+ @elements[:argon].update :combination_order_position => :last
26
26
 
27
27
  TransitionMetal.ranker(:combination_order).with(@elements[:chromium]).instance_eval { rebalance_ranks }
28
28
  }
@@ -40,16 +40,16 @@ describe Element do
40
40
  describe "setting positions on STI classes" do
41
41
 
42
42
  before {
43
- @elements[:helium].update_attribute :combination_order_position, :first
44
- @elements[:xenon].update_attribute :combination_order_position, :first
45
- @elements[:argon].update_attribute :combination_order_position, :first
46
-
47
- @elements[:chromium].update_attribute :combination_order_position, 1
48
- @elements[:manganese].update_attribute :combination_order_position, 1
49
- @elements[:manganese].update_attribute :combination_order_position, 0
50
- @elements[:chromium].update_attribute :combination_order_position, 0
51
- @elements[:manganese].update_attribute :combination_order_position, 0
52
- @elements[:chromium].update_attribute :combination_order_position, 0
43
+ @elements[:helium].update :combination_order_position => :first
44
+ @elements[:xenon].update :combination_order_position => :first
45
+ @elements[:argon].update :combination_order_position => :first
46
+
47
+ @elements[:chromium].update :combination_order_position => 1
48
+ @elements[:manganese].update :combination_order_position => 1
49
+ @elements[:manganese].update :combination_order_position => 0
50
+ @elements[:chromium].update :combination_order_position => 0
51
+ @elements[:manganese].update :combination_order_position => 0
52
+ @elements[:chromium].update :combination_order_position => 0
53
53
  }
54
54
 
55
55
  describe "NobleGas" do
@@ -81,16 +81,16 @@ describe Element do
81
81
  describe "setting positions on STI classes" do
82
82
 
83
83
  before {
84
- @elements[:helium].update_attribute :combination_order_position, :first
85
- @elements[:xenon].update_attribute :combination_order_position, :first
86
- @elements[:argon].update_attribute :combination_order_position, :first
87
-
88
- @elements[:chromium].update_attribute :combination_order_position, 1
89
- @elements[:manganese].update_attribute :combination_order_position, 1
90
- @elements[:manganese].update_attribute :combination_order_position, 0
91
- @elements[:chromium].update_attribute :combination_order_position, 0
92
- @elements[:manganese].update_attribute :combination_order_position, 0
93
- @elements[:chromium].update_attribute :combination_order_position, 0
84
+ @elements[:helium].update :combination_order_position => :first
85
+ @elements[:xenon].update :combination_order_position => :first
86
+ @elements[:argon].update :combination_order_position => :first
87
+
88
+ @elements[:chromium].update :combination_order_position => 1
89
+ @elements[:manganese].update :combination_order_position => 1
90
+ @elements[:manganese].update :combination_order_position => 0
91
+ @elements[:chromium].update :combination_order_position => 0
92
+ @elements[:manganese].update :combination_order_position => 0
93
+ @elements[:chromium].update :combination_order_position => 0
94
94
  }
95
95
 
96
96
  describe "NobleGas" do
@@ -12,7 +12,7 @@ describe Vehicle do
12
12
  }
13
13
  @vehicles.each { |name, vehicle|
14
14
  vehicle.reload
15
- vehicle.update_attribute :parking_order_position, 0
15
+ vehicle.update :parking_order_position => 0
16
16
  }
17
17
  @vehicles.each {|name, vehicle| vehicle.reload }
18
18
  }
@@ -20,8 +20,8 @@ describe Vehicle do
20
20
  describe "ranking by STI parent" do
21
21
 
22
22
  before {
23
- @vehicles[:volvo].update_attribute :parking_order_position, :first
24
- @vehicles[:ford].update_attribute :parking_order_position, :first
23
+ @vehicles[:volvo].update :parking_order_position => :first
24
+ @vehicles[:ford].update :parking_order_position => :first
25
25
  }
26
26
 
27
27
  describe "Vehicle" do
@@ -43,7 +43,7 @@ describe Vehicle do
43
43
  describe "Vehicle" do
44
44
 
45
45
  it "should have one ranker object" do
46
- Vehicle.rankers.count.should == 1
46
+ expect(Vehicle.rankers.count).to eq(1)
47
47
  end
48
48
 
49
49
  subject { Vehicle.rankers.first }
@@ -57,7 +57,7 @@ describe Vehicle do
57
57
  describe "MotorBike" do
58
58
 
59
59
  it "should have one ranker object" do
60
- MotorBike.rankers.count.should == 1
60
+ expect(MotorBike.rankers.count).to eq(1)
61
61
  end
62
62
 
63
63
  subject { MotorBike.rankers.first }
@@ -72,4 +72,4 @@ describe Vehicle do
72
72
 
73
73
  end
74
74
 
75
- end
75
+ end
@@ -1,13 +1,13 @@
1
1
  require 'active_record'
2
2
  require 'logger'
3
3
 
4
- ROOT = File.join(File.dirname(__FILE__), '..')
5
-
6
- DB_CONFIG = "test" + (ENV['DB'] ? "_#{ENV['DB'].downcase}" : '')
4
+ unless ENV['DB']
5
+ ENV['DB'] = 'sqlite'
6
+ end
7
7
 
8
8
  ActiveRecord::Base.logger = Logger.new('tmp/ar_debug.log')
9
9
  ActiveRecord::Base.configurations = YAML::load(IO.read('spec/support/database.yml'))
10
- ActiveRecord::Base.establish_connection(DB_CONFIG)
10
+ ActiveRecord::Base.establish_connection(ENV['DB'].to_sym)
11
11
 
12
12
  ActiveRecord::Schema.define :version => 0 do
13
13
  create_table :ducks, :force => true do |t|
@@ -21,6 +21,8 @@ ActiveRecord::Schema.define :version => 0 do
21
21
  t.string :pond
22
22
  end
23
23
 
24
+ add_index :ducks, [:landing_order, :lake_id, :flock_id], unique: true
25
+
24
26
  create_table :wrong_scope_ducks, :force => true do |t|
25
27
  t.string :name
26
28
  t.integer :size
@@ -33,6 +35,12 @@ ActiveRecord::Schema.define :version => 0 do
33
35
  t.string :pond
34
36
  end
35
37
 
38
+ create_table :column_default_ducks, :force => true do |t|
39
+ t.string :name
40
+ t.integer :size, default: 0
41
+ t.string :pond
42
+ end
43
+
36
44
  create_table :elements, :force => true do |t|
37
45
  t.string :symbol
38
46
  t.string :type
@@ -56,6 +64,11 @@ ActiveRecord::Schema.define :version => 0 do
56
64
  t.string :city
57
65
  t.integer :score
58
66
  end
67
+
68
+ create_table :numbers, :force => true do |t|
69
+ t.float :value
70
+ t.integer :order
71
+ end
59
72
  end
60
73
 
61
74
  class Duck < ActiveRecord::Base
@@ -85,7 +98,12 @@ class WrongFieldDuck < ActiveRecord::Base
85
98
 
86
99
  include RankedModel
87
100
  ranks :age, :with_same => :non_existant_field
101
+ end
88
102
 
103
+ class ReallyWrongFieldDuck < ActiveRecord::Base
104
+ self.table_name = :wrong_field_ducks
105
+ include RankedModel
106
+ ranks :age, :with_same => [:name, :non_existant_field]
89
107
  end
90
108
 
91
109
  # Example for STI, ranking within each child class
@@ -132,7 +150,7 @@ class MotorBike < Vehicle
132
150
  end
133
151
 
134
152
  class Ego < ActiveRecord::Base
135
- primary_key = :alternative_to_id
153
+ self.primary_key = :alternative_to_id
136
154
  include RankedModel
137
155
  ranks :size
138
156
  end
@@ -140,3 +158,8 @@ end
140
158
  class Player < ActiveRecord::Base
141
159
  # don't add rank yet, do it in the specs
142
160
  end
161
+
162
+ class Number < ActiveRecord::Base
163
+ include RankedModel
164
+ ranks :order
165
+ end