acts_as_list_with_sti_support 0.1.1 → 0.1.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/.specification CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 0
9
- version: 0.1.0
8
+ - 2
9
+ version: 0.1.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Coroutine
@@ -15,11 +15,11 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-03-10 00:00:00 -06:00
18
+ date: 2010-03-25 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: activesupport
22
+ name: activerecord
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
25
  requirements:
@@ -30,7 +30,19 @@ dependencies:
30
30
  version: "0"
31
31
  type: :runtime
32
32
  version_requirements: *id001
33
- description: This acts_as extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a position column defined as an integer on the mapped database table.
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :runtime
44
+ version_requirements: *id002
45
+ description: This acts_as extension does everything acts_as_list does, but it also works in single table inheritance designs and accepts less brain-damaged scope syntax.
34
46
  email: jdugan@coroutine.com
35
47
  executables: []
36
48
 
@@ -39,14 +51,19 @@ extensions: []
39
51
  extra_rdoc_files:
40
52
  - README.rdoc
41
53
  files:
54
+ - .specification
42
55
  - MIT-LICENSE
43
56
  - README.rdoc
44
57
  - Rakefile
45
58
  - VERSION
59
+ - acts_as_list_with_sti_support.gemspec
46
60
  - init.rb
61
+ - lib/acts_as_list_with_sti_support.rb
62
+ - lib/acts_as_list_with_sti_support/base.rb
63
+ - test/acts_as_list_with_sti_support_test.rb
47
64
  - test/test_helper.rb
48
65
  has_rdoc: true
49
- homepage: http://github.com/coroutine/acts_as_label_with_sti_support
66
+ homepage: http://github.com/coroutine/acts_as_list_with_sti_support
50
67
  licenses: []
51
68
 
52
69
  post_install_message:
data/Rakefile CHANGED
@@ -28,13 +28,16 @@ end
28
28
 
29
29
  begin
30
30
  Jeweler::Tasks.new do |gemspec|
31
- gemspec.name = "acts_as_list_with_sti_support"
32
- gemspec.summary = "Gem version of acts_as_list_with_sti_support Rails plugin, a smarter version of acts_as_list."
33
- gemspec.description = "This acts_as extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a position column defined as an integer on the mapped database table."
31
+ gemspec.authors = ["Coroutine", "John Dugan"]
32
+ gemspec.description = "This acts_as extension does everything acts_as_list does, but it also works in single table inheritance designs and accepts less brain-damaged scope syntax."
34
33
  gemspec.email = "jdugan@coroutine.com"
35
34
  gemspec.homepage = "http://github.com/coroutine/acts_as_list_with_sti_support"
36
- gemspec.authors = ["Coroutine", "John Dugan"]
37
- gemspec.add_dependency "activesupport"
35
+ gemspec.name = "acts_as_list_with_sti_support"
36
+ gemspec.summary = "Gem version of acts_as_list_with_sti_support Rails plugin, a smarter version of acts_as_list."
37
+
38
+ gemspec.add_dependency("activerecord")
39
+ gemspec.add_dependency("activesupport")
40
+ gemspec.files.include("lib/**/*.rb")
38
41
  end
39
42
  Jeweler::GemcutterTasks.new
40
43
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{acts_as_list_with_sti_support}
8
- s.version = "0.1.1"
8
+ s.version = "0.1.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Coroutine", "John Dugan"]
12
- s.date = %q{2010-03-10}
13
- s.description = %q{This acts_as extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a position column defined as an integer on the mapped database table.}
12
+ s.date = %q{2010-03-25}
13
+ s.description = %q{This acts_as extension does everything acts_as_list does, but it also works in single table inheritance designs and accepts less brain-damaged scope syntax.}
14
14
  s.email = %q{jdugan@coroutine.com}
