shuber-sortable 1.0.4 → 1.0.5
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/CHANGELOG +10 -0
- data/README.rdoc +6 -0
- data/lib/sortable.rb +39 -12
- data/test/sortable_test.rb +26 -0
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
2009-05-30 - Sean Huber (shuber@huberry.com)
|
2
|
+
* Always convert options[:conditions] into an array
|
3
|
+
* options[:conditions] can be a hash
|
4
|
+
* Add higher_items and lower_items instance methods
|
5
|
+
* Update README.rdoc
|
6
|
+
* Update gemspec
|
7
|
+
|
8
|
+
2009-05-29 - Sean Huber (shuber@huberry.com)
|
9
|
+
* Call remove_from_lists after destroy instead of before in case any other before_destroy callbacks fail
|
10
|
+
|
1
11
|
2009-05-28 - Sean Huber (shuber@huberry.com)
|
2
12
|
* All active record versions >= 2.0.0 are now fully supported
|
3
13
|
|
data/README.rdoc
CHANGED
@@ -133,6 +133,9 @@ Any attributes specified as a :scope that are changed on an item cause the item
|
|
133
133
|
# Returns a boolean after determining if the current item is the first item in the specified list
|
134
134
|
first_item?(list_name = nil)
|
135
135
|
|
136
|
+
# Returns an array of items higher than the current item in the specified list
|
137
|
+
higher_items(list_name = nil)
|
138
|
+
|
136
139
|
# Returns a boolean after determining if the current item is in the specified list
|
137
140
|
in_list?(list_name = nil)
|
138
141
|
|
@@ -165,6 +168,9 @@ Any attributes specified as a :scope that are changed on an item cause the item
|
|
165
168
|
# Returns 0 if there are no items in the specified list
|
166
169
|
last_position(list_name = nil)
|
167
170
|
|
171
|
+
# Returns an array of items lower than the current item in the specified list
|
172
|
+
lower_items(list_name = nil)
|
173
|
+
|
168
174
|
# Moves the current item down one position in the specified list and saves
|
169
175
|
move_down!(list_name = nil)
|
170
176
|
|
data/lib/sortable.rb
CHANGED
@@ -12,7 +12,7 @@ module Huberry
|
|
12
12
|
# Accepts four options:
|
13
13
|
#
|
14
14
|
# :column => The name of the column that will be used to store an item's position in the list. Defaults to :position
|
15
|
-
# :conditions => Any extra constraints to use if you need to specify a tighter scope than just a foreign key. Defaults to
|
15
|
+
# :conditions => Any extra constraints to use if you need to specify a tighter scope than just a foreign key. Defaults to {}
|
16
16
|
# :list_name => The name of the list (this is used when calling all sortable related instance methods). Defaults to nil
|
17
17
|
# :scope => A foreign key or an array of foreign keys to use as list constraints. Defaults to []
|
18
18
|
#
|
@@ -123,11 +123,22 @@ module Huberry
|
|
123
123
|
|
124
124
|
define_attribute_methods
|
125
125
|
|
126
|
-
options = { :column => :position, :conditions =>
|
127
|
-
options[:scope] = [options[:scope]] unless options[:scope].is_a?(Array)
|
126
|
+
options = { :column => :position, :conditions => {}, :list_name => nil, :scope => [] }.merge(options)
|
128
127
|
|
128
|
+
options[:conditions] = options[:conditions].inject(['1 = 1']) do |conditions, (key, value)|
|
129
|
+
conditions.first << " AND #{key.is_a?(Symbol) ? "#{table_name}.#{key}" : key} "
|
130
|
+
if value.nil?
|
131
|
+
conditions.first << 'IS NULL'
|
132
|
+
else
|
133
|
+
conditions.first << '= ?'
|
134
|
+
conditions << value
|
135
|
+
end
|
136
|
+
end if options[:conditions].is_a?(Hash)
|
137
|
+
options[:conditions] = Array(options[:conditions])
|
138
|
+
|
139
|
+
options[:scope] = Array(options[:scope])
|
129
140
|
options[:scope].each do |scope|
|
130
|
-
|
141
|
+
options[:conditions].first << " AND (#{table_name}.#{scope} = ?)"
|
131
142
|
|
132
143
|
unless instance_methods.include?("#{scope}_with_sortable=")
|
133
144
|
define_method "#{scope}_with_sortable=" do |value|
|
@@ -145,8 +156,8 @@ module Huberry
|
|
145
156
|
def self.included(base)
|
146
157
|
base.class_eval do
|
147
158
|
before_create :add_to_lists
|
148
|
-
before_destroy :remove_from_lists
|
149
159
|
before_update :update_lists
|
160
|
+
after_destroy :remove_from_lists
|
150
161
|
alias_method_chain :reload, :sortable
|
151
162
|
end
|
152
163
|
end
|
@@ -171,6 +182,14 @@ module Huberry
|
|
171
182
|
self == first_item(list_name)
|
172
183
|
end
|
173
184
|
|
185
|
+
# Returns an array of items higher than the current item in the specified list
|
186
|
+
def higher_items(list_name = nil)
|
187
|
+
options = evaluate_sortable_options(list_name)
|
188
|
+
options[:conditions].first << " AND #{self.class.table_name}.#{options[:column]} < ?"
|
189
|
+
options[:conditions] << send(options[:column])
|
190
|
+
self.class.base_class.find(:all, :conditions => options[:conditions], :order => options[:column])
|
191
|
+
end
|
192
|
+
|
174
193
|
# Returns a boolean after determining if the current item is in the specified list
|
175
194
|
def in_list?(list_name = nil)
|
176
195
|
!new_record? && !send(evaluate_sortable_options(list_name)[:column]).nil?
|
@@ -213,9 +232,9 @@ module Huberry
|
|
213
232
|
# Returns the last item in a list associated with the current item
|
214
233
|
def last_item(list_name = nil)
|
215
234
|
options = evaluate_sortable_options(list_name)
|
216
|
-
|
235
|
+
options[:conditions].first << " AND #{self.class.table_name}.#{options[:column]} IS NOT NULL"
|
217
236
|
klass, conditions = [self.class.base_class, { :conditions => options[:conditions] }]
|
218
|
-
klass.send("find_by_#{options[:column]}".to_sym, klass.maximum(options[:column]
|
237
|
+
klass.send("find_by_#{options[:column]}".to_sym, klass.maximum(options[:column], conditions), conditions)
|
219
238
|
end
|
220
239
|
|
221
240
|
# Returns a boolean after determining if the current item is the last item in the specified list
|
@@ -231,6 +250,14 @@ module Huberry
|
|
231
250
|
item.nil? ? 0 : item.send(evaluate_sortable_options(list_name)[:column])
|
232
251
|
end
|
233
252
|
|
253
|
+
# Returns an array of items lower than the current item in the specified list
|
254
|
+
def lower_items(list_name = nil)
|
255
|
+
options = evaluate_sortable_options(list_name)
|
256
|
+
options[:conditions].first << " AND #{self.class.table_name}.#{options[:column]} > ?"
|
257
|
+
options[:conditions] << send(options[:column])
|
258
|
+
self.class.base_class.find(:all, :conditions => options[:conditions], :order => "#{self.class.table_name}.#{options[:column]}")
|
259
|
+
end
|
260
|
+
|
234
261
|
# Moves the current item down one position in the specified list and saves
|
235
262
|
def move_down!(list_name = nil)
|
236
263
|
in_list?(list_name) && (last_item?(list_name) || insert_at!(send(evaluate_sortable_options(list_name)[:column]) + 1, list_name))
|
@@ -306,13 +333,12 @@ module Huberry
|
|
306
333
|
# Returns the evaluated options
|
307
334
|
def evaluate_sortable_options(list_name = nil)
|
308
335
|
self.class.assert_sortable_list_exists!(list_name)
|
309
|
-
options = self.class.sortable_lists[list_name.to_s].inject({}) { |hash,
|
336
|
+
options = self.class.sortable_lists[list_name.to_s].inject({}) { |hash, (key, value)| hash.merge! key => Marshal::load(Marshal.dump(value)) } # deep dup
|
310
337
|
options[:scope].each do |scope|
|
311
338
|
value = send(scope)
|
312
339
|
if value.nil?
|
313
|
-
|
340
|
+
options[:conditions].first.gsub!(/#{scope} \= \?/, "#{scope} IS NULL")
|
314
341
|
else
|
315
|
-
options[:conditions] = [options[:conditions]] unless options[:conditions].is_a?(Array)
|
316
342
|
options[:conditions] << value
|
317
343
|
end
|
318
344
|
end
|
@@ -323,7 +349,8 @@ module Huberry
|
|
323
349
|
# <tt>direction</tt> (:up or :down) for the specified list
|
324
350
|
def move_lower_items(direction, position, list_name = nil)
|
325
351
|
options = evaluate_sortable_options(list_name)
|
326
|
-
|
352
|
+
options[:conditions].first << " AND #{self.class.table_name}.#{options[:column]} > ? AND #{self.class.table_name}.#{options[:column]} IS NOT NULL"
|
353
|
+
options[:conditions] << position
|
327
354
|
self.class.base_class.update_all "#{options[:column]} = #{options[:column]} #{direction == :up ? '-' : '+'} 1", options[:conditions]
|
328
355
|
end
|
329
356
|
|
@@ -331,7 +358,7 @@ module Huberry
|
|
331
358
|
def remove_from_list(list_name = nil)
|
332
359
|
options = evaluate_sortable_options(list_name)
|
333
360
|
move_lower_items(:up, send(options[:column]), list_name)
|
334
|
-
send("#{options[:column]}=".to_sym, nil)
|
361
|
+
send("#{options[:column]}=".to_sym, nil) unless self.frozen?
|
335
362
|
end
|
336
363
|
|
337
364
|
# Removes the current item from all sortable lists
|
data/test/sortable_test.rb
CHANGED
@@ -24,7 +24,9 @@ def create_tables
|
|
24
24
|
|
25
25
|
create_table :users do |t|
|
26
26
|
t.string :type
|
27
|
+
t.string :name
|
27
28
|
t.integer :position
|
29
|
+
t.integer :steves_position
|
28
30
|
end
|
29
31
|
end
|
30
32
|
end
|
@@ -44,6 +46,7 @@ end
|
|
44
46
|
|
45
47
|
class User < ActiveRecord::Base
|
46
48
|
sortable :scope => :type
|
49
|
+
sortable :conditions => { :name => 'steve' }, :column => :steves_position, :list_name => :steves
|
47
50
|
end
|
48
51
|
|
49
52
|
class Admin < User
|
@@ -297,4 +300,27 @@ class SortableTest < Test::Unit::TestCase
|
|
297
300
|
assert_equal 2, @admin_2.position
|
298
301
|
end
|
299
302
|
|
303
|
+
def test_should_accept_hash_conditions
|
304
|
+
@user = User.create :name => 'steve'
|
305
|
+
@user_2 = User.create :name => 'bob'
|
306
|
+
@user_3 = User.create :name => 'steve'
|
307
|
+
assert_equal 1, @user.steves_position
|
308
|
+
assert_equal 2, @user_2.steves_position
|
309
|
+
assert_equal 2, @user_3.steves_position
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_should_return_higher_items
|
313
|
+
@user = User.create
|
314
|
+
@user_2 = User.create
|
315
|
+
@user_3 = User.create
|
316
|
+
assert_equal [@user, @user_2], @user_3.higher_items
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_should_return_lower_items
|
320
|
+
@user = User.create
|
321
|
+
@user_2 = User.create
|
322
|
+
@user_3 = User.create
|
323
|
+
assert_equal [@user_2, @user_3], @user.lower_items
|
324
|
+
end
|
325
|
+
|
300
326
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shuber-sortable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Huber
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-30 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|