Class: Woods::Extractors::EventExtractor

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

Overview

EventExtractor discovers event publishing and subscribing patterns across the app.

Scans app/*/.rb for two event system conventions:

  • ActiveSupport::Notifications: instrument (publish) and subscribe (consume)

  • Wisper: publish/broadcast (publish) and on(:event_name) (subscribe)

Uses a two-pass approach:

  1. Scan all files, collecting publishers and subscribers per event name

  2. Merge by event name → one ExtractedUnit per unique event

Examples:

extractor = EventExtractor.new
units = extractor.extract_all
event = units.find { |u| u.identifier == "order.completed" }
event.[:publishers]  # => ["app/services/order_service.rb"]
event.[:subscribers] # => ["app/listeners/order_listener.rb"]
event.[:pattern]     # => :active_support

Constant Summary collapse

APP_DIRECTORIES =
%w[app].freeze

Constants included from SharedDependencyScanner

SharedDependencyScanner::FORM_ACTION_HELPER, SharedDependencyScanner::ROUTE_HELPER_PATTERN

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, #count_loc, #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

#initializeEventExtractor

Returns a new instance of EventExtractor.



32
33
34
# File 'lib/woods/extractors/event_extractor.rb', line 32

def initialize
  @directories = APP_DIRECTORIES.map { |d| Rails.root.join(d) }.select(&:directory?)
end

Instance Method Details

#extract_allArray<ExtractedUnit>

Extract all event units using a two-pass approach.

Pass 1: Collect publish/subscribe references across all app files. Pass 2: Merge by event name — one ExtractedUnit per unique event.

Returns:



42
43
44
45
46
47
48
49
50
# File 'lib/woods/extractors/event_extractor.rb', line 42

def extract_all
  event_map = {}

  @directories.flat_map { |dir| Dir[dir.join('**/*.rb')] }.each do |file_path|
    scan_file(file_path, event_map)
  end

  event_map.filter_map { |event_name, data| build_unit(event_name, data) }
end

#scan_file(file_path, event_map) ⇒ void

This method returns an undefined value.

Scan a single file for event publishing and subscribing patterns.

Mutates event_map in place, registering publishers and subscribers.

Parameters:

  • file_path (String)

    Path to the Ruby file

  • event_map (Hash)

    Mutable map of event_name => subscribers:, pattern:



59
60
61
62
63
64
65
# File 'lib/woods/extractors/event_extractor.rb', line 59

def scan_file(file_path, event_map)
  source = File.read(file_path)
  scan_active_support_notifications(source, file_path, event_map)
  scan_wisper_patterns(source, file_path, event_map)
rescue StandardError => e
  Rails.logger.error("Failed to scan #{file_path} for events: #{e.message}")
end