Class: PropCheck::LazyTree

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/prop_check/lazy_tree.rb

Overview

A Rose tree with the root being eager, and the children computed lazily, on demand.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root, children = [].lazy) ⇒ LazyTree

Returns a new instance of LazyTree.


13
14
15
16
# File 'lib/prop_check/lazy_tree.rb', line 13

def initialize(root, children = [].lazy)
  @root = root
  @children = children
end

Instance Attribute Details

#rootObject

Returns the value of attribute root


12
13
14
# File 'lib/prop_check/lazy_tree.rb', line 12

def root
  @root
end

Class Method Details

.wrap(val) ⇒ Object

LazyTree.new(root_root, combined_children) end


50
51
52
# File 'lib/prop_check/lazy_tree.rb', line 50

def self.wrap(val)
  LazyTree.new(val)
end

.zip(trees) ⇒ Object

TODO: fix implementation


102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/prop_check/lazy_tree.rb', line 102

def self.zip(trees)
  # p "TREES: "
  # p trees.to_a
  # p "END TREES"
  # raise "Boom!" unless trees.to_a.is_a?(Array) && trees.to_a.first.is_a?(LazyTree)
  # p self
  new_root = trees.to_a.map(&:root)
  # p new_root
  # new_children = trees.permutations.flat_map(&:children)
  new_children = permutations(trees).map { |children| LazyTree.zip(children) }
  # p new_children
  LazyTree.new(new_root, new_children)
end

Instance Method Details

#bind(&fun) ⇒ Object


54
55
56
57
58
59
60
61
62
63
# File 'lib/prop_check/lazy_tree.rb', line 54

def bind(&fun)
  inner_tree = fun.call(root)
  inner_root = inner_tree.root
  inner_children = inner_tree.children
  mapped_children = children.map { |child| child.bind(&fun) }

  combined_children = PropCheck::Helper.lazy_append(inner_children, mapped_children)

  LazyTree.new(inner_root, combined_children)
end

#childrenObject


18
19
20
# File 'lib/prop_check/lazy_tree.rb', line 18

def children
  @children.reject { |child| child.root == :"_PropCheck.filter_me" }
end

#each(&block) ⇒ Object

Turns a LazyTree in a long lazy enumerable, with the root first followed by its children (and the first children's result before later children; i.e. a depth-first traversal.)

Be aware that this lazy enumerable is potentially infinite, possibly uncountably so.

>> LazyTree.new(1, [LazyTree.new(2, [LazyTree.new(3)]), LazyTree.new(4)]).each.force
=> [1, 4, 2, 3]

74
75
76
77
78
79
# File 'lib/prop_check/lazy_tree.rb', line 74

def each(&block)
  self.to_enum(:each) unless block_given?

  squish([])
  .each(&block)
end

#map(&block) ⇒ Object

Maps `block` eagerly over `root` and lazily over `children`, returning a new LazyTree as result.

>> LazyTree.new(1, [LazyTree.new(2, [LazyTree.new(3)]), LazyTree.new(4)]).map(&:next).to_a
=> LazyTree.new(2, [LazyTree.new(3, [LazyTree.new(4)]), LazyTree.new(5)]).to_a

27
28
29
30
31
# File 'lib/prop_check/lazy_tree.rb', line 27

def map(&block)
  new_root = block.call(root)
  new_children = children.map { |child_tree| child_tree.map(&block) }
  LazyTree.new(new_root, new_children)
end

#to_aObject

Fully evaluate the LazyTree into an eager array, with the root first followed by its children (and the first children's result before later children; i.e. a depth-first traversal.)

Be aware that calling this might make Ruby attempt to evaluate an infinite collection. Therefore, it is mostly useful for debugging; in production you probably want to use the other mechanisms this class provides..

>> LazyTree.new(1, [LazyTree.new(2, [LazyTree.new(3)]), LazyTree.new(4)]).to_a
=> [1, 4, 2, 3]

96
97
98
99
# File 'lib/prop_check/lazy_tree.rb', line 96

def to_a
  each
    .force
end