ranked-model 0.4.0 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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