Class: Hyperloop::Operation::Railway

Inherits:
Object
  • Object
show all
Defined in:
lib/hyper-operation/api.rb,
lib/hyper-operation/railway/run.rb,
lib/hyper-operation/railway/dispatcher.rb,
lib/hyper-operation/railway/validations.rb,
lib/hyper-operation/railway/params_wrapper.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(operation) ⇒ Railway

Returns a new instance of Railway.


159
160
161
# File 'lib/hyper-operation/api.rb', line 159

def initialize(operation)
  @operation = operation
end

Class Method Details

.abort!(arg) ⇒ Object

Raises:


48
49
50
# File 'lib/hyper-operation/railway/run.rb', line 48

def abort!(arg)
  raise Exit.new(:failed, arg)
end

.add_error(param, symbol, message, *args, &block) ⇒ Object


23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/hyper-operation/railway/validations.rb', line 23

def add_error(param, symbol, message, *args, &block)
  add_validation do
    begin
      add_error(param, symbol, message) if instance_eval(&block)
      true
    rescue Exit => e
      raise e unless e.state == :failed
      add_error(param, symbol, message)
      raise Exit.new(:abort_from_add_error, e.result)
    end
  end
end

.add_param(*args, &block) ⇒ Object


117
118
119
# File 'lib/hyper-operation/railway/params_wrapper.rb', line 117

def self.add_param(*args, &block)
  params_wrapper.add_param(*args, &block)
end

.add_receiver(&block) ⇒ Object


16
17
18
# File 'lib/hyper-operation/railway/dispatcher.rb', line 16

def add_receiver(&block)
  receivers << block
end

.add_validation(*args, &block) ⇒ Object


18
19
20
21
# File 'lib/hyper-operation/railway/validations.rb', line 18

def add_validation(*args, &block)
  block = args[0] if args[0]
  validations << block
end

.params_wrapperObject


121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/hyper-operation/railway/params_wrapper.rb', line 121

def self.params_wrapper
  Hyperloop::Context.set_var(self, :@params_wrapper) do
    if Railway == superclass
      Class.new(ParamsWrapper)
    else
      Class.new(superclass.params_wrapper).tap do |wrapper|
        hash_filter = superclass.params_wrapper.hash_filter
        wrapper.instance_variable_set('@hash_filter', hash_filter && hash_filter.dup)
        inbound_params = superclass.params_wrapper.inbound_params
        wrapper.instance_variable_set('@inbound_params', inbound_params && inbound_params.dup)
      end
    end
  end
end

.receiversObject


10
11
12
13
14
# File 'lib/hyper-operation/railway/dispatcher.rb', line 10

def receivers
  # use the force: true option so that system code needing to receive
  # boot will NOT be erased on the next Hyperloop::Context.reset!
  Hyperloop::Context.set_var(self, :@receivers, force: true) { [] }
end

.succeed!(arg) ⇒ Object

Raises:


52
53
54
# File 'lib/hyper-operation/railway/run.rb', line 52

def succeed!(arg)
  raise Exit.new(:success, arg)
end

.to_opts(tie, args, block) ⇒ Object


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/hyper-operation/railway/run.rb', line 24

def to_opts(tie, args, block)
  if args.count.zero?
    { run: block }
  elsif args[0].is_a?(Hash)
    {
      scope: args[0][:class] ? :class : args[0][:scope],
      run: args[0][:class] || args[0][:run] || block
    }
  elsif args[0] == :class && block
    { run: block, scope: :class }
  elsif args[0].is_a?(Class) && args[0] < Operation
    { run: proc { args[0].run(params) } }
  else
    scope = args[1][:scope] if args[1].is_a? Hash
    { run: args[0], scope: scope }
  end.merge(tie: instance_method(tie))
end

.tracksObject


20
21
22
# File 'lib/hyper-operation/railway/run.rb', line 20

def tracks
  @tracks ||= []
end

.validationsObject


14
15
16
# File 'lib/hyper-operation/railway/validations.rb', line 14

def validations
  @validations ||= []
end

Instance Method Details

#add_validation_error(i, e) ⇒ Object


9
10
11
# File 'lib/hyper-operation/railway/validations.rb', line 9

def add_validation_error(i, e)
  @operation.add_error("param validation #{i+1}", :validation_error, e.to_s)
end

#apply(opts, in_promise = nil) ⇒ Object


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/hyper-operation/railway/run.rb', line 85

