Class: Woods::Extractors::DecoratorExtractor

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

Overview

DecoratorExtractor handles decorator, presenter, and form object extraction.

Scans conventional directories for view-layer wrapper objects: decorators (Draper-style or PORO), presenters, and form objects. Extracts the decorated model relationship, delegation chains, and whether the Draper gem is in use.

Examples:

extractor = DecoratorExtractor.new
units = extractor.extract_all
user_dec = units.find { |u| u.identifier == "UserDecorator" }
user_dec.[:decorated_model]  # => "User"
user_dec.[:uses_draper]      # => true

Constant Summary collapse

DECORATOR_DIRECTORIES =

Directories to scan for decorator-style objects

%w[
  app/decorators
  app/presenters
  app/form_objects
].freeze
DIRECTORY_TYPE_MAP =

Maps directory segment to decorator_type symbol

{
  'decorators' => :decorator,
  'presenters' => :presenter,
  'form_objects' => :form_object
}.freeze
DECORATOR_SUFFIXES =

Suffixes used to infer the decorated model name

%w[Decorator Presenter Form].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, #extract_action_filter_actions, #extract_callback_conditions, #extract_class_methods, #extract_custom_errors, #extract_initialize_params, #extract_namespace, #extract_parent_class, #extract_public_methods, #resolve_source_location, #skip_file?

Constructor Details

#initializeDecoratorExtractor

Returns a new instance of DecoratorExtractor.



43
44
45
46
# File 'lib/woods/extractors/decorator_extractor.rb', line 43

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

Instance Method Details

#extract_allArray<ExtractedUnit>

Extract all decorator, presenter, and form object units.

Returns:



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

def extract_all
  @directories.flat_map do |dir|
    Dir[dir.join('**/*.rb')].filter_map do |file|
      extract_decorator_file(file)
    end
  end
end

#extract_decorator_file(file_path) ⇒ ExtractedUnit?

Extract a single decorator file.

Parameters:

  • file_path (String)

    Absolute path to the Ruby file

Returns:

  • (ExtractedUnit, nil)

    The extracted unit or nil if not a decorator



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

def extract_decorator_file(file_path)
  source = File.read(file_path)
  class_name = extract_class_name(file_path, source)

  return nil unless class_name
  return nil if skip_file?(source)

  unit = ExtractedUnit.new(
    type: :decorator,
    identifier: class_name,
    file_path: file_path
  )

  unit.namespace = extract_namespace(class_name)
  unit.source_code = annotate_source(source, class_name, file_path)
  unit. = (source, class_name, file_path)
  unit.dependencies = extract_dependencies(source, class_name)

  unit
rescue StandardError => e
  Rails.logger.error("Failed to extract decorator #{file_path}: #{e.message}")
  nil
end