Class: RailsAiBridge::Introspector

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_ai_bridge/introspector.rb,
lib/rails_ai_bridge/introspector/timed_runner.rb,
lib/rails_ai_bridge/introspector/parallel_runner.rb

Overview

Orchestrates all sub-introspectors to build a complete picture of the Rails application for AI consumption.

Depending on configuration, introspectors are run sequentially (default) or concurrently via ParallelRunner. Sequential runs are timed via TimedRunner so duration data is available in debug logs regardless of the execution strategy.

:reek:RepeatedConditional -- static_mode? guards in build_metadata/run_single/run_parallel are the cleanest way to branch on app type

Examples:

Running all standard introspectors

context = RailsAiBridge::Introspector.new(Rails.application).call
context[:app_name]  #=> "MyApp"
context[:schema]    #=> { tables: { ... } }

Running a subset of introspectors

context = RailsAiBridge::Introspector.new(app).call(only: %i[schema routes])

Defined Under Namespace

Classes: ParallelRunner, TimedRunner

Constant Summary collapse

BUILTIN_INTROSPECTORS =

Registry of all built-in introspector classes, keyed by symbolic name.

The :standard preset uses 9 of these; the :full preset uses 27 (+:full+ already includes :non_ar_models). Opt-in-only keys (e.g. :database_stats, :semantic) are present here but excluded from both presets by default.

Returns:

  • (Hash{Symbol => Class})
{
  schema: Introspectors::SchemaIntrospector,
  models: Introspectors::ModelIntrospector,
  non_ar_models: Introspectors::NonArModelsIntrospector,
  routes: Introspectors::RouteIntrospector,
  jobs: Introspectors::JobIntrospector,
  gems: Introspectors::GemIntrospector,
  conventions: Introspectors::ConventionDetector,
  stimulus: Introspectors::StimulusIntrospector,
  database_stats: Introspectors::DatabaseStatsIntrospector,
  controllers: Introspectors::ControllerIntrospector,
  views: Introspectors::ViewIntrospector,
  turbo: Introspectors::TurboIntrospector,
  i18n: Introspectors::I18nIntrospector,
  config: Introspectors::ConfigIntrospector,
  active_storage: Introspectors::ActiveStorageIntrospector,
  action_text: Introspectors::ActionTextIntrospector,
  auth: Introspectors::AuthIntrospector,
  api: Introspectors::ApiIntrospector,
  tests: Introspectors::TestIntrospector,
  rake_tasks: Introspectors::RakeTaskIntrospector,
  assets: Introspectors::AssetPipelineIntrospector,
  devops: Introspectors::DevOpsIntrospector,
  action_mailbox: Introspectors::ActionMailboxIntrospector,
  migrations: Introspectors::MigrationIntrospector,
  seeds: Introspectors::SeedsIntrospector,
  middleware: Introspectors::MiddlewareIntrospector,
  engines: Introspectors::EngineIntrospector,
  multi_database: Introspectors::MultiDatabaseIntrospector,
  semantic: Introspectors::SemanticIntrospector
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ Introspector

Returns a new instance of Introspector.

Parameters:

  • app (Rails::Application) —

    the Rails application to introspect



28
29
30
31
# File 'lib/rails_ai_bridge/introspector.rb', line 28

def initialize(app)
  @app    = app
  @config = RailsAiBridge.configuration
end

Instance Attribute Details

#app ⇒ Rails::Application (readonly)

Returns the host application passed at construction.

Returns:

  • (Rails::Application) —

    the host application passed at construction



22
23
24
# File 'lib/rails_ai_bridge/introspector.rb', line 22

def app
  @app
end

#config ⇒ RailsAiBridge::Configuration (readonly)

Returns active gem configuration.

Returns:



25
26
27
# File 'lib/rails_ai_bridge/introspector.rb', line 25

def config
  @config
end

Instance Method Details

#app_name ⇒ String

Returns the application name derived from the Rails application class.

Tries module_parent_name first (Rails 6+), falling back to deconstantize on the full class name.

Returns:

  • (String) —

    the application module name (e.g. "MyApp")



106
107
108
109
110
111
112
# File 'lib/rails_ai_bridge/introspector.rb', line 106

def app_name
  if app.class.respond_to?(:module_parent_name)
    app.class.module_parent_name
  else
    app.class.name.deconstantize
  end
end

#call(only: nil) ⇒ Hash

Runs all configured (or a specified subset of) introspectors and returns a unified context hash.

Metadata keys (+:app_name+, :ruby_version, :rails_version, etc.) are always present. Introspector results are merged in at the top level, keyed by their symbolic name (e.g. :schema, :routes).

When parallel introspection is enabled and more than one introspector is requested, execution is delegated to ParallelRunner. Otherwise each introspector runs sequentially, wrapped by TimedRunner for observability.

Parameters:

  • only (Array<Symbol>, nil) (defaults to: nil) —

    optional subset of introspector keys to run; passes through #selected_introspectors

Returns:

  • (Hash) —

    complete application context merged with metadata



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rails_ai_bridge/introspector.rb', line 47

def call(only: nil)
  context = 

  names   = selected_introspectors(only)
  results = if parallel_enabled? && names.size > 1
              run_parallel(names)
            else
              run_sequential(names)
            end

  context.merge(results)
end

#resolve_introspector(name) ⇒ Object

Looks up and instantiates an introspector by name.

Checks config.additional_introspectors before falling back to BUILTIN_INTROSPECTORS.

Parameters:

  • name (Symbol) —

    introspector key

Returns:

  • (Object) —

    an instantiated introspector

Raises:



142
143
144
145
146
147
# File 'lib/rails_ai_bridge/introspector.rb', line 142

def resolve_introspector(name)
  introspector_class = config.additional_introspectors[name] || BUILTIN_INTROSPECTORS[name]
  raise ConfigurationError, "Unknown introspector: #{name}" unless introspector_class

  introspector_class.new(app)
end

#selected_introspectors(only) ⇒ Array<Symbol>

Resolves the list of introspector keys to run.

Returns config.effective_introspectors when only is blank. A non-blank only list is intersected with effective_introspectors (plus additional_introspectors keys) so MCP fetch_section cannot run schema or models when they were disabled by :regulated or disabled_introspection_categories, while host-registered extras remain fetchable.

Parameters:

  • only (Array<Symbol>, nil)

Returns:

  • (Array<Symbol>)


125
126
127
128
129
130
131
132
# File 'lib/rails_ai_bridge/introspector.rb', line 125

def selected_introspectors(only)
  allowed = config.effective_introspectors
  names = Array(only).compact
  return allowed if names.empty?

  extra = config.additional_introspectors.keys
  names.select { |name| allowed.include?(name) || extra.include?(name) }
end