rigortype 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/data/core_overlay/csv.rbs +28 -0
- data/data/core_overlay/psych.rbs +22 -0
- data/docs/handbook/01-getting-started.md +9 -1
- data/docs/handbook/02-everyday-types.md +4 -1
- data/docs/handbook/08-understanding-errors.md +3 -3
- data/docs/manual/01-installation.md +1 -0
- data/docs/manual/02-cli-reference.md +16 -7
- data/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/14-rails-quickstart.md +4 -2
- data/docs/manual/15-type-protection-coverage.md +27 -4
- data/docs/manual/plugins/rigor-actionpack.md +1 -1
- data/docs/manual/plugins/rigor-activerecord.md +12 -5
- data/docs/manual/plugins/rigor-rails-routes.md +11 -0
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +248 -186
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +62 -48
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +46 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_fork_scan.rb +55 -0
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +34 -18
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/missing_gem_constant_index.rb +128 -0
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +225 -304
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +794 -1154
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/fork_map.rb +87 -0
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +627 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +154 -109
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -821
- data/lib/rigor/inference/statement_evaluator.rb +754 -1114
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +141 -184
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +92 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +40 -48
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +140 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +56 -59
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +172 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +168 -241
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +32 -0
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +189 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +61 -75
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +319 -505
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +91 -96
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/environment.rbs +1 -0
- data/sig/rigor/scope.rbs +6 -0
- metadata +9 -1
|
@@ -4,40 +4,34 @@ require "rigor/plugin"
|
|
|
4
4
|
|
|
5
5
|
require_relative "activerecord/schema_table"
|
|
6
6
|
require_relative "activerecord/schema_parser"
|
|
7
|
+
require_relative "activerecord/structure_sql_parser"
|
|
7
8
|
require_relative "activerecord/model_index"
|
|
8
9
|
require_relative "activerecord/model_discoverer"
|
|
9
10
|
require_relative "activerecord/analyzer"
|
|
10
11
|
|
|
11
12
|
module Rigor
|
|
12
13
|
module Plugin
|
|
13
|
-
# rigor-activerecord — types ActiveRecord finder + relation
|
|
14
|
-
#
|
|
15
|
-
# AR model classes.
|
|
14
|
+
# rigor-activerecord — types ActiveRecord finder + relation calls against the project's `db/schema.rb`
|
|
15
|
+
# and discovered AR model classes.
|
|
16
16
|
#
|
|
17
17
|
# ## Architecture
|
|
18
18
|
#
|
|
19
19
|
# Two cached producers per plugin run:
|
|
20
20
|
#
|
|
21
|
-
# 1. `:schema_table` reads `db/schema.rb` via the `IoBoundary`
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# whose direct superclass is in `model_base_classes`, and
|
|
28
|
-
# composes them with the schema table into a {ModelIndex}.
|
|
21
|
+
# 1. `:schema_table` reads `db/schema.rb` via the `IoBoundary` and parses it through {SchemaParser} into
|
|
22
|
+
# a {SchemaTable} mapping `table_name → { column_name → Column }`. When `db/schema.rb` is absent it
|
|
23
|
+
# falls back to a PostgreSQL `db/structure.sql` (`schema_format = :sql` apps) via {StructureSqlParser}.
|
|
24
|
+
# 2. `:model_index` walks every `.rb` file under the configured `model_search_paths`, finds class
|
|
25
|
+
# declarations whose direct superclass is in `model_base_classes`, and composes them with the schema
|
|
26
|
+
# table into a {ModelIndex}.
|
|
29
27
|
#
|
|
30
|
-
# Both producers ride `Plugin::Base#cache_for` (ADR-60 WD3
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
# so editing `db/schema.rb`, editing any model, or adding a new
|
|
35
|
-
# model file invalidates exactly the right cache entry.
|
|
28
|
+
# Both producers ride `Plugin::Base#cache_for` (ADR-60 WD3 record-and-validate): each producer's
|
|
29
|
+
# in-block boundary reads are captured into its dependency descriptor after the block runs, and
|
|
30
|
+
# `model_index`'s `watch:` covers model-file additions, so editing `db/schema.rb`, editing any model, or
|
|
31
|
+
# adding a new model file invalidates exactly the right cache entry.
|
|
36
32
|
#
|
|
37
|
-
# The per-file `#diagnostics_for_file` hook delegates to
|
|
38
|
-
#
|
|
39
|
-
# `Model.find` / `Model.find_by` / `Model.where` calls
|
|
40
|
-
# against the index.
|
|
33
|
+
# The per-file `#diagnostics_for_file` hook delegates to {Analyzer}, which walks Prism and emits
|
|
34
|
+
# diagnostics for `Model.find` / `Model.find_by` / `Model.where` calls against the index.
|
|
41
35
|
#
|
|
42
36
|
# ## Configuration
|
|
43
37
|
#
|
|
@@ -48,75 +42,73 @@ module Rigor
|
|
|
48
42
|
# model_search_paths: ["app/models"]
|
|
49
43
|
# model_base_classes: ["ApplicationRecord", "ActiveRecord::Base"]
|
|
50
44
|
#
|
|
51
|
-
# All three keys default to the values shown above. The class
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# `::ActiveRecord` even though the gem name is hyphenated.
|
|
45
|
+
# All three keys default to the values shown above. The class name `Rigor::Plugin::Activerecord` (single
|
|
46
|
+
# capital R) is intentional — keeps the constant lookup distinct from `::ActiveRecord` even though the
|
|
47
|
+
# gem name is hyphenated.
|
|
55
48
|
#
|
|
56
|
-
# Note: this plugin is the seventh worked example. It does NOT
|
|
57
|
-
#
|
|
58
|
-
# source, the same way the other examples do. Rigor stays
|
|
59
|
-
# decoupled from Rails.
|
|
49
|
+
# Note: this plugin is the seventh worked example. It does NOT require `active_record` at runtime — it
|
|
50
|
+
# only reads project source, the same way the other examples do. Rigor stays decoupled from Rails.
|
|
60
51
|
class Activerecord < Rigor::Plugin::Base
|
|
61
52
|
manifest(
|
|
62
53
|
id: "activerecord",
|
|
63
|
-
# Bumped 2026-05-28 — implicit-self class-side AR call
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
# `
|
|
67
|
-
# falling through to `Kernel#select` (the IO multiplexer,
|
|
68
|
-
# `Array[String]` return). Plus `:select` added to the
|
|
69
|
-
# relation-entry-point list.
|
|
54
|
+
# Bumped 2026-05-28 — implicit-self class-side AR call resolution: `select(:uri).group(:uri)` inside
|
|
55
|
+
# a scope lambda body / class-method body now contributes `Relation[Model]` via `scope.self_type`
|
|
56
|
+
# instead of falling through to `Kernel#select` (the IO multiplexer, `Array[String]` return). Plus
|
|
57
|
+
# `:select` added to the relation-entry-point list.
|
|
70
58
|
version: "0.5.0",
|
|
71
59
|
description: "Types ActiveRecord finders against the project's db/schema.rb and AR models.",
|
|
72
60
|
config_schema: {
|
|
73
61
|
"schema_file" => { kind: :string, default: "db/schema.rb" },
|
|
62
|
+
# `schema_format = :sql` projects (GitLab-class apps) commit a PostgreSQL `db/structure.sql`
|
|
63
|
+
# instead of `db/schema.rb`. Used as the fallback schema source when `schema_file` is absent.
|
|
64
|
+
"structure_sql_file" => { kind: :string, default: "db/structure.sql" },
|
|
74
65
|
"model_search_paths" => { kind: :array, default: ["app/models"] },
|
|
75
66
|
"model_base_classes" => { kind: :array, default: %w[ApplicationRecord ActiveRecord::Base] }
|
|
76
67
|
},
|
|
77
68
|
produces: [:model_index],
|
|
78
|
-
# ADR-25 — the bundled `ActiveRecord::Relation` RBS that
|
|
79
|
-
#
|
|
80
|
-
# `Model.where`, scopes) dispatch against.
|
|
69
|
+
# ADR-25 — the bundled `ActiveRecord::Relation` RBS that relation-typed call sites (`has_many`
|
|
70
|
+
# accessors, `Model.where`, scopes) dispatch against.
|
|
81
71
|
signature_paths: ["sig"],
|
|
82
|
-
# ADR-26 — `ActiveRecord::Relation` is an "open" receiver:
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
# must not fire for it. `CheckRules` reads this manifest
|
|
86
|
-
# field and skips the rule for the class.
|
|
72
|
+
# ADR-26 — `ActiveRecord::Relation` is an "open" receiver: it delegates an unbounded set of
|
|
73
|
+
# user-defined scopes / class methods to its model, so `call.undefined-method` must not fire for
|
|
74
|
+
# it. `CheckRules` reads this manifest field and skips the rule for the class.
|
|
87
75
|
open_receivers: ["ActiveRecord::Relation"]
|
|
88
76
|
)
|
|
89
77
|
|
|
90
|
-
# The class the bundled `sig/active_record/relation.rbs`
|
|
91
|
-
#
|
|
92
|
-
# `
|
|
93
|
-
# call sites (`has_many` accessors, `Model.where`, scopes).
|
|
78
|
+
# The class the bundled `sig/active_record/relation.rbs` describes; `dynamic_return` contributes
|
|
79
|
+
# `ActiveRecord::Relation[Model]` for relation-returning call sites (`has_many` accessors,
|
|
80
|
+
# `Model.where`, scopes).
|
|
94
81
|
RELATION_CLASS_NAME = "ActiveRecord::Relation"
|
|
95
82
|
|
|
96
|
-
# Cached: parsed schema table. The producer reads `@schema_file`
|
|
97
|
-
#
|
|
98
|
-
#
|
|
83
|
+
# Cached: parsed schema table. The producer reads `@schema_file` via `io_boundary.read_file` so the
|
|
84
|
+
# descriptor picks up the digest, then parses through {SchemaParser}. When `db/schema.rb` is absent
|
|
85
|
+
# the producer falls back to a PostgreSQL `db/structure.sql` (`schema_format = :sql` apps) parsed
|
|
86
|
+
# through {StructureSqlParser} — both reads are captured into the record-and-validate descriptor.
|
|
99
87
|
producer :schema_table do |_params|
|
|
100
|
-
|
|
101
|
-
|
|
88
|
+
SchemaParser.parse(io_boundary.read_file(@schema_file))
|
|
89
|
+
rescue Errno::ENOENT
|
|
90
|
+
StructureSqlParser.parse(io_boundary.read_file(@structure_sql_file))
|
|
102
91
|
end
|
|
103
92
|
|
|
104
|
-
# Cached: model index. Walks every model file, then composes
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
# are captured into the record-and-validate dependency
|
|
108
|
-
# descriptor after the block runs.
|
|
93
|
+
# Cached: model index. Walks every model file, then composes the rows with the cached schema table.
|
|
94
|
+
# `watch:` (ADR-60 WD3) covers model-file additions; the discoverer's in-block reads are captured
|
|
95
|
+
# into the record-and-validate dependency descriptor after the block runs.
|
|
109
96
|
producer :model_index, watch: -> { [[@model_search_paths, "**/*.rb"]] } do |_params|
|
|
110
|
-
|
|
97
|
+
discoverer = ModelDiscoverer.new(
|
|
111
98
|
io_boundary: io_boundary,
|
|
112
99
|
search_paths: @model_search_paths,
|
|
113
100
|
base_classes: @model_base_classes
|
|
114
|
-
)
|
|
115
|
-
|
|
101
|
+
)
|
|
102
|
+
rows = discoverer.discover
|
|
103
|
+
ModelIndex.build(
|
|
104
|
+
model_rows: rows, schema_table: schema_table_or_nil,
|
|
105
|
+
type_override_columns: discoverer.type_override_columns
|
|
106
|
+
)
|
|
116
107
|
end
|
|
117
108
|
|
|
118
109
|
def init(_services)
|
|
119
110
|
@schema_file = config.fetch("schema_file")
|
|
111
|
+
@structure_sql_file = config.fetch("structure_sql_file")
|
|
120
112
|
@model_search_paths = Array(config.fetch("model_search_paths")).map(&:to_s)
|
|
121
113
|
@model_base_classes = Array(config.fetch("model_base_classes")).map(&:to_s)
|
|
122
114
|
@schema_table = nil
|
|
@@ -125,15 +117,11 @@ module Rigor
|
|
|
125
117
|
@load_errors = []
|
|
126
118
|
end
|
|
127
119
|
|
|
128
|
-
# ADR-9 cross-plugin publication. Builds the model index
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
# (c) attribute → column cross-check, future plugins
|
|
134
|
-
# that need to know "what columns does class `User`
|
|
135
|
-
# expose?") can read it without coupling to this
|
|
136
|
-
# plugin's carrier classes.
|
|
120
|
+
# ADR-9 cross-plugin publication. Builds the model index eagerly during the per-run
|
|
121
|
+
# `prepare(services)` pass and publishes a flat Hash form to the shared fact store so downstream
|
|
122
|
+
# Tier-2 consumers (rigor-actionpack Phase 1 strong-parameter validation, rigor-factorybot Phase 1
|
|
123
|
+
# (c) attribute → column cross-check, future plugins that need to know "what columns does class
|
|
124
|
+
# `User` expose?") can read it without coupling to this plugin's carrier classes.
|
|
137
125
|
#
|
|
138
126
|
# The published shape:
|
|
139
127
|
#
|
|
@@ -143,11 +131,9 @@ module Rigor
|
|
|
143
131
|
# ...
|
|
144
132
|
# }
|
|
145
133
|
#
|
|
146
|
-
# Consumers do `services.fact_store.read(plugin_id:
|
|
147
|
-
#
|
|
148
|
-
#
|
|
149
|
-
# unparseable models) leave the fact unpublished — the
|
|
150
|
-
# consumer's own degrade path runs (typically a no-op).
|
|
134
|
+
# Consumers do `services.fact_store.read(plugin_id: "activerecord", name: :model_index)` and look up
|
|
135
|
+
# by class name. Discovery failures (missing schema, unparseable models) leave the fact unpublished —
|
|
136
|
+
# the consumer's own degrade path runs (typically a no-op).
|
|
151
137
|
def prepare(services)
|
|
152
138
|
index = model_index
|
|
153
139
|
return if index.nil? || index.empty?
|
|
@@ -162,12 +148,10 @@ module Rigor
|
|
|
162
148
|
def diagnostics_for_file(path:, scope:, root:) # rubocop:disable Lint/UnusedMethodArgument
|
|
163
149
|
index = model_index
|
|
164
150
|
if index.nil?
|
|
165
|
-
# Project-global error (missing `db/schema.rb`, parse
|
|
166
|
-
#
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
# produced 346 identical load-errors; on a Solidus
|
|
170
|
-
# monorepo (no top-level `schema.rb`), 999.
|
|
151
|
+
# Project-global error (missing `db/schema.rb`, parse failure, etc.) — emit once per run rather
|
|
152
|
+
# than once per analyzed file. On a Redmine-shape project that uses migrations only (no
|
|
153
|
+
# `schema.rb`), the old path produced 346 identical load-errors; on a Solidus monorepo (no
|
|
154
|
+
# top-level `schema.rb`), 999.
|
|
171
155
|
return [] if @load_errors_emitted
|
|
172
156
|
|
|
173
157
|
@load_errors_emitted = true
|
|
@@ -179,15 +163,11 @@ module Rigor
|
|
|
179
163
|
Analyzer.new(path: path, model_index: index).analyze(root).diagnostics
|
|
180
164
|
end
|
|
181
165
|
|
|
182
|
-
# Rails migration files (`db/migrate/<timestamp>_*.rb`)
|
|
183
|
-
#
|
|
184
|
-
# the
|
|
185
|
-
#
|
|
186
|
-
#
|
|
187
|
-
# column, even though the current `db/schema.rb` no
|
|
188
|
-
# longer carries it. Validating these files against the
|
|
189
|
-
# CURRENT schema is a category error; the column
|
|
190
|
-
# diagnostics MUST stay silent.
|
|
166
|
+
# Rails migration files (`db/migrate/<timestamp>_*.rb`) and post-migration files
|
|
167
|
+
# (`db/post_migrate/`) reference the EVOLVING schema at the time the migration was written —
|
|
168
|
+
# `User.where(admin: ...)` is valid when the migration ran on a schema that still had the `admin`
|
|
169
|
+
# column, even though the current `db/schema.rb` no longer carries it. Validating these files
|
|
170
|
+
# against the CURRENT schema is a category error; the column diagnostics MUST stay silent.
|
|
191
171
|
MIGRATION_PATH_PATTERNS = [
|
|
192
172
|
%r{(\A|/)db/migrate/},
|
|
193
173
|
%r{(\A|/)db/post_migrate/}
|
|
@@ -201,48 +181,36 @@ module Rigor
|
|
|
201
181
|
MIGRATION_PATH_PATTERNS.any? { |pattern| path_s.match?(pattern) }
|
|
202
182
|
end
|
|
203
183
|
|
|
204
|
-
# The class-side finder / relation entry-point names
|
|
205
|
-
# `
|
|
206
|
-
#
|
|
207
|
-
# the model index (scopes, associations, columns).
|
|
184
|
+
# The class-side finder / relation entry-point names `finder_return_type` recognises. Static half of
|
|
185
|
+
# the `dynamic_return` name gate; the run-time half comes from the model index (scopes,
|
|
186
|
+
# associations, columns).
|
|
208
187
|
FINDER_METHOD_NAMES = %i[find find_by! find_by where all order limit none select].freeze
|
|
209
188
|
private_constant :FINDER_METHOD_NAMES
|
|
210
189
|
|
|
211
|
-
# Return-type contribution via the run-time `methods:` name
|
|
212
|
-
#
|
|
213
|
-
#
|
|
214
|
-
#
|
|
215
|
-
# normal dispatch instead of the RBS-level untyped
|
|
216
|
-
# fall-back; scopes, association accessors, and column
|
|
217
|
-
# readers narrow per the paths below.
|
|
190
|
+
# Return-type contribution via the run-time `methods:` name gate (ADR-52 slice 5b). `Model.find(id)`
|
|
191
|
+
# narrows the call site's return type to `Nominal[Model]`, so chained calls (`User.find(1).name`)
|
|
192
|
+
# resolve through the analyzer's normal dispatch instead of the RBS-level untyped fall-back; scopes,
|
|
193
|
+
# association accessors, and column readers narrow per the paths below.
|
|
218
194
|
#
|
|
219
|
-
# WHY a method-name gate and not `receivers:` — the ADR-52
|
|
220
|
-
#
|
|
221
|
-
#
|
|
222
|
-
#
|
|
223
|
-
#
|
|
224
|
-
#
|
|
225
|
-
#
|
|
226
|
-
#
|
|
227
|
-
# the
|
|
228
|
-
# column name (plus `column?` predicate forms) the model
|
|
229
|
-
# index discovered — is exactly the union of names the four
|
|
230
|
-
# resolution paths below can return a type for, so gating on
|
|
231
|
-
# it is byte-identical to the old ungated hook. It is broad
|
|
232
|
-
# (`name`, `id`, …), but membership is one Set probe and the
|
|
233
|
-
# expensive block runs only on candidate hits.
|
|
195
|
+
# WHY a method-name gate and not `receivers:` — the ADR-52 "rigor-activerecord blocker": a project
|
|
196
|
+
# model not in RBS types its constant as `Dynamic[top]`, so a receiver-type gate declines exactly the
|
|
197
|
+
# calls this plugin exists for. A *name* gate never reads the receiver type; the block keeps the
|
|
198
|
+
# plugin's own AST-constant / `self_type` / `type_of` resolution, so the Dynamic-constant case still
|
|
199
|
+
# reaches it (the same shape as rigor-sorbet's catalog path). The set — the static finder names ∪
|
|
200
|
+
# every scope, association, and column name (plus `column?` predicate forms) the model index
|
|
201
|
+
# discovered — is exactly the union of names the four resolution paths below can return a type for,
|
|
202
|
+
# so gating on it is byte-identical to the old ungated hook. It is broad (`name`, `id`, …), but
|
|
203
|
+
# membership is one Set probe and the expensive block runs only on candidate hits.
|
|
234
204
|
dynamic_return methods: -> { recognised_method_names } do |call_node, scope|
|
|
235
205
|
contribution_return_type(call_node, scope)
|
|
236
206
|
end
|
|
237
207
|
|
|
238
208
|
private
|
|
239
209
|
|
|
240
|
-
# The run-time name gate: finders ∪ scopes ∪ associations ∪
|
|
241
|
-
#
|
|
242
|
-
#
|
|
243
|
-
#
|
|
244
|
-
# then declines every call, matching the old hook's
|
|
245
|
-
# `index.nil? || index.empty?` early return.
|
|
210
|
+
# The run-time name gate: finders ∪ scopes ∪ associations ∪ column readers (+ `?` predicates).
|
|
211
|
+
# Resolved lazily on first dispatch (after `#prepare` built the index), memoised by the engine.
|
|
212
|
+
# Returns [] when discovery found nothing — the gate then declines every call, matching the old
|
|
213
|
+
# hook's `index.nil? || index.empty?` early return.
|
|
246
214
|
def recognised_method_names
|
|
247
215
|
index = model_index
|
|
248
216
|
return [] if index.nil? || index.empty?
|
|
@@ -259,8 +227,8 @@ module Rigor
|
|
|
259
227
|
names
|
|
260
228
|
end
|
|
261
229
|
|
|
262
|
-
# Resolution body for `dynamic_return` — same four-path
|
|
263
|
-
#
|
|
230
|
+
# Resolution body for `dynamic_return` — same four-path order, returning the bare type the contract
|
|
231
|
+
# expects.
|
|
264
232
|
def contribution_return_type(call_node, scope)
|
|
265
233
|
return nil unless call_node.is_a?(Prism::CallNode)
|
|
266
234
|
|
|
@@ -287,24 +255,19 @@ module Rigor
|
|
|
287
255
|
class_scope_return_type(call_node, entry)
|
|
288
256
|
end
|
|
289
257
|
|
|
290
|
-
# Implicit-self class-side call: `select(:uri)` /
|
|
291
|
-
#
|
|
292
|
-
#
|
|
293
|
-
#
|
|
294
|
-
# three cases, so the same finder / scope / relation entry-
|
|
295
|
-
# point resolution that handles `Model.where(...)` applies.
|
|
258
|
+
# Implicit-self class-side call: `select(:uri)` / `where(active: true)` inside a `def
|
|
259
|
+
# self.<method>` body, a class body, or a scope lambda body (`scope :x, -> { ... }`). The
|
|
260
|
+
# surrounding `self_type` is `Singleton[Model]` in all three cases, so the same finder / scope /
|
|
261
|
+
# relation entry-point resolution that handles `Model.where(...)` applies.
|
|
296
262
|
#
|
|
297
|
-
# Without this, `select(:uri)` inside a class body falls
|
|
298
|
-
#
|
|
299
|
-
#
|
|
300
|
-
#
|
|
301
|
-
# AR class-side `select`'s relation return type, so the
|
|
302
|
-
# canonical scope-body idiom
|
|
263
|
+
# Without this, `select(:uri)` inside a class body falls through to RBS dispatch on
|
|
264
|
+
# `Singleton[Account]`, which finds `Kernel#select` (the IO multiplexer) at `core/kernel.rbs` — its
|
|
265
|
+
# `Array[String]` return masks the AR class-side `select`'s relation return type, so the canonical
|
|
266
|
+
# scope-body idiom
|
|
303
267
|
#
|
|
304
268
|
# scope :duplicate_uris, -> { select(:uri).group(:uri) }
|
|
305
269
|
#
|
|
306
|
-
# types `select(:uri)` as `Array[String]` and the chained
|
|
307
|
-
# `.group` as `undefined-method`.
|
|
270
|
+
# types `select(:uri)` as `Array[String]` and the chained `.group` as `undefined-method`.
|
|
308
271
|
def implicit_self_class_call_return_type(call_node, scope, index)
|
|
309
272
|
return nil if scope.nil?
|
|
310
273
|
|
|
@@ -318,12 +281,10 @@ module Rigor
|
|
|
318
281
|
class_scope_return_type(call_node, entry)
|
|
319
282
|
end
|
|
320
283
|
|
|
321
|
-
# Class-side finders + the class-side relation entry points.
|
|
322
|
-
# `
|
|
323
|
-
#
|
|
324
|
-
#
|
|
325
|
-
# type through any further chained query method via the
|
|
326
|
-
# bundled `ActiveRecord::Relation` RBS.
|
|
284
|
+
# Class-side finders + the class-side relation entry points. `find` / `find_by!` return the model;
|
|
285
|
+
# `find_by` adds the `nil` arm; `where` / `all` / `order` / `limit` / `none` open a relation. The
|
|
286
|
+
# relation then carries its element type through any further chained query method via the bundled
|
|
287
|
+
# `ActiveRecord::Relation` RBS.
|
|
327
288
|
def finder_return_type(call_node, entry)
|
|
328
289
|
case call_node.name
|
|
329
290
|
when :find
|
|
@@ -331,8 +292,8 @@ module Rigor
|
|
|
331
292
|
|
|
332
293
|
Rigor::Type::Combinator.nominal_of(entry.class_name)
|
|
333
294
|
when :find_by!
|
|
334
|
-
# The bang variant raises `RecordNotFound` instead of
|
|
335
|
-
#
|
|
295
|
+
# The bang variant raises `RecordNotFound` instead of returning `nil`, so the result is
|
|
296
|
+
# non-nullable.
|
|
336
297
|
Rigor::Type::Combinator.nominal_of(entry.class_name)
|
|
337
298
|
when :find_by
|
|
338
299
|
Rigor::Type::Combinator.union(
|
|
@@ -341,31 +302,26 @@ module Rigor
|
|
|
341
302
|
)
|
|
342
303
|
when :where, :all, :order, :limit, :none, :select
|
|
343
304
|
# `:select` was added to close Mastodon's
|
|
344
|
-
# `scope :duplicate_uris, -> { select(:uri).group(:uri).having(...) }`
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
#
|
|
348
|
-
#
|
|
349
|
-
# query DSL chains through the bundled `ActiveRecord::Relation`
|
|
350
|
-
# RBS once a relation is open.
|
|
305
|
+
# `scope :duplicate_uris, -> { select(:uri).group(:uri).having(...) }` shape: the implicit-self
|
|
306
|
+
# `select(:uri)` inside the scope lambda body had been resolving to `Kernel#select` (IO
|
|
307
|
+
# multiplexer, return `Array[String]`), masking the AR class-side relation entry point. The rest
|
|
308
|
+
# of the query DSL chains through the bundled `ActiveRecord::Relation` RBS once a relation is
|
|
309
|
+
# open.
|
|
351
310
|
relation_of(entry.class_name)
|
|
352
311
|
end
|
|
353
312
|
end
|
|
354
313
|
|
|
355
|
-
# `Post.published` / `Post.recent(5)` — a user-declared
|
|
356
|
-
#
|
|
357
|
-
# arguments it takes.
|
|
314
|
+
# `Post.published` / `Post.recent(5)` — a user-declared `scope` returns a relation of the model
|
|
315
|
+
# regardless of the arguments it takes.
|
|
358
316
|
def class_scope_return_type(call_node, entry)
|
|
359
317
|
return nil unless entry.scope?(call_node.name)
|
|
360
318
|
|
|
361
319
|
relation_of(entry.class_name)
|
|
362
320
|
end
|
|
363
321
|
|
|
364
|
-
# `ActiveRecord::Relation[Model]` — the type the bundled
|
|
365
|
-
# `
|
|
366
|
-
#
|
|
367
|
-
# scope call the bundled RBS cannot enumerate does not
|
|
368
|
-
# surface as `call.undefined-method` (ADR-26).
|
|
322
|
+
# `ActiveRecord::Relation[Model]` — the type the bundled `sig/active_record/relation.rbs` describes.
|
|
323
|
+
# The class is declared `open_receivers` in the manifest, so a chained scope call the bundled RBS
|
|
324
|
+
# cannot enumerate does not surface as `call.undefined-method` (ADR-26).
|
|
369
325
|
def relation_of(model_class_name)
|
|
370
326
|
Rigor::Type::Combinator.nominal_of(
|
|
371
327
|
RELATION_CLASS_NAME,
|
|
@@ -373,24 +329,17 @@ module Rigor
|
|
|
373
329
|
)
|
|
374
330
|
end
|
|
375
331
|
|
|
376
|
-
# A scope invoked on an already-typed relation
|
|
377
|
-
#
|
|
378
|
-
#
|
|
379
|
-
# RBS
|
|
380
|
-
#
|
|
381
|
-
#
|
|
382
|
-
# resolves `where` / `order` / `each` / `first` precisely.
|
|
383
|
-
# Scopes may take arguments (`relation.recent(5)`), so —
|
|
384
|
-
# unlike `instance_call_return_type` — argument calls are
|
|
385
|
-
# not skipped.
|
|
332
|
+
# A scope invoked on an already-typed relation (`User.where(active: true).published`) keeps the
|
|
333
|
+
# relation type through the chain. The bundled `ActiveRecord::Relation` RBS cannot enumerate
|
|
334
|
+
# user-defined scopes, so without this the chain would lose its element type after the first scope
|
|
335
|
+
# call. Non-scope methods decline — the RBS tier resolves `where` / `order` / `each` / `first`
|
|
336
|
+
# precisely. Scopes may take arguments (`relation.recent(5)`), so — unlike `instance_call_return_type`
|
|
337
|
+
# — argument calls are not skipped.
|
|
386
338
|
#
|
|
387
|
-
# The cheap `scope_name?` pre-check is load-bearing: it
|
|
388
|
-
#
|
|
389
|
-
#
|
|
390
|
-
#
|
|
391
|
-
# and calling it for every call node in a long method chain
|
|
392
|
-
# is pathologically expensive — the pre-check keeps the
|
|
393
|
-
# cost off the hot path.
|
|
339
|
+
# The cheap `scope_name?` pre-check is load-bearing: it gates the `scope.type_of(receiver)` call so
|
|
340
|
+
# the receiver type is computed ONLY when the method name could be a scope. `type_of` on a call
|
|
341
|
+
# receiver re-enters dispatch, and calling it for every call node in a long method chain is
|
|
342
|
+
# pathologically expensive — the pre-check keeps the cost off the hot path.
|
|
394
343
|
def relation_call_return_type(call_node, scope, index)
|
|
395
344
|
return nil if call_node.receiver.nil?
|
|
396
345
|
return nil unless scope_name?(call_node.name, index)
|
|
@@ -405,16 +354,15 @@ module Rigor
|
|
|
405
354
|
relation_of(model_name)
|
|
406
355
|
end
|
|
407
356
|
|
|
408
|
-
# Whether `name` is a declared `scope` on ANY model in the
|
|
409
|
-
#
|
|
410
|
-
# in `relation_call_return_type` stays O(1).
|
|
357
|
+
# Whether `name` is a declared `scope` on ANY model in the index. A run-lifetime memoised Set so the
|
|
358
|
+
# per-call check in `relation_call_return_type` stays O(1).
|
|
411
359
|
def scope_name?(name, index)
|
|
412
360
|
@all_scope_names ||= index.entries.each_value.flat_map(&:scopes).to_set
|
|
413
361
|
@all_scope_names.include?(name.to_s)
|
|
414
362
|
end
|
|
415
363
|
|
|
416
|
-
# When `type` is `ActiveRecord::Relation[Nominal[Model]]`,
|
|
417
|
-
#
|
|
364
|
+
# When `type` is `ActiveRecord::Relation[Nominal[Model]]`, returns the model class name; nil for
|
|
365
|
+
# any other type.
|
|
418
366
|
def relation_element_class_name(type)
|
|
419
367
|
return nil unless type.is_a?(Rigor::Type::Nominal)
|
|
420
368
|
return nil unless type.class_name == RELATION_CLASS_NAME
|
|
@@ -423,13 +371,10 @@ module Rigor
|
|
|
423
371
|
element.class_name if element.is_a?(Rigor::Type::Nominal)
|
|
424
372
|
end
|
|
425
373
|
|
|
426
|
-
# Instance-side navigation: when the call's receiver
|
|
427
|
-
#
|
|
428
|
-
#
|
|
429
|
-
#
|
|
430
|
-
# skipped — accessor / association calls take no args, and
|
|
431
|
-
# argument forms (`user.posts(limit: 10)`, `user.name = x`)
|
|
432
|
-
# route through Rails APIs this slice does not model.
|
|
374
|
+
# Instance-side navigation: when the call's receiver resolves to `Nominal[Model]` and the method name
|
|
375
|
+
# matches a discovered association OR a table column, the call site gets a precise return type.
|
|
376
|
+
# Calls with arguments are skipped — accessor / association calls take no args, and argument forms
|
|
377
|
+
# (`user.posts(limit: 10)`, `user.name = x`) route through Rails APIs this slice does not model.
|
|
433
378
|
def instance_call_return_type(call_node, scope, index)
|
|
434
379
|
return nil unless call_node.arguments.nil?
|
|
435
380
|
|
|
@@ -444,16 +389,12 @@ module Rigor
|
|
|
444
389
|
column_return_type(entry, call_node.name)
|
|
445
390
|
end
|
|
446
391
|
|
|
447
|
-
# The return type for an association accessor. A `belongs_to`
|
|
448
|
-
#
|
|
449
|
-
#
|
|
450
|
-
#
|
|
451
|
-
#
|
|
452
|
-
#
|
|
453
|
-
# collection narrows to `ActiveRecord::Relation[Target]` so
|
|
454
|
-
# chained query / iteration calls resolve. A polymorphic
|
|
455
|
-
# association has no single static target and declines
|
|
456
|
-
# rather than inventing a wrong type.
|
|
392
|
+
# The return type for an association accessor. A `belongs_to` / `has_one` singular association
|
|
393
|
+
# narrows to the target model — `belongs_to` is required (non-`nil`) by default since Rails 5 so it
|
|
394
|
+
# is `Nominal[Target]`, while `has_one` (and an `optional: true` / `required: false` `belongs_to`)
|
|
395
|
+
# adds the `nil` arm. A `has_many` / `has_and_belongs_to_many` collection narrows to
|
|
396
|
+
# `ActiveRecord::Relation[Target]` so chained query / iteration calls resolve. A polymorphic
|
|
397
|
+
# association has no single static target and declines rather than inventing a wrong type.
|
|
457
398
|
def association_return_type(entry, method_name)
|
|
458
399
|
association = entry.association(method_name)
|
|
459
400
|
return nil if association.nil?
|
|
@@ -470,19 +411,14 @@ module Rigor
|
|
|
470
411
|
end
|
|
471
412
|
end
|
|
472
413
|
|
|
473
|
-
# Instance-side column access. `user.name` on a
|
|
474
|
-
# `
|
|
475
|
-
# type; `user.name?` (the ActiveRecord-generated predicate)
|
|
476
|
-
# narrows to `bool`.
|
|
414
|
+
# Instance-side column access. `user.name` on a `Nominal[User]` receiver narrows to the column's
|
|
415
|
+
# value type; `user.name?` (the ActiveRecord-generated predicate) narrows to `bool`.
|
|
477
416
|
#
|
|
478
|
-
# The contributed type is deliberately NON-nullable even
|
|
479
|
-
#
|
|
480
|
-
#
|
|
481
|
-
#
|
|
482
|
-
#
|
|
483
|
-
# entire codebase. Under-reporting a nil column is a false
|
|
484
|
-
# negative; over-reporting it is a false positive — and the
|
|
485
|
-
# project ranks the latter as the worse failure.
|
|
417
|
+
# The contributed type is deliberately NON-nullable even though the DB column may permit `NULL`:
|
|
418
|
+
# Rails code calls column accessors directly (`user.email.downcase`) as a matter of course, and
|
|
419
|
+
# contributing `T | nil` would light up that idiom with `possible-nil-receiver` across an entire
|
|
420
|
+
# codebase. Under-reporting a nil column is a false negative; over-reporting it is a false positive
|
|
421
|
+
# — and the project ranks the latter as the worse failure.
|
|
486
422
|
def column_return_type(entry, method_name)
|
|
487
423
|
name = method_name.to_s
|
|
488
424
|
predicate = name.end_with?("?")
|
|
@@ -498,12 +434,10 @@ module Rigor
|
|
|
498
434
|
column.array? ? Rigor::Type::Combinator.nominal_of("Array", type_args: [inner]) : inner
|
|
499
435
|
end
|
|
500
436
|
|
|
501
|
-
# Maps a `SchemaTable::Column#ruby_type` string to a Rigor
|
|
502
|
-
#
|
|
503
|
-
#
|
|
504
|
-
#
|
|
505
|
-
# `call.undefined-method` on a value whose real shape the
|
|
506
|
-
# plugin cannot model.
|
|
437
|
+
# Maps a `SchemaTable::Column#ruby_type` string to a Rigor type. `"Object"` (json / jsonb /
|
|
438
|
+
# unrecognised column types) declines — `Nominal[Object]` would be NARROWER than the RBS-erased
|
|
439
|
+
# envelope and could surface false `call.undefined-method` on a value whose real shape the plugin
|
|
440
|
+
# cannot model.
|
|
507
441
|
def ruby_type_to_type(ruby_type)
|
|
508
442
|
case ruby_type
|
|
509
443
|
when "bool" then bool_type
|
|
@@ -546,12 +480,9 @@ module Rigor
|
|
|
546
480
|
node.arguments.arguments.size
|
|
547
481
|
end
|
|
548
482
|
|
|
549
|
-
# Marshal-clean Hash form for the cross-plugin fact
|
|
550
|
-
#
|
|
551
|
-
#
|
|
552
|
-
# `class_name → { table:, columns: }` map without
|
|
553
|
-
# depending on this plugin's `ModelIndex` /
|
|
554
|
-
# `SchemaTable::Column` carrier classes.
|
|
483
|
+
# Marshal-clean Hash form for the cross-plugin fact store. Consumers (rigor-actionpack Phase 1,
|
|
484
|
+
# rigor-factorybot Phase 1 (c), ...) get a flat `class_name → { table:, columns: }` map without
|
|
485
|
+
# depending on this plugin's `ModelIndex` / `SchemaTable::Column` carrier classes.
|
|
555
486
|
def index_to_published_hash(index)
|
|
556
487
|
index.entries.transform_values do |entry|
|
|
557
488
|
{
|
|
@@ -573,11 +504,9 @@ module Rigor
|
|
|
573
504
|
table = schema_table_or_nil
|
|
574
505
|
return nil if table.nil?
|
|
575
506
|
|
|
576
|
-
# ADR-60 WD3 record-and-validate: the producer's own in-block
|
|
577
|
-
#
|
|
578
|
-
#
|
|
579
|
-
# covers model-file additions — so no priming walk is needed
|
|
580
|
-
# (it used to run the discover twice).
|
|
507
|
+
# ADR-60 WD3 record-and-validate: the producer's own in-block `ModelDiscoverer` reads are
|
|
508
|
+
# captured into the dependency descriptor after the block runs, and the producer's `watch:` covers
|
|
509
|
+
# model-file additions — so no priming walk is needed (it used to run the discover twice).
|
|
581
510
|
@model_index = cache_for(:model_index, params: {}).call
|
|
582
511
|
rescue StandardError => e
|
|
583
512
|
@load_errors << "model index build failed: #{e.class}: #{e.message}"
|
|
@@ -586,26 +515,24 @@ module Rigor
|
|
|
586
515
|
|
|
587
516
|
def schema_table_or_nil
|
|
588
517
|
return @schema_table if @schema_table
|
|
589
|
-
# Memoize the *failure*, not just the success: `model_index`
|
|
590
|
-
#
|
|
591
|
-
#
|
|
592
|
-
#
|
|
593
|
-
#
|
|
594
|
-
# `@load_errors` to millions of retained strings (measured: 4.2 M
|
|
595
|
-
# strings / ~1.5 GB on Redmine). One attempt is enough.
|
|
518
|
+
# Memoize the *failure*, not just the success: `model_index` (and thus this method) is invoked per
|
|
519
|
+
# AR call site, so a missing / unreadable schema file would otherwise re-attempt the read and
|
|
520
|
+
# append a fresh interpolated error string to `@load_errors` on every call. On a large Rails app
|
|
521
|
+
# that grew `@load_errors` to millions of retained strings (measured: 4.2 M strings / ~1.5 GB on
|
|
522
|
+
# Redmine). One attempt is enough.
|
|
596
523
|
return nil if @schema_load_attempted
|
|
597
524
|
|
|
598
525
|
@schema_load_attempted = true
|
|
599
|
-
# ADR-60 WD3 record-and-validate: the producer reads
|
|
600
|
-
#
|
|
601
|
-
#
|
|
602
|
-
# read is needed here.
|
|
526
|
+
# ADR-60 WD3 record-and-validate: the producer reads `@schema_file` in-block, and that read is
|
|
527
|
+
# captured into the dependency descriptor after the block runs — so no priming read is needed
|
|
528
|
+
# here.
|
|
603
529
|
@schema_table = cache_for(:schema_table, params: {}).call
|
|
604
530
|
rescue Plugin::AccessDeniedError => e
|
|
605
531
|
@load_errors << "rigor-activerecord: #{e.message}"
|
|
606
532
|
nil
|
|
607
533
|
rescue Errno::ENOENT
|
|
608
|
-
@load_errors << "rigor-activerecord: schema file `#{@schema_file}`
|
|
534
|
+
@load_errors << "rigor-activerecord: schema file `#{@schema_file}` (or `#{@structure_sql_file}`) " \
|
|
535
|
+
"not found; AR call checks skipped"
|
|
609
536
|
nil
|
|
610
537
|
rescue StandardError => e
|
|
611
538
|
@load_errors << "rigor-activerecord: failed to parse `#{@schema_file}`: #{e.class}: #{e.message}"
|