Class: MTK::Patterns::Pattern Abstract

Inherits:
Object
  • Object
show all
Includes:
Groups::Collection
Defined in:
lib/mtk/patterns/pattern.rb

Overview

This class is abstract.

Subclass and override #advance to implement a Pattern.

A pattern of elements that can be emitted one element at a time via calls to #next.

Patterns can be reset to the beginning via #rewind.

Direct Known Subclasses

Chain, Choice, ForEach, Function, Lines, Sequence

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Groups::Collection

#==, #[], #clone, #concat, #each, #enumerable_map, #first, #last, #map, #partition, #permute, #repeat, #reverse, #rotate, #size, #to_a

Constructor Details

#initialize(elements, options = {}) ⇒ Pattern

Returns a new instance of Pattern.

Parameters:

  • elements (Enumerable)

    the list of elements in the pattern

  • options (Hash) (defaults to: {})

    the pattern options

Options Hash (options):

  • :max_elements (Fixnum)

    the #max_elements (default is nil, which means unlimited)

  • :max_cycles (Fixnum)

    the #max_cycles (default is 1)



42
43
44
45
46
47
48
49
50
# File 'lib/mtk/patterns/pattern.rb', line 42

def initialize(elements, options={})
  elements = elements.to_a if elements.is_a? Enumerable
  @elements = elements
  @options = options
  @min_elements = options[:min_elements]
  @max_elements = options[:max_elements]
  @max_cycles = options.fetch(:max_cycles, 1)
  rewind
end

Instance Attribute Details

#cycle_countObject (readonly)

The number of cycles emitted (1 cycle == all elements emitted) since the last #rewind



32
33
34
# File 'lib/mtk/patterns/pattern.rb', line 32

def cycle_count
  @cycle_count
end

#element_countObject (readonly)

The number of elements emitted since the last #rewind



19
20
21
# File 'lib/mtk/patterns/pattern.rb', line 19

def element_count
  @element_count
end

#elementsObject (readonly)

The elements in the pattern



14
15
16
# File 'lib/mtk/patterns/pattern.rb', line 14

def elements
  @elements
end

#max_cyclesObject (readonly)

The maximum number of cycles this Pattern will emit before a StopIteration exception. A nil value means inifinite cycles.



36
37
38
# File 'lib/mtk/patterns/pattern.rb', line 36

def max_cycles
  @max_cycles
end

#max_elementsObject (readonly)

Note:

#max_cycles may cause this Pattern to end before max_elements are emitted. If this is undesirable then use min_elements to override max_cycles.

The maximum number of elements this Pattern will emit before a StopIteration exception A nil value means infinite elements.



29
30
31
# File 'lib/mtk/patterns/pattern.rb', line 29

def max_elements
  @max_elements
end

#min_elementsObject (readonly)

The minimum number of elements this Pattern will emit before a StopIteration exception This overrides any conflicting max_cycles setting.



23
24
25
# File 'lib/mtk/patterns/pattern.rb', line 23

def min_elements
  @min_elements
end

#optionsObject (readonly)

Returns the value of attribute options.



16
17
18
# File 'lib/mtk/patterns/pattern.rb', line 16

def options
  @options
end

Class Method Details

.from_a(elements, options = {}) ⇒ Object

Construct a pattern from an Array.

Parameters:

  • elements (Enumerable)

    the list of elements in the pattern

  • options (Hash) (defaults to: {})

    the pattern options

Options Hash (options):

  • :max_elements (Fixnum)

    the #max_elements (default is nil, which means unlimited)

  • :max_cycles (Fixnum)

    the #max_cycles (default is 1)

See Also:



56
57
58
# File 'lib/mtk/patterns/pattern.rb', line 56

def self.from_a(elements, options={})
  new(elements, options)
end

Instance Method Details

#advanceObject (protected)

Update internal state (index, etc) and set @current to the next element.



134
135
136
# File 'lib/mtk/patterns/pattern.rb', line 134

def advance
  @current = elements[0]
end

#empty?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/mtk/patterns/pattern.rb', line 108

def empty?
  @elements.nil? or @elements.empty?
end

#max_cycles_exceeded?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/mtk/patterns/pattern.rb', line 104

def max_cycles_exceeded?
  @max_cycles and @cycle_count >= @max_cycles
end

#max_elements_exceeded?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/mtk/patterns/pattern.rb', line 100

def max_elements_exceeded?
  @max_elements and @element_count >= @max_elements
end

#min_elements_unmet?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/mtk/patterns/pattern.rb', line 96

def min_elements_unmet?
  @min_elements and @element_count < @min_elements
end

#nextObject

Emit the next element in the pattern

Raises:

  • StopIteration when the pattern has emitted all values, or has hit the #max_elements limit.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/mtk/patterns/pattern.rb', line 68

def next
  raise StopIteration if empty?

  if @current.is_a? Pattern
    begin
      return emit(@current.next)
    rescue StopIteration
      raise if max_elements_exceeded?
      # else fall through and continue with normal behavior
    end
  end

  begin
    advance
  rescue StopIteration
    rewind_or_cycle(true)
    return self.next
  end

  if @current.kind_of? Pattern
    @current.rewind # ensure nested patterns start from the beginning each time they are encountered
    return self.next
  end

  emit(@current)
end

#rewindObject

Reset the pattern to the beginning



61
62
63
64
# File 'lib/mtk/patterns/pattern.rb', line 61

def rewind
  rewind_or_cycle
  self
end

#rewind_or_cycle(is_cycling = false) ⇒ Object (protected)

Reset the pattern to the beginning

Parameters:

  • is_cycling (Boolean) (defaults to: false)

    true when #next is performing a cycle back to the beginning of the Pattern. false for a normal #rewind



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/mtk/patterns/pattern.rb', line 117

def rewind_or_cycle(is_cycling=false)
  @current = nil
  @index = -1

  # and rewind child patterns
  @elements.each{|element| element.rewind if element.is_a? Pattern }

  if is_cycling
    @cycle_count += 1
    raise StopIteration if max_cycles_exceeded? and not min_elements_unmet?
  else
    @element_count = 0
    @cycle_count = 0
  end
end