Class: Woods::Extractors::ModelExtractor

Inherits:
Object
  • Object
show all
Includes:
SharedDependencyScanner, SharedUtilityMethods
Defined in:
lib/woods/extractors/model_extractor.rb

Overview

ModelExtractor handles ActiveRecord model extraction with:

  • Inline concern resolution (concerns are embedded, not referenced)

  • Full callback chain extraction

  • Association mapping with target models

  • Schema information as header comments

  • Automatic chunking for large models

This is typically the most important extractor as models represent the core domain and have the most implicit behavior (callbacks, validations, etc.)

Examples:

extractor = ModelExtractor.new
units = extractor.extract_all
user_unit = units.find { |u| u.identifier == "User" }

Constant Summary collapse

AR_INTERNAL_METHOD_PATTERN =

Single combined regex for filtering AR-generated internal methods. Replaces 5 separate patterns with one alternation for O(1) matching.

/\A(?:
  _                                         | # _run_save_callbacks, _validators, etc.
  autosave_associated_records_for_           | # autosave_associated_records_for_comments
  validate_associated_records_for_           | # validate_associated_records_for_comments
  (?:after|before)_(?:add|remove)_for_         # collection callbacks
)/x

Constants included from SharedDependencyScanner

SharedDependencyScanner::FORM_ACTION_HELPER, SharedDependencyScanner::ROUTE_HELPER_PATTERN

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SharedDependencyScanner

#extract_constantize_targets, #scan_common_dependencies, #scan_form_dependencies, #scan_job_dependencies, #scan_mailer_dependencies, #scan_model_dependencies, #scan_navigation_dependencies, #scan_service_dependencies

Methods included from SharedUtilityMethods

#app_source?, #condition_label, #detect_entry_points, #extract_action_filter_actions, #extract_callback_conditions, #extract_class_methods, #extract_class_name, #extract_custom_errors, #extract_initialize_params, #extract_namespace, #extract_parent_class, #extract_public_methods, #resolve_source_location, #skip_file?

Constructor Details

#initializeModelExtractor

Returns a new instance of ModelExtractor.



42
43
44
45
# File 'lib/woods/extractors/model_extractor.rb', line 42

def initialize
  @concern_cache = {}
  @warnings = []
end

Instance Attribute Details

#warningsObject (readonly)

Warnings collected during extraction (skipped associations, failed models)



40
41
42
# File 'lib/woods/extractors/model_extractor.rb', line 40

def warnings
  @warnings
end

Instance Method Details

#extract_allArray<ExtractedUnit>

Extract all ActiveRecord models in the application

Returns:



50
51
52
53
54
55
56
57
# File 'lib/woods/extractors/model_extractor.rb', line 50

def extract_all
  ActiveRecord::Base.descendants
                    .reject(&:abstract_class?)
                    .reject { |m| m.name.nil? } # Skip anonymous classes
                    .reject { |m| habtm_join_model?(m) }
                    .map { |model| extract_model(model) }
                    .compact
end

#extract_model(model) ⇒ ExtractedUnit

Extract a single model

Parameters:

  • model (Class)

    The ActiveRecord model class

Returns:



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/woods/extractors/model_extractor.rb', line 63

def extract_model(model)
  unit = ExtractedUnit.new(
    type: :model,
    identifier: model.name,
    file_path: source_file_for(model)
  )

  source_path = unit.file_path
  source = source_path && File.exist?(source_path) ? File.read(source_path) : nil

  unit.namespace = model.module_parent.name unless model.module_parent == Object
  unit.source_code = build_composite_source(model, source)
  unit. = (model, source)
  unit.dependencies = extract_dependencies(model, source)

  # Enrich callbacks with side-effect analysis
  enrich_callbacks_with_side_effects(unit, source)

  # Build semantic chunks for all models (summary, associations, callbacks, validations)
  unit.chunks = build_chunks(unit)

  unit
rescue StandardError => e
  @warnings << "Failed to extract model #{model.name}: #{e.message}"
  Rails.logger.error("Failed to extract model #{model.name}: #{e.message}")
  nil
end