Class: RubyReactor::Web::API

Inherits:
Roda
  • Object
show all
Defined in:
lib/ruby_reactor/web/api.rb

Overview

rubocop:disable Metrics/BlockLength

Class Method Summary collapse

Class Method Details

.build_structure(reactor_class) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/ruby_reactor/web/api.rb', line 110

def self.build_structure(reactor_class)
  return {} unless reactor_class.respond_to?(:steps)

  steps_config = reactor_class.steps
  return {} unless steps_config.is_a?(Hash)

  # Use DependencyGraph to calculate dependencies effectively
  graph = RubyReactor::DependencyGraph.new
  steps_config.each_value { |config| graph.add_step(config) }

  steps_config.to_h do |name, config|
    type = determine_step_type(config)

    step_data = {
      name: name,
      type: type,
      depends_on: graph.dependencies[name],
      async: config.async?
    }

    if type == "compose"
      inner_class = extract_inner_class(config, :composed_reactor_class)
      step_data[:nested_structure] = build_structure(inner_class) if inner_class
    elsif type == "map"
      inner_class = extract_inner_class(config, :mapped_reactor_class)
      step_data[:nested_structure] = build_structure(inner_class) if inner_class
    end

    [name, step_data]
  end
end

.determine_step_type(config) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/ruby_reactor/web/api.rb', line 142

def self.determine_step_type(config)
  if config.respond_to?(:interrupt?) && config.interrupt?
    "interrupt"
  elsif config.arguments&.key?(:composed_reactor_class)
    "compose"
  elsif config.arguments&.key?(:mapped_reactor_class)
    "map"
  elsif config.async?
    "async"
  else
    "step"
  end
end

.extract_inner_class(config, param_name) ⇒ Object



156
157
158
159
160
161
# File 'lib/ruby_reactor/web/api.rb', line 156

def self.extract_inner_class(config, param_name)
  val = config.arguments.dig(param_name, :source)
  val.is_a?(RubyReactor::Template::Value) ? val.value : nil
rescue StandardError
  nil
end

.hydrate_composed_contexts(composed_contexts, reactor_class_name) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/ruby_reactor/web/api.rb', line 163

def self.hydrate_composed_contexts(composed_contexts, reactor_class_name)
  return {} unless composed_contexts.is_a?(Hash)

  composed_contexts.transform_values do |value|
    type = value[:type] || value["type"]
    if ["map_ref", :map_ref].include?(type)
      hydrate_map_ref(value, reactor_class_name)
    else
      value
    end
  end
end

.hydrate_map_ref(ref_data, reactor_class_name) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/ruby_reactor/web/api.rb', line 176

def self.hydrate_map_ref(ref_data, reactor_class_name)
  storage = RubyReactor.configuration.storage_adapter
  map_id = ref_data[:map_id] || ref_data["map_id"]

  # Use the specific element reactor class if available, otherwise fallback to parent
  target_reactor_class = ref_data[:element_reactor_class] ||
                         ref_data["element_reactor_class"] ||
                         reactor_class_name

  # 1. Check for specific failure (O(1))
  # Stored by ResultHandler when a map element fails
  failed_context_id = storage.retrieve_map_failed_context_id(map_id, reactor_class_name)

  target_context_id = if failed_context_id
                        failed_context_id
                      else
                        # 2. Fallback to representative sample (last element) (O(1))
                        # If no failure, the last element gives a good idea of progress/completion
                        target_id = storage.retrieve_map_element_context_id(map_id, reactor_class_name, index: -1)
                        target_id
                      end

  return ref_data unless target_context_id

  # Retrieve the actual context data for the target ID
  representative_data = storage.retrieve_context(target_context_id, target_reactor_class)

  return ref_data unless representative_data

  {
    "name" => ref_data["name"],
    "type" => "map_element",
    "context" => representative_data
  }
end