def apply(opts, in_promise = nil)
  if opts[:scope] == :class
    args = [@operation, *@last_result]
    instance = @operation.class
  else
    args = @last_result
    instance = @operation
  end
  block = opts[:run]
  block = instance.method(block) if block.is_a? Symbol
  @last_result =
    if block.arity.zero?
      instance.instance_exec(&block)
    elsif args.is_a?(Array) && block.arity == args.count
      instance.instance_exec(*args, &block)
    else
      instance.instance_exec(args, &block)
    end
  return @last_result unless @last_result.is_a? Promise
  raise @last_result.error if @last_result.rejected?
  @last_result = @last_result.value if @last_result.resolved?
  @last_result
rescue Exit => e
  @state = e.state
  @last_result = (e.state != :failed || e.result.is_a?(Exception)) ? e.result : e
  raise e
rescue Exception => e
  @state = :failed
  @last_result = e
  raise e if in_promise
end

#async(opts) ⇒ Object


81
82
83
# File 'lib/hyper-operation/railway/run.rb', line 81

def async(opts)
  apply(opts) if @state != :failed
end

#dispatchObject


21
22
23
24
25
26
27
28
29
30
# File 'lib/hyper-operation/railway/dispatcher.rb', line 21

def dispatch
  result.then do
    receivers.each do |receiver|
      receiver.call(
        self.class.params_wrapper.dispatch_params(@operation.params),
        @operation
      )
    end
  end
end

#failed(opts) ⇒ Object


68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/hyper-operation/railway/run.rb', line 68

def failed(opts)
  if @last_result.is_a? Promise
    @last_result = @last_result.fail do |e|
      @last_result = e
      apply(opts, :in_promise)
      raise @last_result if @last_result.is_a? Exception
      raise e
    end
  elsif @state == :failed
    apply(opts)
  end
end

#process_params(args) ⇒ Object


113
114
115
# File 'lib/hyper-operation/railway/params_wrapper.rb', line 113

def process_params(args)
  self.class.params_wrapper.process_params(@operation, args)
end

#process_validationsObject


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/hyper-operation/railway/validations.rb', line 37

def process_validations
  validations.each_with_index do |validator, i|
    begin
      validator = @operation.method(validator) if validator.is_a? Symbol
      next if @operation.instance_exec(&validator)
      add_validation_error(i, "param validation #{i+1} failed")
    rescue Exit => e
      case e.state
      when :success
        add_validation_error(i, "illegal use of succeed! in validation")
      when :failed
        add_validation_error(i, "param validation #{i+1} aborted")
      end
      @state = :failed
      return # break does not work in Opal
    rescue AccessViolation => e
      add_validation_error(i, e)
      @state = :failed
      @last_result = e
      return # break does not work in Opal
    rescue Exception => e
      add_validation_error(i, e)
    end
  end
end

#receiversObject


5
6
7
# File 'lib/hyper-operation/railway/dispatcher.rb', line 5

def receivers
  self.class.receivers
end

#resultObject


129
130
131
132
133
134
135
136
137
# File 'lib/hyper-operation/railway/run.rb', line 129

def result
  return @last_result if @last_result.is_a? Promise
  @last_result =
    if @state == :success
      Promise.new.resolve(@last_result)
    else
      Promise.new.reject(@last_result)
    end
end

#runObject


117
118
119
120
121
122
123
124
125
126
127
# File 'lib/hyper-operation/railway/run.rb', line 117

def run
  if @operation.has_errors? || @state
    @last_result ||= ValidationException.new(@operation.instance_variable_get('@errors'))
    return if @state  # handles abort out of validation
    @state = :failed
  else
    @state = :success
  end
  tracks.each { |opts| opts[:tie].bind(self).call(opts) }
rescue Exit
end

#step(opts) ⇒ Object


57
58
59
60
61
62
63
64
65
66
# File 'lib/hyper-operation/railway/run.rb', line 57

def step(opts)
  if @last_result.is_a? Promise
    @last_result = @last_result.then do |*result|
      @last_result = result
      apply(opts, :in_promise)
    end
  elsif @state == :success
    apply(opts)
  end
end

#tracksObject


15
16
17
# File 'lib/hyper-operation/railway/run.rb', line 15

def tracks
  self.class.tracks
end

#validationsObject


5
6
7
# File 'lib/hyper-operation/railway/validations.rb', line 5

def validations
  self.class.validations
end