dm-is-list 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
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