15
15
  s.extra_rdoc_files = [
16
16
  "README.rdoc"
@@ -21,10 +21,10 @@ Gem::Specification.new do |s|
21
21
  "README.rdoc",
22
22
  "Rakefile",
23
23
  "VERSION",
24
- "acts_as_list_with_sti_support-0.1.0.gem",
25
24
  "acts_as_list_with_sti_support.gemspec",
26
25
  "init.rb",
27
26
  "lib/acts_as_list_with_sti_support.rb",
27
+ "lib/acts_as_list_with_sti_support/base.rb",
28
28
  "test/acts_as_list_with_sti_support_test.rb",
29
29
  "test/test_helper.rb"
30
30
  ]
@@ -43,11 +43,14 @@ Gem::Specification.new do |s|
43
43
  s.specification_version = 3
44
44
 
45
45
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
46
+ s.add_runtime_dependency(%q<activerecord>, [">= 0"])
46
47
  s.add_runtime_dependency(%q<activesupport>, [">= 0"])
47
48
  else
49
+ s.add_dependency(%q<activerecord>, [">= 0"])
48
50
  s.add_dependency(%q<activesupport>, [">= 0"])
49
51
  end
50
52
  else
53
+ s.add_dependency(%q<activerecord>, [">= 0"])
51
54
  s.add_dependency(%q<activesupport>, [">= 0"])
52
55
  end
53
56
  end
data/init.rb CHANGED
@@ -1,5 +1 @@
1
- require 'acts_as_list_with_sti_support'
2
-
3
- ActiveRecord::Base.class_eval do
4
- include Coroutine::Acts::List
5
- end
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
@@ -1,319 +1,10 @@
1
- module Coroutine #:nodoc:
2
- module Acts #:nodoc:
3
- module List #:nodoc:
4
-
5
- def self.included(base)
6
- base.extend(ClassMethods)
7
- end
1
+ # external gems
2
+ require "active_record"
8
3
 
9
-
10
- module ClassMethods
11
-
12
- # = Description
13
- #
14
- # This +acts_as+ extension provides the capabilities for sorting and reordering a number of objects in a list.
15
- # The class that has this specified needs to have a +position+ column defined as an integer on
16
- # the mapped database table.
17
- #
18
- #
19
- # = Usage
20
- #
21
- # class TodoList < ActiveRecord::Base
22
- # has_many :todo_items, :order => "position"
23
- # end
24
- #
25
- # class TodoItem < ActiveRecord::Base
26
- # belongs_to :todo_list
27
- # acts_as_list :scope => :todo_list
28
- # end
29
- #
30
- # todo_list.first.move_to_bottom
31
- # todo_list.last.move_higher
32
- #
33
- #
34
- # = Configuration
35
- #
36
- # * +column+ - specifies the column name to use for keeping the position integer (default: +position+)
37
- # * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt>
38
- # (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
39
- # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
40
- # Example: <tt>acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>
41
- #
42
- def acts_as_list(options = {})
43
-
44
- #-------------------------------------------
45
- # scrub options
46
- #-------------------------------------------
47
- options = {} if !options.is_a?(Hash)
48
- column = options.key?(:column) ? options[:column] : :position
49
- scope = options.key?(:scope) ? options[:scope] : "1 = 1"
50
-
51
4
 
52
- #--------------------------------------------
53
- # mix methods into class definition
54
- #--------------------------------------------
55
- class_eval do
56
-
57
- # Add inheritable accessors
58
- write_inheritable_attribute :acts_as_list_column, column
59
- class_inheritable_reader :acts_as_list_column
60
- write_inheritable_attribute :acts_as_list_scope, scope
61
- class_inheritable_reader :acts_as_list_scope
62
- write_inheritable_attribute :acts_as_list_default_scope, "1 = 1"
63
- class_inheritable_reader :acts_as_list_default_scope
64
- write_inheritable_attribute :acts_as_list_scope_condition, nil
65
- class_inheritable_reader :acts_as_list_scope_condition
66
-
67
-
68
- # Add validations (column is allowed to be nil to support soft deletes)
69
- validates_numericality_of column, :only_integer => true, :greater_than => 0, :allow_nil => true
70
-
71
-
72
- # Add callbacks
73
- before_validation_on_create :add_to_list_bottom
74
- before_destroy :remove_from_list
75
-
76
-
77
- # if no default scoping, order by position
78
- if self.default_scoping.empty?
79
- default_scope :order => column
80
- end
81
-
82
-
83
- # Include instance methods
84
- include Coroutine::Acts::List::InstanceMethods
5
+ # acts_as_label extension
6
+ require File.dirname(__FILE__) + "/acts_as_list_with_sti_support/base"
85
7
 
