Module: Hyrarchy::AwesomeNestedSetCompatibility::InstanceMethods

Included in:
InstanceMethods
Defined in:
lib/hyrarchy/awesome_nested_set_compatibility.rb

Instance Method Summary collapse

Instance Method Details

#<=>(x) ⇒ Object

Compares two nodes by their left values.



109
110
111
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 109

def <=>(x)
  x.left <=> left
end

#child?Boolean

Returns true if this node is a child of another node.

Returns:

  • (Boolean)


104
105
106
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 104

def child?
  !root?
end

#is_ancestor_of?(other) ⇒ Boolean

Returns true if this node is an ancestor of other.

Returns:

  • (Boolean)


247
248
249
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 247

def is_ancestor_of?(other)
  other.left > left && other.left <= right
end

#is_descendant_of?(other) ⇒ Boolean

Returns true if this node is a descendant of other.

Returns:

  • (Boolean)


236
237
238
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 236

def is_descendant_of?(other)
  left > other.left && left <= other.right
end

#is_or_is_ancestor_of?(other) ⇒ Boolean

Returns true if this node is an ancestor of other, or if this node is other.

Returns:

  • (Boolean)


253
254
255
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 253

def is_or_is_ancestor_of?(other)
  other.left >= left && other.left <= right
end

#is_or_is_descendant_of?(other) ⇒ Boolean

Returns true if this node is a descendant of other, or if this node is other.

Returns:

  • (Boolean)


242
243
244
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 242

def is_or_is_descendant_of?(other)
  left >= other.left && left <= other.right
end

#leaf?Boolean

Returns true if this node has no children.

Returns:

  • (Boolean)


99
100
101
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 99

def leaf?
  children.empty?
end

#leavesObject

Returns an array containing this node’s childless descendants. The array returned by this method is a named scope.



157
158
159
160
161
162
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 157

def leaves
  cached[:leaves] ||= descendants.scoped :conditions => "NOT EXISTS (
    SELECT * FROM #{self.class.quoted_table_name} tt
    WHERE tt.parent_id = #{self.class.quoted_table_name}.id
  )"
end

#leftObject

Returns this node’s left value. Records that haven’t yet been saved won’t have left values.



83
84
85
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 83

def left
  encoded_path
end

#left_siblingObject

Returns the sibling before this node. If this node is its parent’s first child, returns nil.



266
267
268
269
270
271
272
273
274
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 266

def left_sibling # :nodoc:
  path = send(:encoded_path)
  return nil if path == path.parent.first_child
  sibling_path = path.previous_sibling
  until self.class.exists?(:lft_numer => sibling_path.numerator, :lft_denom => sibling_path.denominator)
    sibling_path = sibling_path.previous_sibling
  end
  self.class.send(:find_by_encoded_path, sibling_path)
end

#levelObject

Alias for depth.



165
166
167
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 165

def level
  depth
end

#move_leftObject

:nodoc:

Raises:

  • (NotImplementedError)


288
289
290
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 288

def move_left # :nodoc:
  raise NotImplementedError, "awesome_nested_set's move_left method isn't implemented in this version of Hyrarchy"
end

#move_possible?(target) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


363
364
365
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 363

def move_possible?(target) # :nodoc:
  raise NotImplementedError, "awesome_nested_set's move_possible? method isn't implemented in this version of Hyrarchy"
end

#move_rightObject

:nodoc:

Raises:

  • (NotImplementedError)


292
293
294
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 292

def move_right # :nodoc:
  raise NotImplementedError, "awesome_nested_set's move_right method isn't implemented in this version of Hyrarchy"
end

#move_to_child_of(node) ⇒ Object

Sets this node’s parent to node and calls save!.



351
352
353
354
355
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 351

def move_to_child_of(node)
  node = self.class.find(node)
  self.parent = node
  save!
end

#move_to_left_of(other) ⇒ Object

The semantics of left and right don’t quite map exactly from awesome_nested_set to Hyrarchy. For the purpose of this method, “left” means “before.”

If this node isn’t a sibling of other, its parent will be set to other‘s parent.



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 302

def move_to_left_of(other)
  # Don't attempt an impossible move.
  if other.is_descendant_of?(self)
    raise ArgumentError, "you can't move a node to the left of one of its descendants"
  end
  # Find the first unused path after +other+'s path.
  open_path = other.send(:encoded_path).next_sibling
  while self.class.exists?(:lft_numer => open_path.numerator, :lft_denom => open_path.denominator)
    open_path = open_path.next_sibling
  end
  # Move +other+, and all nodes following it, down.
  while open_path != other.send(:encoded_path)
    p = open_path.previous_sibling
    n = self.class.send(:find_by_encoded_path, p)
    n.send(:encoded_path=, open_path)
    n.save!
    open_path = p
  end
  puts open_path
  # Insert this node.
  send(:encoded_path=, open_path)
  save!
end

#move_to_right_of(other) ⇒ Object

The semantics of left and right don’t quite map exactly from awesome_nested_set to Hyrarchy. For the purpose of this method, “right” means “after.”

If this node isn’t a sibling of other, its parent will be set to other‘s parent.



332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 332

def move_to_right_of(other)
  # Don't attempt an impossible move.
  if other.is_descendant_of?(self)
    raise ArgumentError, "you can't move a node to the right of one of its descendants"
  end
  # If +other+ is its parent's last child, we can simply append this node
  # to the parent's children.
  siblings = other.root? ? self.class.roots : other.parent.children
  if other == siblings.last
    send(:encoded_path=, other.send(:encoded_path).next_sibling)
    save!
  else
    # Otherwise, this is equivalent to moving this node to the left of
    # +other+'s right sibling.
    move_to_left_of(other.right_sibling)
  end
