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



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

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

rubocop:enable Lint/ShadowedException



105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/smash_the_state/operation/sequence.rb', line 105

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



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

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



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

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)


118
119
120
# File 'lib/smash_the_state/operation/sequence.rb', line 118

def dynamic_schema?
  dynamic_schema_step.nil? == false
end

#dynamic_schema_stepObject



122
123
124
# File 'lib/smash_the_state/operation/sequence.rb', line 122

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



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

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

#middleware_class(state, original_state = nil) ⇒ Object

rubocop:disable Lint/ShadowedException



98
99
100
101
102
# File 'lib/smash_the_state/operation/sequence.rb', line 98

def middleware_class(state, original_state = nil)
  middleware_class_block.call(state, original_state).constantize
rescue NameError, NoMethodError
  nil
end

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



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

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
40
# File 'lib/smash_the_state/operation/sequence.rb', line 33

def side_effect_free
  dup.tap do |seq|
    seq.run_options[:dry] = true
    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)



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

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