Skip to content

Instantly share code, notes, and snippets.

@rmg
Last active December 19, 2015 12:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmg/5953543 to your computer and use it in GitHub Desktop.
Save rmg/5953543 to your computer and use it in GitHub Desktop.
Lineage: Tap into the latent enumerable powers of your class's directed graph!
require 'set'
def Lineage(enum_name = :lineage, parent_accessor = :parent)
Module.new do
define_method enum_name do |&block|
if block.nil?
enum_for(enum_name)
else
next_parent, visited = self, Set[self]
while next_parent = next_parent.send(parent_accessor)
if visited.include? next_parent
raise "Cycle detected!"
end
block.yield next_parent
visited << next_parent
end
end
end
end
end
module Lineage
include Lineage()
end
# A simple example
class Person < Struct.new(:name, :parent)
include Lineage
end
youngest = Person.new("Adam", nil)
(1..10).each do |n|
youngest = Person.new(n.to_s, youngest)
end
youngest.name #=> "10"
youngest.lineage.map(&:name) #=> ["9", "8", "7", "6", "5", "4", "3", "2", "1", "Adam"]
@rmg
Copy link
Author

rmg commented Jul 9, 2013

The #lineage method this mixin provides yields or returns an Enumerator, which lets you do all the cool enumeration stuff like map, reduce, select, each, to_a, etc..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment