ranked-model 0.0.1 → 0.0.2
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.
- data/.gitignore +2 -0
- data/Readme.mkd +1 -1
- data/lib/ranked-model.rb +2 -1
- data/lib/ranked-model/ranker.rb +120 -25
- data/lib/ranked-model/version.rb +1 -1
- data/ranked-model.gemspec +1 -1
- data/spec/duck-model/duck_spec.rb +149 -3
- data/spec/duck-model/lots_of_ducks_spec.rb +117 -0
- data/spec/duck-model/wrong_ducks_spec.rb +25 -0
- data/spec/support/active_record.rb +28 -0
- metadata +9 -6
- data/Gemfile.lock +0 -81
data/Readme.mkd
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
**ranked-model** is a modern row sorting library built for Rails 3. It uses ARel
|
1
|
+
**ranked-model** is a modern row sorting library built for Rails 3. It uses ARel aggressively and is better optimized than most other libraries.
|
2
2
|
|
3
3
|
Installation
|
4
4
|
------------
|
data/lib/ranked-model.rb
CHANGED
data/lib/ranked-model/ranker.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module RankedModel
|
2
2
|
|
3
|
+
class InvalidScope < StandardError; end
|
4
|
+
class InvalidField < StandardError; end
|
5
|
+
|
3
6
|
class Ranker
|
4
7
|
attr_accessor :name, :column, :scope, :with_same
|
5
8
|
|
@@ -22,12 +25,24 @@ module RankedModel
|
|
22
25
|
def initialize ranker, instance
|
23
26
|
self.ranker = ranker
|
24
27
|
self.instance = instance
|
28
|
+
|
29
|
+
validate_ranker_for_instance!
|
25
30
|
end
|
26
31
|
|
32
|
+
def validate_ranker_for_instance!
|
33
|
+
if ranker.scope && !instance.class.respond_to?(ranker.scope)
|
34
|
+
raise RankedModel::InvalidScope, %Q{No scope called "#{ranker.scope}" found in model}
|
35
|
+
end
|
36
|
+
|
37
|
+
if ranker.with_same && !instance.respond_to?(ranker.with_same)
|
38
|
+
raise RankedModel::InvalidField, %Q{No field called "#{ranker.with_same}" found in model}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
27
42
|
def handle_ranking
|
28
43
|
update_index_from_position
|
29
44
|
assure_unique_position
|
30
|
-
end
|
45
|
+
end
|
31
46
|
|
32
47
|
def update_rank! value
|
33
48
|
# Bypass callbacks
|
@@ -43,6 +58,12 @@ module RankedModel
|
|
43
58
|
instance.send "#{ranker.column}"
|
44
59
|
end
|
45
60
|
|
61
|
+
def current_at_position _pos
|
62
|
+
if (ordered_instance = finder.offset(_pos).first)
|
63
|
+
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
46
67
|
private
|
47
68
|
|
48
69
|
def position_at value
|
@@ -65,25 +86,30 @@ module RankedModel
|
|
65
86
|
def update_index_from_position
|
66
87
|
case position
|
67
88
|
when :first
|
68
|
-
if
|
69
|
-
rank_at(
|
89
|
+
if current_first && current_first.rank
|
90
|
+
rank_at( ( ( RankedModel::MIN_RANK_VALUE - current_first.rank ).to_f / 2 ).ceil + current_first.rank)
|
70
91
|
else
|
71
|
-
|
92
|
+
position_at :middle
|
72
93
|
end
|
73
94
|
when :last
|
74
|
-
if
|
75
|
-
rank_at( ( RankedModel::MAX_RANK_VALUE
|
95
|
+
if current_last && current_last.rank
|
96
|
+
rank_at( ( ( RankedModel::MAX_RANK_VALUE - current_last.rank ).to_f / 2 ).ceil + current_last.rank )
|
76
97
|
else
|
77
|
-
|
98
|
+
position_at :middle
|
78
99
|
end
|
100
|
+
when :middle
|
101
|
+
rank_at( ( ( RankedModel::MAX_RANK_VALUE - RankedModel::MIN_RANK_VALUE ).to_f / 2 ).ceil + RankedModel::MIN_RANK_VALUE )
|
79
102
|
when String
|
80
103
|
position_at position.to_i
|
81
104
|
when 0
|
82
105
|
position_at :first
|
83
106
|
when Integer
|
84
|
-
|
85
|
-
|
86
|
-
|
107
|
+
neighbors = neighbors_at_position(position)
|
108
|
+
min = (neighbors[:lower] ? neighbors[:lower].rank : RankedModel::MIN_RANK_VALUE)
|
109
|
+
max = (neighbors[:upper] ? neighbors[:upper].rank : RankedModel::MAX_RANK_VALUE)
|
110
|
+
rank_at( ( ( max - min ).to_f / 2 ).ceil + min )
|
111
|
+
when NilClass
|
112
|
+
if !rank
|
87
113
|
position_at :last
|
88
114
|
end
|
89
115
|
end
|
@@ -92,24 +118,38 @@ module RankedModel
|
|
92
118
|
def assure_unique_position
|
93
119
|
if ( new_record? || rank_changed? )
|
94
120
|
unless rank
|
95
|
-
rank_at RankedModel::MAX_RANK_VALUE
|
121
|
+
rank_at( RankedModel::MAX_RANK_VALUE )
|
96
122
|
end
|
97
123
|
|
98
|
-
if (rank > RankedModel::MAX_RANK_VALUE) || (
|
99
|
-
|
100
|
-
rankable.rank == rank
|
101
|
-
end)
|
102
|
-
rebalance_ranks
|
124
|
+
if (rank > RankedModel::MAX_RANK_VALUE) || current_at_rank(rank)
|
125
|
+
rearrange_ranks
|
103
126
|
end
|
104
127
|
end
|
105
128
|
end
|
106
|
-
|
129
|
+
|
130
|
+
def rearrange_ranks
|
131
|
+
if current_last.rank < (RankedModel::MAX_RANK_VALUE - 1) && rank < current_last.rank
|
132
|
+
instance.class.
|
133
|
+
where( instance.class.arel_table[:id].not_eq(instance.id) ).
|
134
|
+
where( instance.class.arel_table[ranker.column].gteq(rank) ).
|
135
|
+
update_all( "#{ranker.column} = #{ranker.column} + 1" )
|
136
|
+
elsif current_first.rank > RankedModel::MIN_RANK_VALUE && rank > current_first.rank
|
137
|
+
instance.class.
|
138
|
+
where( instance.class.arel_table[:id].not_eq(instance.id) ).
|
139
|
+
where( instance.class.arel_table[ranker.column].lt(rank) ).
|
140
|
+
update_all( "#{ranker.column} = #{ranker.column} - 1" )
|
141
|
+
rank_at( rank - 1 )
|
142
|
+
else
|
143
|
+
rebalance_ranks
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
107
147
|
def rebalance_ranks
|
108
148
|
total = current_order.size + 2
|
109
149
|
has_set_self = false
|
110
150
|
total.times do |index|
|
111
151
|
next if index == 0 || index == total
|
112
|
-
rank_value = RankedModel::MAX_RANK_VALUE / total * index
|
152
|
+
rank_value = ((((RankedModel::MAX_RANK_VALUE - RankedModel::MIN_RANK_VALUE).to_f / total) * index ).ceil + RankedModel::MIN_RANK_VALUE)
|
113
153
|
index = index - 1
|
114
154
|
if has_set_self
|
115
155
|
index = index - 1
|
@@ -126,26 +166,81 @@ module RankedModel
|
|
126
166
|
end
|
127
167
|
end
|
128
168
|
|
129
|
-
def
|
130
|
-
@
|
131
|
-
|
169
|
+
def finder
|
170
|
+
@finder ||= begin
|
171
|
+
_finder = instance.class
|
132
172
|
if ranker.scope
|
133
|
-
|
173
|
+
_finder = _finder.send ranker.scope
|
134
174
|
end
|
135
175
|
if ranker.with_same
|
136
|
-
|
176
|
+
_finder = _finder.where \
|
137
177
|
instance.class.arel_table[ranker.with_same].eq(instance.attributes["#{ranker.with_same}"])
|
138
178
|
end
|
139
179
|
if !new_record?
|
140
|
-
|
180
|
+
_finder = _finder.where \
|
141
181
|
instance.class.arel_table[:id].not_eq(instance.id)
|
142
182
|
end
|
143
|
-
|
183
|
+
_finder.order(instance.class.arel_table[ranker.column].asc).select([:id, ranker.column])
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def current_order
|
188
|
+
@current_order ||= begin
|
189
|
+
finder.collect { |ordered_instance|
|
144
190
|
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
145
191
|
}
|
146
192
|
end
|
147
193
|
end
|
148
194
|
|
195
|
+
def current_first
|
196
|
+
@current_first ||= begin
|
197
|
+
if (ordered_instance = finder.first)
|
198
|
+
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def current_last
|
204
|
+
@current_last ||= begin
|
205
|
+
if (ordered_instance = finder.
|
206
|
+
except( :order ).
|
207
|
+
order( instance.class.arel_table[ranker.column].desc ).
|
208
|
+
first)
|
209
|
+
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def current_at_rank _rank
|
215
|
+
if (ordered_instance = finder.
|
216
|
+
except( :order ).
|
217
|
+
where( ranker.column => _rank ).
|
218
|
+
first)
|
219
|
+
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def neighbors_at_position _pos
|
224
|
+
if _pos > 0
|
225
|
+
if (ordered_instances = finder.offset(_pos-1).limit(2).all)
|
226
|
+
if ordered_instances[1]
|
227
|
+
{ :lower => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[0] ),
|
228
|
+
:upper => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[1] ) }
|
229
|
+
elsif ordered_instances[0]
|
230
|
+
{ :lower => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[0] ) }
|
231
|
+
else
|
232
|
+
{ :lower => current_last }
|
233
|
+
end
|
234
|
+
end
|
235
|
+
else
|
236
|
+
if (ordered_instance = finder.first)
|
237
|
+
{ :upper => RankedModel::Ranker::Mapper.new( ranker, ordered_instance ) }
|
238
|
+
else
|
239
|
+
{}
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
149
244
|
end
|
150
245
|
|
151
246
|
end
|
data/lib/ranked-model/version.rb
CHANGED
data/ranked-model.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.email = ["matt.beale@madhatted.com"]
|
11
11
|
s.homepage = "https://github.com/harvesthq/ranked-model"
|
12
12
|
s.summary = %q{An acts_as_sortable replacement built for Rails 3}
|
13
|
-
s.description = %q{ranked-model is a modern row sorting library built for Rails 3. It uses ARel
|
13
|
+
s.description = %q{ranked-model is a modern row sorting library built for Rails 3. It uses ARel aggressively and is better optimized than most other libraries.}
|
14
14
|
|
15
15
|
s.add_dependency "activerecord", ">= 3.0.3"
|
16
16
|
s.add_development_dependency "rspec"
|
@@ -25,9 +25,9 @@ describe Duck do
|
|
25
25
|
}
|
26
26
|
@ducks.each { |name, duck|
|
27
27
|
duck.reload
|
28
|
-
duck.row_position
|
29
|
-
duck.size_position
|
30
|
-
duck.age_position
|
28
|
+
duck.update_attribute :row_position, 0
|
29
|
+
duck.update_attribute :size_position, 0
|
30
|
+
duck.update_attribute :age_position, 0
|
31
31
|
duck.save!
|
32
32
|
}
|
33
33
|
@ducks.each {|name, duck| duck.reload }
|
@@ -124,4 +124,150 @@ describe Duck do
|
|
124
124
|
|
125
125
|
end
|
126
126
|
|
127
|
+
describe "setting and fetching by positioning" do
|
128
|
+
|
129
|
+
describe "in the middle" do
|
130
|
+
|
131
|
+
before {
|
132
|
+
@ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_eq @ducks[:wingy].id).collect {|duck| duck.id }
|
133
|
+
@ducks[:wingy].update_attribute :row_position, 2
|
134
|
+
}
|
135
|
+
|
136
|
+
context {
|
137
|
+
|
138
|
+
subject { Duck.ranker(:row).with(Duck.new).current_at_position(2).instance }
|
139
|
+
|
140
|
+
its(:id) { should == @ducks[:wingy].id }
|
141
|
+
|
142
|
+
}
|
143
|
+
|
144
|
+
context {
|
145
|
+
|
146
|
+
subject { Duck.rank(:row).collect {|duck| duck.id } }
|
147
|
+
|
148
|
+
it { subject[0..1].should == @ordered[0..1] }
|
149
|
+
|
150
|
+
it { subject[3..subject.length].should == @ordered[2..@ordered.length] }
|
151
|
+
|
152
|
+
}
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "at the start" do
|
157
|
+
|
158
|
+
before {
|
159
|
+
@ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_eq @ducks[:wingy].id).collect {|duck| duck.id }
|
160
|
+
@ducks[:wingy].update_attribute :row_position, 0
|
161
|
+
}
|
162
|
+
|
163
|
+
context {
|
164
|
+
|
165
|
+
subject { Duck.ranker(:row).with(Duck.new).current_at_position(0).instance }
|
166
|
+
|
167
|
+
its(:id) { should == @ducks[:wingy].id }
|
168
|
+
|
169
|
+
}
|
170
|
+
|
171
|
+
context {
|
172
|
+
|
173
|
+
subject { Duck.ranker(:row).with(Duck.new).instance_eval { current_first }.instance }
|
174
|
+
|
175
|
+
its(:id) { should == @ducks[:wingy].id }
|
176
|
+
|
177
|
+
}
|
178
|
+
|
179
|
+
context {
|
180
|
+
|
181
|
+
subject { Duck.rank(:row).collect {|duck| duck.id } }
|
182
|
+
|
183
|
+
it { subject[1..subject.length].should == @ordered }
|
184
|
+
|
185
|
+
}
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "at the end" do
|
190
|
+
|
191
|
+
before {
|
192
|
+
@ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_eq @ducks[:wingy].id).collect {|duck| duck.id }
|
193
|
+
@ducks[:wingy].update_attribute :row_position, (@ducks.size - 1)
|
194
|
+
}
|
195
|
+
|
196
|
+
context {
|
197
|
+
|
198
|
+
subject { Duck.ranker(:row).with(Duck.new).current_at_position(@ducks.size - 1).instance }
|
199
|
+
|
200
|
+
its(:id) { should == @ducks[:wingy].id }
|
201
|
+
|
202
|
+
}
|
203
|
+
|
204
|
+
context {
|
205
|
+
|
206
|
+
subject { Duck.rank(:row).last }
|
207
|
+
|
208
|
+
its(:id) { should == @ducks[:wingy].id }
|
209
|
+
|
210
|
+
}
|
211
|
+
|
212
|
+
context {
|
213
|
+
|
214
|
+
subject { Duck.ranker(:row).with(Duck.new).instance_eval { current_last }.instance }
|
215
|
+
|
216
|
+
its(:id) { should == @ducks[:wingy].id }
|
217
|
+
|
218
|
+
}
|
219
|
+
|
220
|
+
context {
|
221
|
+
|
222
|
+
subject { Duck.rank(:row).collect {|duck| duck.id } }
|
223
|
+
|
224
|
+
it { subject[0..-2].should == @ordered }
|
225
|
+
|
226
|
+
}
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
describe "at the end with symbol" do
|
231
|
+
|
232
|
+
before {
|
233
|
+
@ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_eq @ducks[:wingy].id).collect {|duck| duck.id }
|
234
|
+
@ducks[:wingy].update_attribute :row_position, :last
|
235
|
+
}
|
236
|
+
|
237
|
+
context {
|
238
|
+
|
239
|
+
subject { Duck.ranker(:row).with(Duck.new).current_at_position(@ducks.size - 1).instance }
|
240
|
+
|
241
|
+
its(:id) { should == @ducks[:wingy].id }
|
242
|
+
|
243
|
+
}
|
244
|
+
|
245
|
+
context {
|
246
|
+
|
247
|
+
subject { Duck.rank(:row).last }
|
248
|
+
|
249
|
+
its(:id) { should == @ducks[:wingy].id }
|
250
|
+
|
251
|
+
}
|
252
|
+
|
253
|
+
context {
|
254
|
+
|
255
|
+
subject { Duck.ranker(:row).with(Duck.new).instance_eval { current_last }.instance }
|
256
|
+
|
257
|
+
its(:id) { should == @ducks[:wingy].id }
|
258
|
+
|
259
|
+
}
|
260
|
+
|
261
|
+
context {
|
262
|
+
|
263
|
+
subject { Duck.rank(:row).collect {|duck| duck.id } }
|
264
|
+
|
265
|
+
it { subject[0..-2].should == @ordered }
|
266
|
+
|
267
|
+
}
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
127
273
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Duck do
|
4
|
+
|
5
|
+
before {
|
6
|
+
200.times do |i|
|
7
|
+
Duck.create \
|
8
|
+
:name => "Duck #{i}"
|
9
|
+
end
|
10
|
+
}
|
11
|
+
|
12
|
+
describe "setting and fetching by position" do
|
13
|
+
|
14
|
+
describe '137' do
|
15
|
+
|
16
|
+
before {
|
17
|
+
@last = Duck.last
|
18
|
+
@last.update_attribute :row_position, 137
|
19
|
+
}
|
20
|
+
|
21
|
+
subject { Duck.ranker(:row).with(Duck.new).current_at_position(137).instance }
|
22
|
+
|
23
|
+
its(:id) { should == @last.id }
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '2' do
|
28
|
+
|
29
|
+
before {
|
30
|
+
@last = Duck.last
|
31
|
+
@last.update_attribute :row_position, 2
|
32
|
+
}
|
33
|
+
|
34
|
+
subject { Duck.ranker(:row).with(Duck.new).current_at_position(2).instance }
|
35
|
+
|
36
|
+
its(:id) { should == @last.id }
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "a rearrangement" do
|
43
|
+
|
44
|
+
describe "with max value" do
|
45
|
+
|
46
|
+
before {
|
47
|
+
@first = Duck.first
|
48
|
+
@second = Duck.offset(1).first
|
49
|
+
@ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_in([@first.id, @second.id])).collect {|d| d.id }
|
50
|
+
@first.update_attribute :row, RankedModel::MAX_RANK_VALUE
|
51
|
+
@second.update_attribute :row, RankedModel::MAX_RANK_VALUE
|
52
|
+
}
|
53
|
+
|
54
|
+
context {
|
55
|
+
|
56
|
+
subject { Duck.rank(:row).collect {|d| d.id } }
|
57
|
+
|
58
|
+
it { should == (@ordered[0..-2] + [@first.id, @second.id, @ordered[-1]]) }
|
59
|
+
|
60
|
+
}
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "with min value" do
|
65
|
+
|
66
|
+
before {
|
67
|
+
@first = Duck.first
|
68
|
+
@second = Duck.offset(1).first
|
69
|
+
@ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_in([@first.id, @second.id])).collect {|d| d.id }
|
70
|
+
@first.update_attribute :row, RankedModel::MIN_RANK_VALUE
|
71
|
+
@second.update_attribute :row, RankedModel::MIN_RANK_VALUE
|
72
|
+
}
|
73
|
+
|
74
|
+
context {
|
75
|
+
|
76
|
+
subject { Duck.rank(:row).collect {|d| d.id } }
|
77
|
+
|
78
|
+
it { should == ([@second.id, @first.id] + @ordered) }
|
79
|
+
|
80
|
+
}
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "with no more gaps" do
|
85
|
+
|
86
|
+
before {
|
87
|
+
@first = Duck.first
|
88
|
+
@second = Duck.where(:row => RankedModel::MAX_RANK_VALUE).first || Duck.offset(1).first
|
89
|
+
@third = Duck.offset(2).first
|
90
|
+
@fourth = Duck.offset(4).first
|
91
|
+
@lower = Duck.rank(:row).
|
92
|
+
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
|
93
|
+
where(Duck.arel_table[:row].lt(RankedModel::MAX_RANK_VALUE / 2)).
|
94
|
+
collect {|d| d.id }
|
95
|
+
@upper = Duck.rank(:row).
|
96
|
+
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
|
97
|
+
where(Duck.arel_table[:row].gteq(RankedModel::MAX_RANK_VALUE / 2)).
|
98
|
+
collect {|d| d.id }
|
99
|
+
@first.update_attribute :row, RankedModel::MIN_RANK_VALUE
|
100
|
+
@second.update_attribute :row, RankedModel::MAX_RANK_VALUE
|
101
|
+
@third.update_attribute :row, (RankedModel::MAX_RANK_VALUE / 2)
|
102
|
+
@fourth.update_attribute :row, @third.row
|
103
|
+
}
|
104
|
+
|
105
|
+
context {
|
106
|
+
|
107
|
+
subject { Duck.rank(:row).collect {|d| d.id } }
|
108
|
+
|
109
|
+
it { should == ([@first.id] + @lower + [@fourth.id, @third.id] + @upper + [@second.id]) }
|
110
|
+
|
111
|
+
}
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WrongScopeDuck do
|
4
|
+
|
5
|
+
it "should raise an error because of an unknown scope" do
|
6
|
+
|
7
|
+
expect {
|
8
|
+
WrongScopeDuck.create(:name => 'Quocky', :pond => 'Shin')
|
9
|
+
}.to raise_error(RankedModel::InvalidScope, 'No scope called "non_existant_scope" found in model')
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
describe WrongFieldDuck do
|
16
|
+
|
17
|
+
it "should raise an error because of an unknown field" do
|
18
|
+
|
19
|
+
expect {
|
20
|
+
WrongFieldDuck.create(:name => 'Quicky', :pond => 'Shin')
|
21
|
+
}.to raise_error(RankedModel::InvalidField, 'No field called "non_existant_field" found in model')
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -18,6 +18,18 @@ ActiveRecord::Schema.define :version => 0 do
|
|
18
18
|
t.integer :age
|
19
19
|
t.string :pond
|
20
20
|
end
|
21
|
+
|
22
|
+
create_table :wrong_scope_ducks, :force => true do |t|
|
23
|
+
t.string :name
|
24
|
+
t.integer :size
|
25
|
+
t.string :pond
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table :wrong_field_ducks, :force => true do |t|
|
29
|
+
t.string :name
|
30
|
+
t.integer :age
|
31
|
+
t.string :pond
|
32
|
+
end
|
21
33
|
end
|
22
34
|
|
23
35
|
class Duck < ActiveRecord::Base
|
@@ -30,3 +42,19 @@ class Duck < ActiveRecord::Base
|
|
30
42
|
scope :in_shin_pond, where(:pond => 'Shin')
|
31
43
|
|
32
44
|
end
|
45
|
+
|
46
|
+
# Negative examples
|
47
|
+
|
48
|
+
class WrongScopeDuck < ActiveRecord::Base
|
49
|
+
|
50
|
+
include RankedModel
|
51
|
+
ranks :size, :scope => :non_existant_scope
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
class WrongFieldDuck < ActiveRecord::Base
|
56
|
+
|
57
|
+
include RankedModel
|
58
|
+
ranks :age, :with_same => :non_existant_field
|
59
|
+
|
60
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ranked-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Matthew Beale
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-04-14 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -104,7 +104,7 @@ dependencies:
|
|
104
104
|
version: "0"
|
105
105
|
type: :development
|
106
106
|
version_requirements: *id006
|
107
|
-
description: ranked-model is a modern row sorting library built for Rails 3. It uses ARel
|
107
|
+
description: ranked-model is a modern row sorting library built for Rails 3. It uses ARel aggressively and is better optimized than most other libraries.
|
108
108
|
email:
|
109
109
|
- matt.beale@madhatted.com
|
110
110
|
executables: []
|
@@ -117,7 +117,6 @@ files:
|
|
117
117
|
- .gitignore
|
118
118
|
- .rspec
|
119
119
|
- Gemfile
|
120
|
-
- Gemfile.lock
|
121
120
|
- LICENSE
|
122
121
|
- Rakefile
|
123
122
|
- Readme.mkd
|
@@ -128,6 +127,8 @@ files:
|
|
128
127
|
- rails/init.rb
|
129
128
|
- ranked-model.gemspec
|
130
129
|
- spec/duck-model/duck_spec.rb
|
130
|
+
- spec/duck-model/lots_of_ducks_spec.rb
|
131
|
+
- spec/duck-model/wrong_ducks_spec.rb
|
131
132
|
- spec/ranked-model/ranker_spec.rb
|
132
133
|
- spec/ranked-model/version_spec.rb
|
133
134
|
- spec/spec_helper.rb
|
@@ -170,6 +171,8 @@ specification_version: 3
|
|
170
171
|
summary: An acts_as_sortable replacement built for Rails 3
|
171
172
|
test_files:
|
172
173
|
- spec/duck-model/duck_spec.rb
|
174
|
+
- spec/duck-model/lots_of_ducks_spec.rb
|
175
|
+
- spec/duck-model/wrong_ducks_spec.rb
|
173
176
|
- spec/ranked-model/ranker_spec.rb
|
174
177
|
- spec/ranked-model/version_spec.rb
|
175
178
|
- spec/spec_helper.rb
|
data/Gemfile.lock
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
ranked-model (0.0.1)
|
5
|
-
activerecord (>= 3.0.3)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: http://rubygems.org/
|
9
|
-
specs:
|
10
|
-
abstract (1.0.0)
|
11
|
-
actionpack (3.0.3)
|
12
|
-
activemodel (= 3.0.3)
|
13
|
-
activesupport (= 3.0.3)
|
14
|
-
builder (~> 2.1.2)
|
15
|
-
erubis (~> 2.6.6)
|
16
|
-
i18n (~> 0.4)
|
17
|
-
rack (~> 1.2.1)
|
18
|
-
rack-mount (~> 0.6.13)
|
19
|
-
rack-test (~> 0.5.6)
|
20
|
-
tzinfo (~> 0.3.23)
|
21
|
-
activemodel (3.0.3)
|
22
|
-
activesupport (= 3.0.3)
|
23
|
-
builder (~> 2.1.2)
|
24
|
-
i18n (~> 0.4)
|
25
|
-
activerecord (3.0.3)
|
26
|
-
activemodel (= 3.0.3)
|
27
|
-
activesupport (= 3.0.3)
|
28
|
-
arel (~> 2.0.2)
|
29
|
-
tzinfo (~> 0.3.23)
|
30
|
-
activesupport (3.0.3)
|
31
|
-
arel (2.0.7)
|
32
|
-
builder (2.1.2)
|
33
|
-
diff-lcs (1.1.2)
|
34
|
-
erubis (2.6.6)
|
35
|
-
abstract (>= 1.0.0)
|
36
|
-
genspec (0.1.1)
|
37
|
-
rspec
|
38
|
-
sc-core-ext (>= 1.2.0)
|
39
|
-
i18n (0.5.0)
|
40
|
-
mocha (0.9.10)
|
41
|
-
rake
|
42
|
-
rack (1.2.1)
|
43
|
-
rack-mount (0.6.13)
|
44
|
-
rack (>= 1.0.0)
|
45
|
-
rack-test (0.5.7)
|
46
|
-
rack (>= 1.0)
|
47
|
-
railties (3.0.3)
|
48
|
-
actionpack (= 3.0.3)
|
49
|
-
activesupport (= 3.0.3)
|
50
|
-
rake (>= 0.8.7)
|
51
|
-
thor (~> 0.14.4)
|
52
|
-
rake (0.8.7)
|
53
|
-
rspec (2.4.0)
|
54
|
-
rspec-core (~> 2.4.0)
|
55
|
-
rspec-expectations (~> 2.4.0)
|
56
|
-
rspec-mocks (~> 2.4.0)
|
57
|
-
rspec-core (2.4.0)
|
58
|
-
rspec-expectations (2.4.0)
|
59
|
-
diff-lcs (~> 1.1.2)
|
60
|
-
rspec-mocks (2.4.0)
|
61
|
-
rspec-rails (2.4.1)
|
62
|
-
actionpack (~> 3.0)
|
63
|
-
activesupport (~> 3.0)
|
64
|
-
railties (~> 3.0)
|
65
|
-
rspec (~> 2.4.0)
|
66
|
-
sc-core-ext (1.2.1)
|
67
|
-
activesupport (>= 2.3.5)
|
68
|
-
sqlite3 (1.3.3)
|
69
|
-
thor (0.14.6)
|
70
|
-
tzinfo (0.3.24)
|
71
|
-
|
72
|
-
PLATFORMS
|
73
|
-
ruby
|
74
|
-
|
75
|
-
DEPENDENCIES
|
76
|
-
genspec
|
77
|
-
mocha
|
78
|
-
ranked-model!
|
79
|
-
rspec
|
80
|
-
rspec-rails
|
81
|
-
sqlite3
|