86
- end
87
-
88
- end
89
- end
90
8
 
91
-
92
- # All the methods available to a record that has had <tt>acts_as_list</tt> specified. Each method works
93
- # by assuming the object to be the item in the list, so <tt>chapter.move_lower</tt> would move that chapter
94
- # lower in the list of all chapters. Likewise, <tt>chapter.first?</tt> would return +true+ if that chapter is
95
- # the first in the list of all chapters.
96
- #
97
- module InstanceMethods
98
-
99
- # Return the instance's class object
100
- def acts_as_list_class
101
- self.class
102
- end
103
-
104
- # Returns the column name that holds the position value.
105
- def position_column
106
- acts_as_list_column
107
- end
108
-
109
- # Returns the scope condition appropriate for the specified definition. (This could probably
110
- # be refactored for brevity.)
111
- def scope_condition
112
- if acts_as_list_scope_condition.nil?
113
-
114
- # if symbol, do convenience conversions
115
- if acts_as_list_scope.is_a?(Symbol)
116
- scope_as_sym = acts_as_list_scope
117
- scope_as_str = acts_as_list_scope.to_s
118
- if scope_as_str.nil?
119
- acts_as_list_scope_condition = "#{scope_as_str} IS NULL"
120
- else
121
- scope_with_id = scope_as_str + "_id"
122
- if scope_as_str !~ /_id$/ && acts_as_list_class.column_names.include?("#{scope_with_id}")
123
- scope_as_sym = scope_with_id.to_sym
124
- scope_as_str = scope_as_sym.to_s
125
- end
126
- acts_as_list_scope_condition = "#{scope_as_str} = \'#{self[scope_as_sym]}\'"
127
- end
128
-
129
- # if lambda, execute in scope of instance
130
- elsif acts_as_list_scope.is_a?(Proc)
131
- acts_as_list_scope_condition = acts_as_list_scope.call(self)
132
-
133
- # else, return string as is
134
- else
135
- acts_as_list_scope_condition = !acts_as_list_scope.blank? ? acts_as_list_scope.to_s : acts_as_list_default_scope.to_s
136
- end
137
- end
138
-
139
- acts_as_list_scope_condition
140
- end
141
-
142
- # Insert the item at the given position (defaults to the top position of 1).
143
- def insert_at(position = 1)
144
- insert_at_position(position)
145
- end
146
-
147
- # Swap positions with the next lower item, if one exists.
148
- def move_lower
149
- return unless lower_item
150
-
151
- acts_as_list_class.transaction do
152
- lower_item.decrement_position
153
- increment_position
154
- end
155
- end
156
-
157
- # Swap positions with the next higher item, if one exists.
158
- def move_higher
159
- return unless higher_item
160
-
161
- acts_as_list_class.transaction do
162
- higher_item.increment_position
163
- decrement_position
164
- end
165
- end
166
-
167
- # Move to the bottom of the list. If the item is already in the list, the items below it have their
168
- # position adjusted accordingly.
169
- def move_to_bottom
170
- return unless in_list?
171
- acts_as_list_class.transaction do
172
- decrement_positions_on_lower_items
173
- assume_bottom_position
174
- end
175
- end
176
-
177
- # Move to the top of the list. If the item is already in the list, the items above it have their
178
- # position adjusted accordingly.
179
- def move_to_top
180
- return unless in_list?
181
- acts_as_list_class.transaction do
182
- increment_positions_on_higher_items
183
- assume_top_position
184
- end
185
- end
186
-
187
- # Removes the item from the list.
188
- def remove_from_list
189
- if in_list?
190
- decrement_positions_on_lower_items
191
- update_attribute position_column, nil
192
- end
193
- end
194
-
195
- # Increase the position of this item without adjusting the rest of the list.
196
- def increment_position
197
- return unless in_list?
198
- update_attribute position_column, self.send(position_column).to_i + 1
199
- end
200
-
201
- # Decrease the position of this item without adjusting the rest of the list.
202
- def decrement_position
203
- return unless in_list?
204
- update_attribute position_column, self.send(position_column).to_i - 1
205
- end
206
-
207
- # Return +true+ if this object is the first in the list.
208
- def first?
209
- return false unless in_list?
210
- self.send(position_column) == 1
211
- end
212
-
213
- # Return +true+ if this object is the last in the list.
214
- def last?
215
- return false unless in_list?
216
- self.send(position_column) == bottom_position_in_list
217
- end
218
-
219
- # Return the next higher item in the list.
220
- def higher_item
221
- return nil unless in_list?
222
- acts_as_list_class.find(:first, :conditions =>
223
- "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}"
224
- )
225
- end
226
-
227
- # Return the next lower item in the list.
228
- def lower_item
229
- return nil unless in_list?
230
- acts_as_list_class.find(:first, :conditions =>
231
- "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}"
232
- )
233
- end
234
-
235
- # Test if this record is in a list
236
- def in_list?
237
- !send(position_column).nil?
238
- end
239
-
240
- private
241
- def add_to_list_top
242
- increment_positions_on_all_items
243
- end
244
-
245
- def add_to_list_bottom
246
- self[position_column] = bottom_position_in_list.to_i + 1
247
- end
248
-
249
- # Returns the bottom position number in the list.
250
- # bottom_position_in_list # => 2
251
- def bottom_position_in_list(except = nil)
252
- item = bottom_item(except)
253
- item ? item.send(position_column) : 0
254
- end
255
-
256
- # Returns the bottom item
257
- def bottom_item(except = nil)
258
- conditions = scope_condition
259
- conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except
260
- acts_as_list_class.find(:first, :conditions => conditions, :order => "#{position_column} DESC")
261
- end
262
-
263
- # Forces item to assume the bottom position in the list.
264
- def assume_bottom_position
265
- update_attribute(position_column, bottom_position_in_list(self).to_i + 1)
266
- end
267
-
268
- # Forces item to assume the top position in the list.
269
- def assume_top_position
270
- update_attribute(position_column, 1)
271
- end
272
-
273
- # This has the effect of moving all the higher items up one.
274
- def decrement_positions_on_higher_items(position)
275
- acts_as_list_class.update_all(
276
- "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} <= #{position}"
277
- )
278
- end
279
-
280
- # This has the effect of moving all the lower items up one.
281
- def decrement_positions_on_lower_items
282
- return unless in_list?
283
- acts_as_list_class.update_all(
284
- "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}"
285
- )
286
- end
287
-
288
- # This has the effect of moving all the higher items down one.
289
- def increment_positions_on_higher_items
290
- return unless in_list?
291
- acts_as_list_class.update_all(
292
- "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
293
- )
294
- end
295
-
296
- # This has the effect of moving all the lower items down one.
297
- def increment_positions_on_lower_items(position)
298
- acts_as_list_class.update_all(
299
- "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} >= #{position}"
300
- )
301
- end
302
-
303
- # Increments position (<tt>position_column</tt>) of all items in the list.
304
- def increment_positions_on_all_items
305
- acts_as_list_class.update_all(
306
- "#{position_column} = (#{position_column} + 1)", "#{scope_condition}"
307
- )
308
- end
309
-
310
- def insert_at_position(position)
311
- remove_from_list
312
- increment_positions_on_lower_items(position)
313
- self.update_attribute(position_column, position)
314
- end
315
-
316
- end
317
- end
318
- end
319
- end
9
+ # add extensions to active record
10
+ ::ActiveRecord::Base.send(:include, Coroutine::ActsAsList::Base)
@@ -0,0 +1,319 @@
1
+ module Coroutine #:nodoc:
2
+ module ActsAsList #:nodoc:
3
+ module Base #:nodoc:
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+
10
+ module ClassMethods
11
+
12
+ # = Description
13
+ #
14
+ # This +acts_as+ extension provides the capabilities for sorting and reordering a number of objects in a list.
15
+ # The class that has this specified needs to have a +position+ column defined as an integer on
16
+ # the mapped database table.
17
+ #
18
+ #
19
+ # = Usage
20
+ #
21
+ # class TodoList < ActiveRecord::Base
22
+ # has_many :todo_items, :order => "position"
23
+ # end
24
+ #
25
+ # class TodoItem < ActiveRecord::Base
26
+ # belongs_to :todo_list
27
+ # acts_as_list :scope => :todo_list
28
+ # end
29
+ #
30
+ # todo_list.first.move_to_bottom
31
+ # todo_list.last.move_higher
32
+ #
33
+ #
34
+ # = Configuration
35
+ #
36
+ # * +column+ - specifies the column name to use for keeping the position integer (default: +position+)
37
+ # * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt>
38
+ # (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
39
+ # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
40
+ # Example: <tt>acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>
41
+ #
42
+ def acts_as_list(options = {})
43
+
44
+ #-------------------------------------------
45
+ # scrub options
46
+ #-------------------------------------------
47
+ options = {} if !options.is_a?(Hash)
48
+ column = options.key?(:column) ? options[:column] : :position
49
+ scope = options.key?(:scope) ? options[:scope] : "1 = 1"
50
+
51
+
52
+ #--------------------------------------------
53
+ # mix methods into class definition
54
+ #--------------------------------------------
55
+ class_eval do
56
+
57
+ # Add inheritable accessors
58
+ write_inheritable_attribute :acts_as_list_column, column
59
+ class_inheritable_reader :acts_as_list_column
60
+ write_inheritable_attribute :acts_as_list_scope, scope
61
+ class_inheritable_reader :acts_as_list_scope
62
+ write_inheritable_attribute :acts_as_list_default_scope, "1 = 1"
63
+ class_inheritable_reader :acts_as_list_default_scope
64
+ write_inheritable_attribute :acts_as_list_scope_condition, nil
65
+ class_inheritable_reader :acts_as_list_scope_condition
66
+
67
+
68
+ # Add validations (column is allowed to be nil to support soft deletes)
69
+ validates_numericality_of column, :only_integer => true, :greater_than => 0, :allow_nil => true
70
+
71
+
72
+ # Add callbacks
73
+ before_validation_on_create :add_to_list_bottom
74
+ before_destroy :remove_from_list
75
+
76
+
77
+ # if no default scoping, order by position
78
+ if self.default_scoping.empty?
79
+ default_scope :order => column
80
+ end
81
+
82
+
83
+ # Include instance methods
84
+ include Coroutine::ActsAsList::Base::InstanceMethods
85
+
86
+ end
87
+
88
+ end
89
+ end
90
+
91
+
92
+ # All the methods available to a record that has had <tt>acts_as_list</tt> specified. Each method works
93
+ # by assuming the object to be the item in the list, so <tt>chapter.move_lower</tt> would move that chapter
94
+ # lower in the list of all chapters. Likewise, <tt>chapter.first?</tt> would return +true+ if that chapter is
95
+ # the first in the list of all chapters.
96
+ #
97
+ module InstanceMethods
98
+
99
+ # Return the instance's class object
100
+ def acts_as_list_class
101
+ self.class
102
+ end
103
+
104
+ # Returns the column name that holds the position value.
105
+ def position_column
106
+ acts_as_list_column
107
+ end
108
+
109
+ # Returns the scope condition appropriate for the specified definition. (This could probably
110
+ # be refactored for brevity.)
111
+ def scope_condition
112
+ if acts_as_list_scope_condition.nil?
113
+
114
+ # if symbol, do convenience conversions
115
+ if acts_as_list_scope.is_a?(Symbol)
116
+ scope_as_sym = acts_as_list_scope
117
+ scope_as_str = acts_as_list_scope.to_s
118
+ if scope_as_str.nil?
119
+ acts_as_list_scope_condition = "#{scope_as_str} IS NULL"
120
+ else
121
+ scope_with_id = scope_as_str + "_id"
122
+ if scope_as_str !~ /_id$/ && acts_as_list_class.column_names.include?("#{scope_with_id}")
123
+ scope_as_sym = scope_with_id.to_sym
124
+ scope_as_str = scope_as_sym.to_s
125
+ end
126
+ acts_as_list_scope_condition = "#{scope_as_str} = \'#{self[scope_as_sym]}\'"
127
+ end
128
+
129
+ # if lambda, execute in scope of instance
130
+ elsif acts_as_list_scope.is_a?(Proc)
131
+ acts_as_list_scope_condition = acts_as_list_scope.call(self)
132
+
133
+ # else, return string as is
134
+ else
135
+ acts_as_list_scope_condition = !acts_as_list_scope.blank? ? acts_as_list_scope.to_s : acts_as_list_default_scope.to_s
136
+ end
137
+ end
138
+
139
+ acts_as_list_scope_condition
140
+ end
141
+
142
+ # Insert the item at the given position (defaults to the top position of 1).
143
+ def insert_at(position = 1)
144
+ insert_at_position(position)
145
+ end
146
+
147
+ # Swap positions with the next lower item, if one exists.
148
+ def move_lower
149
+ return unless lower_item
150
+
151
+ acts_as_list_class.transaction do
152
+ lower_item.decrement_position
153
+ increment_position
154
+ end
155
+ end
156
+
157
+ # Swap positions with the next higher item, if one exists.
158
+ def move_higher
159
+ return unless higher_item
160
+
161
+ acts_as_list_class.transaction do
162
+ higher_item.increment_position
163
+ decrement_position
164
+ end
165
+ end
166
+
167
+ # Move to the bottom of the list. If the item is already in the list, the items below it have their
168
+ # position adjusted accordingly.
169
+ def move_to_bottom
170
+ return unless in_list?
171
+ acts_as_list_class.transaction do
172
+ decrement_positions_on_lower_items
173
+ assume_bottom_position
174
+ end
175
+ end
176
+
177
+ # Move to the top of the list. If the item is already in the list, the items above it have their
178
+ # position adjusted accordingly.
179
+ def move_to_top
180
+ return unless in_list?
181
+ acts_as_list_class.transaction do
182
+ increment_positions_on_higher_items
183
+ assume_top_position
184
+ end
185
+ end
186
+
187
+ # Removes the item from the list.
188
+ def remove_from_list
189
+ if in_list?
190
+ decrement_positions_on_lower_items
191
+ update_attribute position_column, nil
192
+ end
193
+ end
194
+
195
+ # Increase the position of this item without adjusting the rest of the list.
196
+ def increment_position
197
+ return unless in_list?
198
+ update_attribute position_column, self.send(position_column).to_i + 1
199
+ end
200
+
201
+ # Decrease the position of this item without adjusting the rest of the list.
202
+ def decrement_position
203
+ return unless in_list?
204
+ update_attribute position_column, self.send(position_column).to_i - 1
205
+ end
206
+
207
+ # Return +true+ if this object is the first in the list.
208
+ def first?
209
+ return false unless in_list?
210
+ self.send(position_column) == 1
211
+ end
212
+
213
+ # Return +true+ if this object is the last in the list.
214
+ def last?
215
+ return false unless in_list?
216
+ self.send(position_column) == bottom_position_in_list
217
+ end
218
+
219
+ # Return the next higher item in the list.
220
+ def higher_item
221
+ return nil unless in_list?
222
+ acts_as_list_class.find(:first, :conditions =>
223
+ "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}"
224
+ )
225
+ end
226
+
227
+ # Return the next lower item in the list.
228
+ def lower_item
229
+ return nil unless in_list?
230
+ acts_as_list_class.find(:first, :conditions =>
231
+ "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}"
232
+ )
233
+ end
234
+
235
+ # Test if this record is in a list
236
+ def in_list?
237
+ !send(position_column).nil?
238
+ end
239
+
240
+ private
241
+ def add_to_list_top
242
+ increment_positions_on_all_items
243
+ end
244
+
245
+ def add_to_list_bottom
246
+ self[position_column] = bottom_position_in_list.to_i + 1
247
+ end
248
+
249
+ # Returns the bottom position number in the list.
250
+ # bottom_position_in_list # => 2
251
+ def bottom_position_in_list(except = nil)
252
+ item = bottom_item(except)
253
+ item ? item.send(position_column) : 0
254
+ end
255
+
256
+ # Returns the bottom item
257
+ def bottom_item(except = nil)
258
+ conditions = scope_condition
259
+ conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except
260
+ acts_as_list_class.find(:first, :conditions => conditions, :order => "#{position_column} DESC")
261
+ end
262
+
263
+ # Forces item to assume the bottom position in the list.
264
+ def assume_bottom_position
265
+ update_attribute(position_column, bottom_position_in_list(self).to_i + 1)
266
+ end
267
+
268
+ # Forces item to assume the top position in the list.
269
+ def assume_top_position
270
+ update_attribute(position_column, 1)
271
+ end
272
+
273
+ # This has the effect of moving all the higher items up one.
274
+ def decrement_positions_on_higher_items(position)
275
+ acts_as_list_class.update_all(
276
+ "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} <= #{position}"
277
+ )
278
+ end
279
+
280
+ # This has the effect of moving all the lower items up one.
281
+ def decrement_positions_on_lower_items
282
+ return unless in_list?
283
+ acts_as_list_class.update_all(
284
+ "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}"
285
+ )
286
+ end
287
+
288
+ # This has the effect of moving all the higher items down one.
289
+ def increment_positions_on_higher_items
290
+ return unless in_list?
291
+ acts_as_list_class.update_all(
292
+ "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
293
+ )
294
+ end
295
+
296
+ # This has the effect of moving all the lower items down one.
297
+ def increment_positions_on_lower_items(position)
298
+ acts_as_list_class.update_all(
299
+ "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} >= #{position}"
300
+ )
301
+ end
302
+
303
+ # Increments position (<tt>position_column</tt>) of all items in the list.
304
+ def increment_positions_on_all_items
305
+ acts_as_list_class.update_all(
306
+ "#{position_column} = (#{position_column} + 1)", "#{scope_condition}"
307
+ )
308
+ end
309
+
310
+ def insert_at_position(position)
311
+ remove_from_list
312
+ increment_positions_on_lower_items(position)
313
+ self.update_attribute(position_column, position)
314
+ end
315
+
316
+ end
317
+ end
318
+ end
319
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 1
9
- version: 0.1.1
8
+ - 2
9
+ version: 0.1.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Coroutine
@@ -15,11 +15,11 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-03-10 00:00:00 -06:00
18
+ date: 2010-03-25 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: activesupport
22
+ name: activerecord
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
25
  requirements:
@@ -30,7 +30,19 @@ dependencies:
30
30
  version: "0"
31
31
  type: :runtime
32
32
  version_requirements: *id001
33
- description: This acts_as extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a position column defined as an integer on the mapped database table.
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :runtime
44
+ version_requirements: *id002
45
+ description: This acts_as extension does everything acts_as_list does, but it also works in single table inheritance designs and accepts less brain-damaged scope syntax.
34
46
  email: jdugan@coroutine.com
35
47
  executables: []
36
48
 
@@ -44,10 +56,10 @@ files:
44
56
  - README.rdoc
45
57
  - Rakefile
46
58
  - VERSION
47
- - acts_as_list_with_sti_support-0.1.0.gem
48
59
  - acts_as_list_with_sti_support.gemspec
49
60
  - init.rb
50
61
  - lib/acts_as_list_with_sti_support.rb
62
+ - lib/acts_as_list_with_sti_support/base.rb
51
63
  - test/acts_as_list_with_sti_support_test.rb
52
64
  - test/test_helper.rb
53
65
  has_rdoc: true