dm-is-list 0.9.5 → 0.9.6

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/Rakefile CHANGED
@@ -45,5 +45,5 @@ end
45
45
  desc 'Run specifications'
46
46
  Spec::Rake::SpecTask.new(:spec) do |t|
47
47
  t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
48
- t.spec_files = Pathname.glob(Pathname.new(__FILE__).dirname + 'spec/**/*_spec.rb')
48
+ t.spec_files = Pathname.glob((ROOT + 'spec/**/*_spec.rb').to_s)
49
49
  end
@@ -2,10 +2,10 @@
2
2
  require 'rubygems'
3
3
  require 'pathname'
4
4
 
5
- gem 'dm-core', '=0.9.5'
5
+ gem 'dm-core', '=0.9.6'
6
6
  require 'dm-core'
7
7
 
8
- gem 'dm-adjust', '=0.9.5'
8
+ gem 'dm-adjust', '=0.9.6'
9
9
  require 'dm-adjust'
10
10
 
11
11
  require Pathname(__FILE__).dirname.expand_path / 'dm-is-list' / 'is' / 'list.rb'
@@ -19,31 +19,32 @@ module DataMapper
19
19
  # @option :scope<Array> an array of attributes that should be used to scope lists
20
20
  #
21
21
  def is_list(options={})
22
- options = { :scope => [] }.merge(options)
22
+ options = { :scope => [], :first => 1 }.merge(options)
23
23
 
24
24
  extend DataMapper::Is::List::ClassMethods
25
25
  include DataMapper::Is::List::InstanceMethods
26
26
 
27
27
  property :position, Integer unless properties.detect{|p| p.name == :position && p.type == Integer}
28
28
 
29
- @list_scope = options[:scope]
29
+ @list_options = options
30
30
 
31
31
  before :save do
32
32
  if self.new_record?
33
33
  # a position has been set before save => open up and make room for item
34
34
  # no position has been set => move to bottom of my scope-list (or keep detached?)
35
- self.position ? self.move_without_saving(:to => self.position) : self.move_without_saving(:lowest)
35
+ self.send(:move_without_saving, (self.position || :lowest))
36
36
  else
37
37
  # if the scope has changed, we need to detach our item from the old list
38
38
  if self.list_scope != self.original_list_scope
39
- oldpos = self.original_values[:position]
40
39
  newpos = self.position
41
40
 
42
41
  self.detach(self.original_list_scope) # removing from old list
43
- self.move_without_saving(oldpos ? {:to => newpos} : :lowest) # moving to pos or bottom of new list
42
+ self.send(:move_without_saving, newpos || :lowest) # moving to pos or bottom of new list
44
43
 
45
- elsif self.attribute_dirty?(:position)
46
- self.move_without_saving(:to => self.position)
44
+ elsif self.attribute_dirty?(:position) && !self.moved
45
+ self.send(:move_without_saving, self.position)
46
+ else
47
+ self.moved = false
47
48
  end
48
49
  # a (new) position has been set => move item to this position (only if position has been set manually)
49
50
  # the scope has changed => detach from old list, and possibly move into position
@@ -57,13 +58,13 @@ module DataMapper
57
58
 
58
59
  # we need to make sure that STI-models will inherit the list_scope.
59
60
  after_class_method :inherited do |retval, target|
60
- target.instance_variable_set(:@list_scope, @list_scope.dup)
61
+ target.instance_variable_set(:@list_options, @list_options.dup)
61
62
  end
62
63
 
63
64
  end
64
65
 
65
66
  module ClassMethods
66
- attr_reader :list_scope
67
+ attr_reader :list_options
67
68
 
68
69
  ##
69
70
  # use this function to repair / build your lists.
@@ -75,19 +76,20 @@ module DataMapper
75
76
  # @param scope [Hash]
76
77
  #
77
78
  def repair_list(scope={})
78
- return false unless scope.keys.all?{|s| list_scope.include?(s) || s == :order }
79
+ return false unless scope.keys.all?{|s| list_options[:scope].include?(s) || s == :order }
79
80
  all({:order => [:position.asc]}.merge(scope)).each_with_index{ |item,i| item.position = i+1; item.save }
80
81
  end
81
82
  end
82
83
 
83
84
  module InstanceMethods
85
+ attr_accessor :moved
84
86
 
85
87
  def list_scope
86
- self.class.list_scope.map{|p| [p,attribute_get(p)]}.to_hash
88
+ self.class.list_options[:scope].map{|p| [p,attribute_get(p)]}.to_hash
87
89
  end
88
90
 
89
91
  def original_list_scope
90
- self.class.list_scope.map{|p| [p,original_values.key?(p) ? original_values[p] : attribute_get(p)]}.to_hash
92
+ self.class.list_options[:scope].map{|p| [p,original_values.key?(p) ? original_values[p] : attribute_get(p)]}.to_hash
91
93
  end
92
94
 
93
95
  def list_query
@@ -112,6 +114,19 @@ module DataMapper
112
114
  self.class.repair_list(list_scope.merge(:order => order))
113
115
  end
114
116
 