end

#move_to_rootObject

Makes this node a root node and calls save!.



358
359
360
361
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 358

def move_to_root
  self.parent = nil
  save!
end

#rightObject

Returns this node’s left value. Records that haven’t yet been saved won’t have right values.



89
90
91
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 89

def right
  encoded_path && encoded_path.next_farey_fraction
end

#right_siblingObject

Returns the sibling after this node. If this node is its parent’s last child, returns nil.



278
279
280
281
282
283
284
285
286
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 278

def right_sibling
  siblings = root? ? self.class.roots : other.parent.children
  return nil if self == siblings.last
  sibling_path = send(:encoded_path).next_sibling
  until self.class.exists?(:lft_numer => sibling_path.numerator, :lft_denom => sibling_path.denominator)
    sibling_path = sibling_path.next_sibling
  end
  self.class.send(:find_by_encoded_path, sibling_path)
end

#root?Boolean

Returns true if this is a root node.

Returns:

  • (Boolean)


94
95
96
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 94

def root?
  (encoded_path.nil? || depth == 0 || @make_root) && !@new_parent
end

#same_scope?(other) ⇒ Boolean

Always returns true. This method exists solely for compatibility with awesome_nested_set; Hyrarchy doesn’t support scoping (but maybe it will some day).

Returns:

  • (Boolean)


260
261
262
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 260

def same_scope?(other)
  true
end

#self_and_ancestorsObject

Returns an array containing this node and its ancestors, starting with this node and ending with its root. The array returned by this method is a has_many association, so you can do things like this:

node.self_and_ancestors.find(:all, :conditions => { ... })


119
120
121
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 119

def self_and_ancestors
  ancestors(true)
end

#self_and_descendantsObject

Returns an array of this node and its descendants: its children, grandchildren, and so on. The array returned by this method is a has_many association, so you can do things like this:

node.self_and_descendants.find(:all, :conditions => { ... })


175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 175

def self_and_descendants
  cached[:self_and_descendants] ||= CollectionProxy.new(
    self,
    :descendants,
    :conditions => { :lft => (lft - FLOAT_FUDGE_FACTOR)..(rgt + FLOAT_FUDGE_FACTOR) },
    :order => 'rgt DESC, lft',
    # The query conditions intentionally load extra records that aren't
    # descendants to account for floating point imprecision. This
    # procedure removes the extra records.
    :after => Proc.new do |records|
      r = encoded_path.next_farey_fraction
      records.delete_if do |n|
        n.encoded_path < encoded_path || n.encoded_path >= r
      end
    end,
    # The regular count method doesn't work because of the fudge factor
    # in the conditions. This procedure uses the length of the records
    # array if it's been loaded. Otherwise it does a raw SQL query (to
    # avoid the expense of instantiating a bunch of ActiveRecord objects)
    # and prunes the results in the same manner as the :after procedure.
    :count => Proc.new do
      if descendants.loaded?
        descendants.length
      else
        rows = self.class.connection.select_all("
          SELECT lft_numer, lft_denom
          FROM #{self.class.quoted_table_name}
          WHERE #{descendants.conditions}")
        r = encoded_path.next_farey_fraction
        rows.delete_if do |row|
          p = Hyrarchy::EncodedPath(
            row['lft_numer'].to_i,
            row['lft_denom'].to_i)
          p < encoded_path || p >= r
        end
        rows.length
      end
    end,
    # Associations don't normally have an optimized index method, but
    # this one does. :)
    :index => Proc.new do |obj|
      rows = self.class.connection.select_all("
        SELECT id, lft_numer, lft_denom
        FROM #{self.class.quoted_table_name}
        WHERE #{descendants.conditions}
        ORDER BY rgt DESC, lft")
      r = encoded_path.next_farey_fraction
      rows.delete_if do |row|
        p = Hyrarchy::EncodedPath(
          row['lft_numer'].to_i,
          row['lft_denom'].to_i)
        row.delete('lft_numer')
        row.delete('lft_denom')
        p < encoded_path || p >= r
      end
      rows.index({'id' => obj.id.to_s})
    end
  )
end

#self_and_siblingsObject

Returns an array containing this node and its siblings. The array returned by this method is a has_many association, so you can do things like this:

node.self_and_siblings.find(:all, :conditions => { ... })


129
130
131
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 129

def self_and_siblings
  siblings(true)
end

#siblings(with_self = false) ⇒ Object

Returns an array containing this node’s siblings. The array returned by this method is a has_many association, so you can do things like this:

node.siblings.find(:all, :conditions => { ... })


138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 138

def siblings(with_self = false)
  cache_key = with_self ? :self_and_siblings : :siblings
  return cached[cache_key] if cached[cache_key]

  if with_self
    conditions = { :parent_id => parent_id }
  else
    conditions = ["parent_id #{parent_id.nil? ? 'IS' : '='} ? AND id <> ?",
      parent_id, id]
  end

  cached[cache_key] = self.class.scoped(
    :conditions => conditions,
    :order      => 'rgt DESC, lft'
  )
end

#to_textObject

Returns a textual representation of this node and its descendants.



368
369
370
371
372
# File 'lib/hyrarchy/awesome_nested_set_compatibility.rb', line 368

def to_text
  self_and_descendants.map do |node|
    "#{'*'*(node.depth+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})"
  end.join("\n")
end