Class: Lyra::Verification::CrudVerifier

Inherits:
Object
  • Object
show all
Defined in:
lib/lyra/verification/crud_lifecycle_workflow.rb

Overview

Verification runner for Lyra CRUD workflows

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize ⇒ CrudVerifier

Returns a new instance of CrudVerifier.



194
195
196
197
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 194

def initialize
  @results = {}
  @report = nil
end

Instance Attribute Details

#report ⇒ Object (readonly)

Returns the value of attribute report.



192
193
194
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 192

def report
  @report
end

#results ⇒ Object (readonly)

Returns the value of attribute results.



192
193
194
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 192

def results
  @results
end

Instance Method Details

#analyze_mapping ⇒ Object

Analyze actual CRUD→Event mapping from Lyra configuration



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 340

def analyze_mapping
  mapping = PetriFlow::Matrix::CrudEventMapping.new

  Lyra.config.monitored_models.each do |model_class|
    config = Lyra.config.model_config(model_class)
    prefix = config.event_prefix

    # Record expected mappings
    mapping.record_mapping(:create, "#{prefix}Created".to_sym)
    mapping.record_mapping(:update, "#{prefix}Updated".to_sym)
    mapping.record_mapping(:delete, "#{prefix}Destroyed".to_sym)
  end

  @results[:mapping] = {
    matrix: mapping.to_table,
    stats: {
      models: Lyra.config.monitored_models.count,
      total_mappings: mapping.to_matrix.to_a.flatten.sum
    }
  }
end

#find_workflow_class(class_name) ⇒ Object

Find workflow class by name, checking multiple locations



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 318

def find_workflow_class(class_name)
  # Check Generated module first (if it exists)
  if defined?(Lyra::Verification::Generated) &&
     Lyra::Verification::Generated.const_defined?(class_name)
    return Lyra::Verification::Generated.const_get(class_name)
  end

  # Check top-level (for workflows defined without module)
  if Object.const_defined?(class_name)
    klass = Object.const_get(class_name)
    return klass if klass < PetriFlow::Workflow
  end

  nil
end

#find_workflows_dir ⇒ Object

Backwards compatibility



335
336
337
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 335

def find_workflows_dir
  find_workflows_dirs.first
end

#find_workflows_dirs ⇒ Object

Find all workflow directories (both Lyra gem and Rails app)



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 298

def find_workflows_dirs
  dirs = []

  # Check Lyra gem's app/workflows
  lyra_gem_root = Gem.loaded_specs['lyra']&.gem_dir
  lyra_gem_root ||= File.expand_path('../../..', __dir__)
  lyra_workflows = File.join(lyra_gem_root, 'app', 'workflows')
  dirs << lyra_workflows if Dir.exist?(lyra_workflows)

  # Check Rails app's app/workflows
  if defined?(Rails) && Rails.root
    rails_workflows = Rails.root.join('app', 'workflows').to_s
    # Add only if different from Lyra gem's path
    dirs << rails_workflows if Dir.exist?(rails_workflows) && !dirs.include?(rails_workflows)
  end

  dirs
end

#generate_report ⇒ Object

Generate verification report



363
364
365
366
367
368
369
370
371
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 363

def generate_report
  @report = {
    timestamp: Time.current,
    lyra_version: Lyra::VERSION,
    petri_flow_version: PetriFlow::VERSION,
    summary: build_summary,
    details: @results
  }
end

#verify_all ⇒ Object

Verify all CRUD workflows



200
201
202
203
204
205
206
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 200

def verify_all
  verify_lifecycle
  verify_modes
  verify_generated_workflows
  generate_report
  @report
end

#verify_generated_workflows ⇒ Object

Verify generated workflows from app/workflows directories Scans both Lyra gem's workflows AND Rails app's workflows



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 246

def verify_generated_workflows
  @results[:generated_workflows] = {}

  # Find all workflow directories
  workflows_dirs = find_workflows_dirs
  return if workflows_dirs.empty?

  # Ensure the Generated module exists
  Lyra::Verification.const_set(:Generated, Module.new) unless Lyra::Verification.const_defined?(:Generated)

  # Load and verify workflows from all directories
  workflows_dirs.each do |workflows_dir|
    Dir.glob(File.join(workflows_dir, "*_workflow.rb")).each do |file|
      basename = File.basename(file, '.rb')
      # Skip if already loaded from another directory
      next if @results[:generated_workflows].key?(basename.to_sym)

      begin
        # Use load instead of require to bypass Zeitwerk
        load file

        # Extract class name from file name
        class_name = basename.split('_').map(&:capitalize).join

        # Try to find the class - check multiple locations
        workflow_class = find_workflow_class(class_name)

        if workflow_class
          workflow = workflow_class.new

          @results[:generated_workflows][basename.to_sym] = {
            workflow: workflow.workflow_name,
            file: file,
            verification: workflow.verify!,
            terminal_reachability: workflow.terminal_reachability.dup,
            diagrams: {
              mermaid: workflow.to_mermaid,
              dot: workflow.to_dot
            }
          }
        end
      rescue StandardError => e
        @results[:generated_workflows][basename.to_sym] = {
          error: "#{e.class}: #{e.message}",
          file: file
        }
      end
    end
  end
end

#verify_lifecycle ⇒ Object

Verify entity lifecycle workflow



209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 209

def verify_lifecycle
  workflow = CrudLifecycleWorkflow.new
  @results[:lifecycle] = {
    workflow: workflow.workflow_name,
    verification: workflow.verify!,
    terminal_reachability: workflow.terminal_reachability.dup,
    diagrams: {
      mermaid: workflow.to_mermaid,
      dot: workflow.to_dot
    }
  }
end

#verify_modes ⇒ Object

Verify mode-switching workflows (Create, Update, Destroy)



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/lyra/verification/crud_lifecycle_workflow.rb', line 223

def verify_modes
  @results[:modes] = {}

  {
    create: CreateModeWorkflow,
    update: UpdateModeWorkflow,
    destroy: DestroyModeWorkflow
  }.each do |operation, workflow_class|
    workflow = workflow_class.new
    @results[:modes][operation] = {
      workflow: workflow.workflow_name,
      verification: workflow.verify!,
      terminal_reachability: workflow.terminal_reachability.dup,
      diagrams: {
        mermaid: workflow.to_mermaid,
        dot: workflow.to_dot
      }
    }
  end
end