Class: SmashTheState::Operation::Sequence

Inherits:
Object
  • Object
show all
Defined in:
lib/smash_the_state/operation/sequence.rb

Defined Under Namespace

Classes: BadOverride, StepConflict

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSequence

Returns a new instance of Sequence.



10
11
12
13
# File 'lib/smash_the_state/operation/sequence.rb', line 10

def initialize
  @steps = []
  @run_options = { dry: false }
end

Instance Attribute Details

#middleware_class_blockObject

Returns the value of attribute middleware_class_block.



7
8
9
# File 'lib/smash_the_state/operation/sequence.rb', line 7

def middleware_class_block
  @middleware_class_block
end

#run_optionsObject (readonly)

Returns the value of attribute run_options.



8
9
10
# File 'lib/smash_the_state/operation/sequence.rb', line 8

def run_options
  @run_options
end

#stepsObject (readonly)

Returns the value of attribute steps.



8
9
10
# File 'lib/smash_the_state/operation/sequence.rb', line 8

def steps
  @steps
end

Instance Method Details

#add_error_handler_for_step(step_name, &block) ⇒ Object



87
88
89
90
91
92
93
94
# File 'lib/smash_the_state/operation/sequence.rb', line 87

def add_error_handler_for_step(step_name, &block)
  step = @steps.find { |s| s.name == step_name }

  # should we raise an exception instead?
  return if step.nil?

  step.error_handler = block
end

#add_middleware_step(step_name, options = {}) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/smash_the_state/operation/sequence.rb', line 111

def add_middleware_step(step_name, options = {})
  step = Operation::Step.new step_name, options do |state, original_state|
    if middleware_class(state, original_state).nil?
      # no-op
      state
    else
      middleware_class(state, original_state).send(step_name, state, original_state)
    end
  end

  @steps << step
end

#add_step(step_name, options = {}, &block) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/smash_the_state/operation/sequence.rb', line 46

def add_step(step_name, options = {}, &block)
  # steps need to be unique
  unless steps_for_name(step_name).empty?
    raise(
      StepConflict,
      "an operation step named #{step_name.inspect} already exists"
    )
  end

  @steps << Step.new(step_name, options, &block)
end

#add_validation_step(options = {}, &block) ⇒ Object



58
59
60
61
62
63
64
# File 'lib/smash_the_state/operation/sequence.rb', line 58

def add_validation_step(options = {}, &block)
  step = steps_for_name(:validate).first ||
         SmashTheState::Operation::ValidationStep.new(options)

  step.add_implementation(&block)
  @steps |= [step]
end

#call(state) ⇒ Object



15
16
17
# File 'lib/smash_the_state/operation/sequence.rb', line 15

def call(state)
  run_steps(@steps, state)
end

#dynamic_schema?Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/smash_the_state/operation/sequence.rb', line 124

def dynamic_schema?
  dynamic_schema_step.nil? == false
end

#dynamic_schema_stepObject



128
129
130
# File 'lib/smash_the_state/operation/sequence.rb', line 128

def dynamic_schema_step
  steps_for_name(:_dynamic_schema).first
end

#mark_as_side_effect_free!Object

marks all the the currently defined steps as free of side-effects



42
43
44
# File 'lib/smash_the_state/operation/sequence.rb', line 42

def mark_as_side_effect_free!
  steps.each { |s| s.options[:side_effect_free] = true }
end

#middleware_class(state, original_state = nil) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/smash_the_state/operation/sequence.rb', line 96

def middleware_class(state, original_state = nil)
  klass = middleware_class_block.call(state, original_state)

  case klass
  when Module, Class
    klass
  else
    begin
      klass.constantize if klass.respond_to?(:constantize)
    rescue NameError
      nil
    end
  end
end

#override_step(step_name, options = {}, &block) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/smash_the_state/operation/sequence.rb', line 66

def override_step(step_name, options = {}, &block)
  step = steps_for_name(step_name).first

  if step.nil?
    raise(
      BadOverride,
      "overriding step #{step_name.inspect} failed because it does " \
      "not exist"
    )
  end

  @steps[@steps.index(step)] = Step.new(step_name, options, &block)
end

#side_effect_freeObject

return a copy without the steps that produce side-effects



33
34
35
36
37
38
39
# File 'lib/smash_the_state/operation/sequence.rb', line 33

def side_effect_free
  dup.tap do |seq|
    seq.instance_eval do
      @steps = seq.steps.select(&:side_effect_free?)
    end
  end
end

#slice(start, count) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/smash_the_state/operation/sequence.rb', line 19

def slice(start, count)
  # slice should return a copy of the object being sliced
  dup.tap do |seq|
    # we're going to slice the steps, which is really the meat of a sequence, but we
    # need to evaluate in the copy context so that we can swap out the steps for a
    # new copy of steps (because note - even though we've copied the sequence
    # already, the steps of the copy still refer to the steps of the original!)
    seq.instance_eval do
      @steps = seq.steps.slice(start, count)
    end
  end
end

#steps_for_name(name) ⇒ Object

returns steps named the specified name. it’s generally bad form to have mulitple steps with the same name, but it can happen in some reasonable cases (the most common being :validate)



83
84
85
# File 'lib/smash_the_state/operation/sequence.rb', line 83

def steps_for_name(name)
  steps.select { |s| s.name == name }
end