DanaDanger-hyrarchy 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -60,7 +60,6 @@ module Hyrarchy
60
60
  return true if (valid? rescue false)
61
61
 
62
62
  update_all("lft = id, rgt = id, lft_numer = id, lft_denom = id")
63
- reset_all_free_child_paths
64
63
  paths_by_id = {}
65
64
  order_by = columns_hash['created_at'] ? :created_at : :id
66
65
 
@@ -210,6 +209,25 @@ module Hyrarchy
210
209
  end
211
210
  rows.length
212
211
  end
212
+ end,
213
+ # Associations don't normally have an optimized index method, but
214
+ # this one does. :)
215
+ :index => Proc.new do |obj|
216
+ rows = self.class.connection.select_all("
217
+ SELECT id, lft_numer, lft_denom
218
+ FROM #{self.class.quoted_table_name}
219
+ WHERE #{descendants.conditions}
220
+ ORDER BY rgt DESC, lft")
221
+ r = encoded_path.next_farey_fraction
222
+ rows.delete_if do |row|
223
+ p = Hyrarchy::EncodedPath(
224
+ row['lft_numer'].to_i,
225
+ row['lft_denom'].to_i)
226
+ row.delete('lft_numer')
227
+ row.delete('lft_denom')
228
+ p < encoded_path || p >= r
229
+ end
230
+ rows.index({'id' => obj.id.to_s})
213
231
  end
214
232
  )
215
233
  end
@@ -7,6 +7,7 @@ module Hyrarchy
7
7
  def initialize(owner, name, options = {})
8
8
  @after = options.delete(:after)
9
9
  @count = options.delete(:count)
10
+ @index = options.delete(:index)
10
11
  reflection = ActiveRecord::Base.create_reflection(
11
12
  :has_many, name, options.merge(:class_name => owner.class.to_s), owner.class)
12
13
  super(owner, reflection)
@@ -52,6 +53,15 @@ module Hyrarchy
52
53
  end
53
54
  end
54
55
 
56
+ # Overrides index to run the association's +index+ procedure.
57
+ def index(obj)
58
+ if @index && !loaded?
59
+ @index.call(obj)
60
+ else
61
+ super
62
+ end
63
+ end
64
+
55
65
  protected
56
66
 
57
67
  # Overrides find_target to run the association's +after+ procedure on the
data/lib/hyrarchy.rb CHANGED
@@ -80,7 +80,7 @@ module Hyrarchy
80
80
 
81
81
  before_save :set_encoded_paths
82
82
  before_save :set_parent_id
83
- after_destroy :mark_path_free
83
+ after_save :update_descendant_paths
84
84
 
85
85
  named_scope :roots,
86
86
  :conditions => { :parent_id => nil },
@@ -96,41 +96,17 @@ module Hyrarchy
96
96
 
97
97
  private
98
98
 
99
- # Returns an array of unused child paths beneath +parent_path+.
100
- def free_child_paths(parent_path)
101
- @@free_child_paths ||= {}
102
- @@free_child_paths[parent_path] ||= []
103
- end
104
-
105
- # Stores +path+ in the arrays of free child paths.
106
- def child_path_is_free(path)
107
- parent_path = path.parent(false)
108
- free_child_paths(parent_path) << path
109
- free_child_paths(parent_path).sort!
110
- end
111
-
112
- # Removes all paths from the array of free child paths for +parent_path+.
113
- def reset_free_child_paths(parent_path)
114
- free_child_paths(parent_path).clear
115
- end
116
-
117
- # Removes all paths from the array of free child paths.
118
- def reset_all_free_child_paths
119
- @@free_child_paths = {}
120
- end
121
-
122
99
  # Finds the first unused child path beneath +parent_path+.
123
100
  def next_child_encoded_path(parent_path)
124
- p = free_child_paths(parent_path).shift || parent_path.first_child
125
- while true do
126
- if exists?(:lft_numer => p.numerator, :lft_denom => p.denominator)
127
- p = parent_path.mediant(p)
101
+ if parent_path == Hyrarchy::EncodedPath::ROOT
102
+ if sibling = roots.last
103
+ sibling.send(:encoded_path).next_sibling
128
104
  else
129
- if free_child_paths(parent_path).empty?
130
- child_path_is_free(parent_path.mediant(p))
131
- end
132
- return p
105
+ Hyrarchy::EncodedPath::ROOT.first_child
133
106
  end
107
+ else
108
+ node = find_by_encoded_path(parent_path)
109
+ node ? node.send(:next_child_encoded_path) : parent_path.first_child
134
110
  end
135
111
  end
136
112
 
@@ -202,7 +178,7 @@ module Hyrarchy
202
178
  paths.collect {|p| "(lft_numer = ? AND lft_denom = ?)"}.join(" OR "),
203
179
  *(paths.collect {|p| [p.numerator, p.denominator]}.flatten)
204
180
  ],
205
- :order => 'rgt DESC, lft'
181
+ :order => 'rgt, lft DESC'
206
182
  )
207
183
  end
208
184
 
@@ -249,6 +225,7 @@ module Hyrarchy
249
225
  self.lft = nil
250
226
  self.rgt = nil
251
227
  else
228
+ @path_has_changed = true
252
229
  self.lft_numer = r.numerator
253
230
  self.lft_denom = r.denominator
254
231
  self.lft = r.to_f
@@ -268,12 +245,22 @@ module Hyrarchy
268
245
  @cached ||= {}
269
246
  end
270
247
 
248
+ # Returns the first unused child path under this node.
249
+ def next_child_encoded_path
250
+ return nil unless encoded_path
251
+ if children.empty?
252
+ encoded_path.first_child
253
+ else
254
+ children.last.send(:encoded_path).next_sibling
255
+ end
256
+ end
257
+
271
258
  private
272
259
 
273
260
  # before_save callback to ensure that this node's encoded path is a child
274
- # of its parent, and that its descendants' paths are updated if this node
275
- # has moved.
261
+ # of its parent.
276
262
  def set_encoded_paths # :nodoc:
263
+ @path_has_changed = false if @path_has_changed.nil?
277
264
  p = nil
278
265
  self.lft_numer = self.lft_denom = nil if @make_root
279
266
 
@@ -287,13 +274,8 @@ module Hyrarchy
287
274
 
288
275
  if p
289
276
  new_path = self.class.send(:next_child_encoded_path, p)
290
- if encoded_path != new_path
291
- self.class.send(:reset_free_child_paths, encoded_path)
277
+ if @path_has_changed = (encoded_path != new_path)
292
278
  self.encoded_path = new_path
293
- children.each do |c|
294
- c.parent = self
295
- c.save!
296
- end
297
279
  end
298
280
  end
299
281
 
@@ -308,10 +290,19 @@ module Hyrarchy
308
290
  true
309
291
  end
310
292
 
311
- # after_destroy callback to add this node's encoded path to its parent's
312
- # list of available child paths.
313
- def mark_path_free # :nodoc:
314
- self.class.send(:child_path_is_free, encoded_path)
293
+ # after_save callback to ensure that this node's descendants are updated if
294
+ # this node has moved.
295
+ def update_descendant_paths
296
+ return true unless @path_has_changed
297
+
298
+ child_path = encoded_path.first_child
299
+ children.each do |c|
300
+ c.encoded_path = child_path
301
+ c.save!
302
+ child_path = child_path.next_sibling
303
+ end
304
+
305
+ true
315
306
  end
316
307
  end
317
308
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: DanaDanger-hyrarchy
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.1"
4
+ version: "0.2"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dana Danger
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-12-15 00:00:00 -08:00
12
+ date: 2008-12-22 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15