117
+ def detach(scope=list_scope)
118
+ list(scope).all(:position.gt => position).adjust!({:position => -1},true)
119
+ self.position = nil
120
+ end
121
+
122
+ def left_sibling
123
+ list.reverse.first(:position.lt => position)
124
+ end
125
+
126
+ def right_sibling
127
+ list.first(:position.gt => position)
128
+ end
129
+
115
130
  ##
116
131
  # move item to a position in the list. position should _only_ be changed through this
117
132
  #
@@ -143,52 +158,41 @@ module DataMapper
143
158
  # does all the actual movement in #move, but does not save afterwards. this is used internally in
144
159
  # before :save, and will probably be marked private. should not be used by organic beings.
145
160
  #
146
- # @see move_without_saving
161
+ # @see move
162
+ private
147
163
  def move_without_saving(vector)
148
164
  if vector.is_a? Hash then action,object = vector.keys[0],vector.values[0] else action = vector end
149
165
 
150
- prepos = self.original_values[:position]||self.position
151
- maxpos = list.last ? (list.last == self ? prepos : list.last.position + 1) : 1
166
+ minpos = self.class.list_options[:first]
167
+ prepos = self.original_values[:position] || self.position
168
+ maxpos = list.last ? (list.last == self ? prepos : list.last.position + 1) : minpos
152
169
  newpos = case action
153
- when :highest then 1
170
+ when :highest then minpos
154
171
  when :lowest then maxpos
155
- when :higher,:up then [position-1,1].max
172
+ when :higher,:up then [position-1,minpos].max
156
173
  when :lower,:down then [position+1,maxpos].min
157
174
  when :above then object.position
158
175
  when :below then object.position+1
159
- when :to then [object.to_i,maxpos].min
176
+ when :to then [minpos,[object.to_i,maxpos].min].max
177
+ else [action.to_i,maxpos].min
160
178
  end
161
179
 
162
180
  return false if !newpos || ([:above,:below].include?(action) && list_scope != object.list_scope)
163
- return true if newpos == position || (newpos == maxpos && position == maxpos-1)
181
+ return true if newpos == position && position == prepos || (newpos == maxpos && position == maxpos-1)
164
182
 
165
183
  if !position
166
184
  list.all(:position.gte => newpos).adjust!({:position => +1},true) unless action == :lowest
167
- elsif newpos > position
185
+ elsif newpos > prepos
168
186
  newpos -= 1 if [:lowest,:above,:below,:to].include?(action)
169
- list.all(:position => position..newpos).adjust!({:position => -1},true)
170
- elsif newpos < position
171
- list.all(:position => newpos..position).adjust!({:position => +1},true)
187
+ list.all(:position => prepos..newpos).adjust!({:position => -1},true)
188
+ elsif newpos < prepos
189
+ list.all(:position => newpos..prepos).adjust!({:position => +1},true)
172
190
  end
173
191
 
174
192
  self.position = newpos
175
-
193
+ self.moved = true
176
194
  true
177
195
  end
178
-
179
- def detach(scope=list_scope)
180
- list(scope).all(:position.gt => position).adjust!({:position => -1},true)
181
- self.position = nil
182
- end
183
-
184
- def left_sibling
185
- list.reverse.first(:position.lt => position)
186
- end
187
-
188
- def right_sibling
189
- list.first(:position.gt => position)
190
- end
191
-
192
196
  end
193
197
  end # List
194
198
  end # Is
@@ -1,7 +1,7 @@
1
1
  module DataMapper
2
2
  module Is
3
3
  module List
4
- VERSION = "0.9.5"
4
+ VERSION = "0.9.6"
5
5
  end
6
6
  end
7
7
  end
@@ -57,15 +57,23 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
57
57
  Todo.get(6).position.should == 3
58
58
  end
59
59
  end
60
+
61
+ it 'should rearrange items when setting position yourself' do
62
+ repository(:default) do |repos|
63
+ Todo.get(2).update_attributes(:position => 1)
64
+ Todo.get(2).position.should == 1
65
+ Todo.get(1).position.should == 2
66
+ end
67
+ end
60
68
  end
61
69
 
62
70
  describe 'movement' do
63
71
  it 'should rearrange items correctly when moving :higher' do
64
72
  repository(:default) do |repos|
65
73
  Todo.get(3).move :higher
74
+ Todo.get(4).position.should == 1
66
75
  Todo.get(3).position.should == 2
67
76
  Todo.get(2).position.should == 3
68
- Todo.get(4).position.should == 1
69
77
  end
70
78
  end
71
79
 
@@ -128,7 +136,9 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
128
136
  item.user_id = 1
129
137
  item.save
130
138
 
131
- item.position.should == 4
139
+ item.list_scope.should != item.original_list_scope
140
+ item.position.should == 1
141
+ Todo.get(1).position.should == 2
132
142
  Todo.get(5).position.should == 1
133
143
 
134
144
  item.user_id = 2
@@ -10,7 +10,7 @@ def load_driver(name, default_uri)
10
10
  lib = "do_#{name}"
11
11
 
12
12
  begin
13
- gem lib, '=0.9.5'
13
+ gem lib, '>=0.9.5'
14
14
  require lib
15
15
  DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
16
16
  DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-is-list
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sindre Aarsaether
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-08-26 00:00:00 -05:00
12
+ date: 2008-10-12 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - "="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.9.5
23
+ version: 0.9.6
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: hoe