Skip to content

Instantly share code, notes, and snippets.

@havenwood
Last active November 13, 2019 18:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save havenwood/85734cd9a9db1cbbdfbb845467544e49 to your computer and use it in GitHub Desktop.
Save havenwood/85734cd9a9db1cbbdfbb845467544e49 to your computer and use it in GitHub Desktop.
Playing with Enumerator.produce from Ruby 2.7
# frozen_string_literal: true
class Node
attr_reader :value
attr_reader :parent
def initialize(value:, parent: nil)
@value = value
@parent = parent
end
def ancestors
return [] unless @parent
Enumerator.produce @parent do |child|
child.parent || raise(StopIteration)
end.to_a
end
end
require 'minitest/autorun'
describe Node do
let(:parent) { Node.new value: 42 }
let(:child) { Node.new parent: parent, value: 22 }
let(:grandchild) { Node.new parent: child, value: 2 }
describe 'values' do
it 'has a value' do
assert_equal 42, parent.value
assert_equal 22, child.value
assert_equal 2, grandchild.value
end
end
describe 'parents' do
describe 'a very long chain' do
it 'does not blow up' do
high_number = 20_000
variables = ('a'..).take(high_number)
variables.each_cons(2) do |a, b|
instance_variable_set "@#{b}", Node.new(value: b, parent: instance_variable_get("@#{a}"))
end
assert_equal high_number - 2, instance_variable_get("@#{variables.last}").ancestors.size
end
end
describe 'the first generation' do
it 'has no parent' do
assert_nil parent.parent
end
it 'has no ancestry' do
assert_empty parent.ancestors
end
end
describe 'a grandchild' do
it 'has a parent' do
assert_equal child, grandchild.parent
end
describe 'ancestors' do
it 'has two ancestors' do
assert_equal 2, grandchild.ancestors.size
end
it 'lists the child first' do
assert_equal child, grandchild.ancestors.first
end
it 'lists the parent last' do
assert_equal parent, grandchild.ancestors.last
end
end
end
end
end
@3limin4t0r
Copy link

I would use something like:

def ancestors
  return [] unless parent
  parent.ancestors << parent
end

@havenwood
Copy link
Author

Only downside would be it blowing up with really long chains. For the same order:

parent.ancestors.prepend parent

@3limin4t0r
Copy link

Or using a while loop:

def ancestors
  node = self
  ancestors = []
  ancestors << node while (node = node.parent)
  ancestors
end

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