rigortype 0.3.8 → 0.4.0
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 +2 -2
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +3 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +112 -14
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -6
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +2 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +12 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +36 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +10 -17
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +2 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +10 -5
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
#
|
|
32
32
|
# Every method carries an effect annotation, and the split down
|
|
33
33
|
# the middle of this file is the whole point of the Rails effect
|
|
34
|
-
# layer: a **builder** is `%a{pure}` because it issues nothing —
|
|
34
|
+
# layer: a **query builder** is `%a{pure}` because it issues nothing —
|
|
35
35
|
# `where` composes an Arel tree and returns a relation — while a
|
|
36
36
|
# **materializer** is `%a{rigor:v1:effect io.db.read}` because it
|
|
37
37
|
# is the call that finally runs the query. A presenter that builds
|
|
@@ -46,6 +46,136 @@
|
|
|
46
46
|
# `Enumerable` surface, which materialise by delegating to `each`
|
|
47
47
|
# — are covered by the plugin's `effect_attributions:` instead,
|
|
48
48
|
# because declaring them here would change how they TYPE.
|
|
49
|
+
#
|
|
50
|
+
# ## Every bound here also bounds the association's relations
|
|
51
|
+
#
|
|
52
|
+
# A `has_many` reader returns an
|
|
53
|
+
# `ActiveRecord::Associations::CollectionProxy`, and a query
|
|
54
|
+
# builder called on the proxy (`user.posts.where(…)`) returns an
|
|
55
|
+
# `ActiveRecord::AssociationRelation`. Both are Relation subclasses
|
|
56
|
+
# that still hold the association, and the plugin types both as
|
|
57
|
+
# `Relation[Model]`. A call on either imports this file's bound, so
|
|
58
|
+
# each annotation has to hold for all three classes. The facts below
|
|
59
|
+
# are checked against activerecord 8.1.3.1.
|
|
60
|
+
#
|
|
61
|
+
# Where one of them adds records to the association's in-memory
|
|
62
|
+
# target or discards them from it, the bound carries `mutate.self`:
|
|
63
|
+
#
|
|
64
|
+
# - `build` / `new`, `create` / `create!` and the `find_or_*`,
|
|
65
|
+
# `create_or_find_by` and `first_or_*` builders reach
|
|
66
|
+
# `@association.build` / `create`, which call `add_to_target`. On
|
|
67
|
+
# the proxy they are overrides. On an AssociationRelation they are
|
|
68
|
+
# its private `_new` / `_create`.
|
|
69
|
+
# - `reset`, `reload`, `delete_all` and `destroy_all` on the proxy
|
|
70
|
+
# reset the association, which drops every record built there and
|
|
71
|
+
# not yet saved. So do `update_all` and `touch_all`: the proxy does
|
|
72
|
+
# not override them, and Relation's version ends with
|
|
73
|
+
# `.tap { reset }`, which reaches the proxy's `reset`.
|
|
74
|
+
# - `insert`, `insert!` and `upsert`, and their `_all` forms, on the
|
|
75
|
+
# proxy reset the target only when it holds no unsaved record.
|
|
76
|
+
# Rails 8.1 deprecates the other branch and says those records will
|
|
77
|
+
# be lost in 8.2. The bound is written for 8.2, and it over-states
|
|
78
|
+
# 8.1.
|
|
79
|
+
#
|
|
80
|
+
# So `user.posts.build` changes an object the caller can still reach
|
|
81
|
+
# through `user`: `user.posts.size` counts the new record, and
|
|
82
|
+
# `user.save` saves it. On a plain Relation, `new` and `build` change
|
|
83
|
+
# nothing, so `mutate.self` over-states them there. The type cannot
|
|
84
|
+
# tell the receivers apart, and an upper bound may be too wide but
|
|
85
|
+
# never too narrow.
|
|
86
|
+
#
|
|
87
|
+
# Loading is not counted as a change. `to_a` and `load` fill the
|
|
88
|
+
# target with what the database holds, which is the `io.db.read` they
|
|
89
|
+
# already carry.
|
|
90
|
+
#
|
|
91
|
+
# `mutate.self` is written from the callee's side, as any envelope
|
|
92
|
+
# is: the receiver changes itself. A caller imports the label
|
|
93
|
+
# unchanged, so in the caller's row it names the proxy it called,
|
|
94
|
+
# not the caller's own `self`.
|
|
95
|
+
#
|
|
96
|
+
# `insert`, `insert!` and `upsert` are declared here, beside their
|
|
97
|
+
# `_all` forms, because a plain Relation defines them too. The
|
|
98
|
+
# declaration changes no result type: an undeclared method on this
|
|
99
|
+
# open receiver already types as `untyped`. It adds the checks any
|
|
100
|
+
# declared method gets, `call.wrong-arity` and
|
|
101
|
+
# `call.possible-nil-receiver`, and its parameter list admits every
|
|
102
|
+
# call Rails accepts.
|
|
103
|
+
#
|
|
104
|
+
# The writers a plain Relation does not define (`<<`, `push`,
|
|
105
|
+
# `append`, `concat`, `replace`, `clear`) are rows in the plugin's
|
|
106
|
+
# `effect_attributions:` rather than declarations here. The same rows
|
|
107
|
+
# cover `delete` / `destroy`, which a Relation does define, as
|
|
108
|
+
# `delete(id_or_array)` and `destroy(id)`, but the proxy overrides as
|
|
109
|
+
# `delete(*records)` and `destroy(*records)`. A declaration here
|
|
110
|
+
# would need a parameter list and a return wide enough for both, and
|
|
111
|
+
# it would give the two methods a second effect channel next to
|
|
112
|
+
# their rows.
|
|
113
|
+
#
|
|
114
|
+
# ## Every parameter list here also admits the overrides
|
|
115
|
+
#
|
|
116
|
+
# The rule above holds for parameter lists as well as effect bounds.
|
|
117
|
+
# A call on the proxy or on an AssociationRelation is checked against
|
|
118
|
+
# the parameter list declared here, so a declaration must accept
|
|
119
|
+
# every argument an override accepts, or valid Rails draws
|
|
120
|
+
# `call.wrong-arity`. Of the overrides this file declares, only the
|
|
121
|
+
# proxy's `delete_all(dependent = nil)` accepts more than the
|
|
122
|
+
# Relation's `delete_all`. It takes `:nullify` or `:delete_all`, so
|
|
123
|
+
# `delete_all` declares an optional argument. The price is that
|
|
124
|
+
# `delete_all(:nullify)` on a plain Relation or on an
|
|
125
|
+
# AssociationRelation (`user.posts.where(…)`), neither of which
|
|
126
|
+
# overrides it, raises `ArgumentError` and goes unreported.
|
|
127
|
+
#
|
|
128
|
+
# Of the rest, the `(...)` methods of the `insert` and `insert_all`
|
|
129
|
+
# families and the proxy's `delegate … to: :scope` block (the query
|
|
130
|
+
# builders and `scoping`) forward their arguments unchanged to the
|
|
131
|
+
# Relation's own methods, and the proxy's other overrides (`find`,
|
|
132
|
+
# `last`, `take`, `build`, `create`, `calculate`, `pluck`, …) take no
|
|
133
|
+
# more than the declarations here. `delete` and `destroy`, whose
|
|
134
|
+
# overrides take more arguments than the Relation's, stay undeclared
|
|
135
|
+
# for the reasons above.
|
|
136
|
+
#
|
|
137
|
+
# ## A writer that also queries carries the read too
|
|
138
|
+
#
|
|
139
|
+
# `io.db.write` does not include `io.db.read`: they are sibling
|
|
140
|
+
# leaves. So a writer that queries before its write, or after a failed
|
|
141
|
+
# one, names both. In activerecord 8.1.3.1:
|
|
142
|
+
#
|
|
143
|
+
# - `find_or_create_by(!)` is `find_by || create_or_find_by`, and
|
|
144
|
+
# `first_or_create(!)` is `first || create`.
|
|
145
|
+
# - `create_or_find_by(!)` rescues `RecordNotUnique` with `find_by!`.
|
|
146
|
+
# - `destroy_all` is `records.each(&:destroy)`, which loads first, and
|
|
147
|
+
# `destroy_by` is `where(…).destroy_all`. `update(!)` walks `each`,
|
|
148
|
+
# or passes an id to the model's `update`, which calls `find`.
|
|
149
|
+
# - `update_all` and `delete_all`, and so `touch_all` and `delete_by`,
|
|
150
|
+
# first `SELECT` the distinct primary keys when the relation
|
|
151
|
+
# eager-loads, has a limit or offset and no `group`, and eager-loads
|
|
152
|
+
# or joins a collection association (`apply_join_dependency`). The
|
|
153
|
+
# proxy's `delete_all` on a `has_many :through` loads the target
|
|
154
|
+
# before it deletes.
|
|
155
|
+
# - `create(!)` on the proxy of a `has_many :through` a `has_one`
|
|
156
|
+
# builds the join record through the `has_one`, which loads the
|
|
157
|
+
# record it replaces.
|
|
158
|
+
#
|
|
159
|
+
# The `insert` and `insert_all` families stay `io.db.write` alone.
|
|
160
|
+
# Each compiles one `INSERT` statement and queries nothing else: the
|
|
161
|
+
# proxy's override reads only the target it already holds in memory.
|
|
162
|
+
#
|
|
163
|
+
# Two kinds of query are not counted. Schema reflection is one: the
|
|
164
|
+
# column and index lookups the schema cache serves would otherwise
|
|
165
|
+
# make `where` a read. The model's callbacks and validators are the
|
|
166
|
+
# other, including those an association option such as `dependent:`
|
|
167
|
+
# or `touch:` registers. They are not part of any bound here. The
|
|
168
|
+
# plugin's callback edge carries only symbol-argument callback macros
|
|
169
|
+
# and a uniqueness validator, and only on the model's own `save` /
|
|
170
|
+
# `destroy`. Nothing carries the reads a required `belongs_to`,
|
|
171
|
+
# `touch:` or `dependent:` registers.
|
|
172
|
+
#
|
|
173
|
+
# One case is not covered. On that same `has_many :through` a
|
|
174
|
+
# `has_one`, `new` / `build` also build the join record when the
|
|
175
|
+
# source reflection has an inverse, and so do `find_or_initialize_by`
|
|
176
|
+
# and `first_or_initialize`, which reach `new`. The `has_one` then
|
|
177
|
+
# replaces its record: it loads the old one, and even without a
|
|
178
|
+
# save it can delete, destroy or save it.
|
|
49
179
|
|
|
50
180
|
module ActiveRecord
|
|
51
181
|
class Relation[Elem]
|
|
@@ -101,6 +231,10 @@ module ActiveRecord
|
|
|
101
231
|
def left_outer_joins: (*untyped) -> self
|
|
102
232
|
%a{pure}
|
|
103
233
|
def references: (*untyped) -> self
|
|
234
|
+
# With a block, `select` is Enumerable's and returns an Array. It
|
|
235
|
+
# stays `self`: on this open receiver a method the file does not
|
|
236
|
+
# declare is not reported, while on `Array[Elem]` any ActiveSupport
|
|
237
|
+
# method the bundled overlay leaves out would be.
|
|
104
238
|
%a{pure}
|
|
105
239
|
def select: (*untyped) -> self
|
|
106
240
|
%a{pure}
|
|
@@ -145,9 +279,33 @@ module ActiveRecord
|
|
|
145
279
|
def with: (*untyped) -> self
|
|
146
280
|
def scoping: () { () -> untyped } -> untyped
|
|
147
281
|
|
|
148
|
-
# --- finders (return an element
|
|
149
|
-
|
|
150
|
-
|
|
282
|
+
# --- finders (return an element, or an Array of them; `find`
|
|
283
|
+
# with a block, the element or nil) ---
|
|
284
|
+
# Two or more ids return an Array, unless dropping `nil`s and
|
|
285
|
+
# duplicates leaves one. One argument returns an Array when it is an
|
|
286
|
+
# Array of ids, but one record when it is a composite key's tuple
|
|
287
|
+
# (`[shop_id, id]`), and nothing here can tell those apart. An
|
|
288
|
+
# overload keyed on an `Array` argument would be selected for every
|
|
289
|
+
# untyped id too (`find(params[:id])`). Its return would be joined
|
|
290
|
+
# with this one's into `Dynamic[Array[Elem] | Elem]`, on which a
|
|
291
|
+
# following `update` or `save` no longer resolves on the model and
|
|
292
|
+
# loses its `io.db.write`. So a single argument stays `Elem`. A
|
|
293
|
+
# splat and a `**` hash each count as one argument, so `find(*ids)`
|
|
294
|
+
# is `Elem`, while `find(id, *ids)` and `find(*args, **opts)` are
|
|
295
|
+
# Arrays even when the splat or the hash turns out empty.
|
|
296
|
+
#
|
|
297
|
+
# With a block `find` is `Enumerable#find` (`return super if
|
|
298
|
+
# block_given?`), so the id overloads do not apply: no argument
|
|
299
|
+
# returns the element or `nil`, and one argument is the `ifnone`
|
|
300
|
+
# callable, whose result joins the union. That form is rare, so
|
|
301
|
+
# it stays `untyped` rather than typing the callable. The
|
|
302
|
+
# class-side `Model.find { … }` reaches this same method through
|
|
303
|
+
# `all`.
|
|
304
|
+
%a{rigor:v1:effect io.db.read}
|
|
305
|
+
def find: () { (Elem) -> boolish } -> Elem?
|
|
306
|
+
| (untyped ifnone) { (Elem) -> boolish } -> untyped
|
|
307
|
+
| (untyped, untyped, *untyped) -> Array[Elem]
|
|
308
|
+
| (?untyped id) -> Elem
|
|
151
309
|
%a{rigor:v1:effect io.db.read}
|
|
152
310
|
def find_by: (*untyped) -> Elem?
|
|
153
311
|
%a{rigor:v1:effect io.db.read}
|
|
@@ -243,9 +401,9 @@ module ActiveRecord
|
|
|
243
401
|
def entries: () -> Array[Elem]
|
|
244
402
|
%a{rigor:v1:effect io.db.read}
|
|
245
403
|
def load: (?untyped) -> self
|
|
246
|
-
%a{rigor:v1:effect io.db.read}
|
|
404
|
+
%a{rigor:v1:effect io.db.read, mutate.self}
|
|
247
405
|
def reload: () -> self
|
|
248
|
-
%a{
|
|
406
|
+
%a{rigor:v1:effect mutate.self}
|
|
249
407
|
def reset: () -> self
|
|
250
408
|
%a{pure}
|
|
251
409
|
def loaded?: () -> bool
|
|
@@ -272,56 +430,73 @@ module ActiveRecord
|
|
|
272
430
|
%a{pure}
|
|
273
431
|
def table: () -> untyped
|
|
274
432
|
%a{pure}
|
|
275
|
-
def arel: () -> untyped
|
|
433
|
+
def arel: (?untyped aliases) -> untyped
|
|
276
434
|
|
|
277
435
|
# --- whole-relation persistence ---
|
|
278
|
-
%a{rigor:v1:effect io.db.write}
|
|
436
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
279
437
|
def update_all: (untyped) -> Integer
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
438
|
+
# The optional argument is the association proxy's `dependent`
|
|
439
|
+
# (see the header). A plain Relation's and an AssociationRelation's
|
|
440
|
+
# `delete_all` take none.
|
|
441
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
442
|
+
def delete_all: (?untyped dependent) -> Integer
|
|
443
|
+
# On a plain `has_many`, the proxy's `destroy_all` returns `nil`
|
|
444
|
+
# when a `before_remove` callback throws `:abort`. A `:through` one,
|
|
445
|
+
# which includes `has_and_belongs_to_many`, still returns the
|
|
446
|
+
# records. `Array[Elem]?` would report `call.possible-nil-receiver`
|
|
447
|
+
# on every `destroyed.each` for a case only such a callback reaches.
|
|
448
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
283
449
|
def destroy_all: () -> Array[Elem]
|
|
284
|
-
%a{rigor:v1:effect io.db.write}
|
|
450
|
+
%a{rigor:v1:effect io.db.read, io.db.write}
|
|
285
451
|
def update: (*untyped) -> untyped
|
|
286
|
-
%a{rigor:v1:effect io.db.write}
|
|
452
|
+
%a{rigor:v1:effect io.db.read, io.db.write}
|
|
287
453
|
def update!: (*untyped) -> untyped
|
|
288
|
-
%a{rigor:v1:effect io.db.write}
|
|
454
|
+
%a{rigor:v1:effect io.db.read, io.db.write}
|
|
289
455
|
def delete_by: (*untyped) -> Integer
|
|
290
|
-
%a{rigor:v1:effect io.db.write}
|
|
456
|
+
%a{rigor:v1:effect io.db.read, io.db.write}
|
|
291
457
|
def destroy_by: (*untyped) -> Array[Elem]
|
|
292
|
-
%a{rigor:v1:effect io.db.write}
|
|
458
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
293
459
|
def touch_all: (*untyped) -> Integer
|
|
294
|
-
%a{rigor:v1:effect io.db.write}
|
|
460
|
+
%a{rigor:v1:effect io.db.write, mutate.self}
|
|
461
|
+
def insert: (untyped, **untyped) -> untyped
|
|
462
|
+
%a{rigor:v1:effect io.db.write, mutate.self}
|
|
295
463
|
def insert_all: (untyped, **untyped) -> untyped
|
|
296
|
-
%a{rigor:v1:effect io.db.write}
|
|
464
|
+
%a{rigor:v1:effect io.db.write, mutate.self}
|
|
465
|
+
def insert!: (untyped, **untyped) -> untyped
|
|
466
|
+
%a{rigor:v1:effect io.db.write, mutate.self}
|
|
297
467
|
def insert_all!: (untyped, **untyped) -> untyped
|
|
298
|
-
%a{rigor:v1:effect io.db.write}
|
|
468
|
+
%a{rigor:v1:effect io.db.write, mutate.self}
|
|
469
|
+
def upsert: (untyped, **untyped) -> untyped
|
|
470
|
+
%a{rigor:v1:effect io.db.write, mutate.self}
|
|
299
471
|
def upsert_all: (untyped, **untyped) -> untyped
|
|
300
472
|
|
|
301
473
|
# --- instantiating builders (return an element) ---
|
|
302
|
-
|
|
474
|
+
# Given an Array of attribute hashes, `new`, `build`, `create` and
|
|
475
|
+
# `create!` return an Array of records. No overload says so, for
|
|
476
|
+
# the reason `find` gives: an untyped argument would select it too.
|
|
477
|
+
%a{rigor:v1:effect mutate.self}
|
|
303
478
|
def new: (*untyped) ?{ (Elem) -> void } -> Elem
|
|
304
|
-
%a{
|
|
479
|
+
%a{rigor:v1:effect mutate.self}
|
|
305
480
|
def build: (*untyped) ?{ (Elem) -> void } -> Elem
|
|
306
|
-
%a{rigor:v1:effect io.db.write}
|
|
481
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
307
482
|
def create: (*untyped) ?{ (Elem) -> void } -> Elem
|
|
308
|
-
%a{rigor:v1:effect io.db.write}
|
|
483
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
309
484
|
def create!: (*untyped) ?{ (Elem) -> void } -> Elem
|
|
310
|
-
%a{rigor:v1:effect io.db.write}
|
|
485
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
311
486
|
def find_or_create_by: (untyped) ?{ (Elem) -> void } -> Elem
|
|
312
|
-
%a{rigor:v1:effect io.db.write}
|
|
487
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
313
488
|
def find_or_create_by!: (untyped) ?{ (Elem) -> void } -> Elem
|
|
314
|
-
%a{rigor:v1:effect io.db.read}
|
|
489
|
+
%a{rigor:v1:effect io.db.read, mutate.self}
|
|
315
490
|
def find_or_initialize_by: (untyped) ?{ (Elem) -> void } -> Elem
|
|
316
|
-
%a{rigor:v1:effect io.db.write}
|
|
491
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
317
492
|
def create_or_find_by: (untyped) ?{ (Elem) -> void } -> Elem
|
|
318
|
-
%a{rigor:v1:effect io.db.write}
|
|
493
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
319
494
|
def create_or_find_by!: (untyped) ?{ (Elem) -> void } -> Elem
|
|
320
|
-
%a{rigor:v1:effect io.db.write}
|
|
495
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
321
496
|
def first_or_create: (?untyped) ?{ (Elem) -> void } -> Elem
|
|
322
|
-
%a{rigor:v1:effect io.db.write}
|
|
497
|
+
%a{rigor:v1:effect io.db.read, io.db.write, mutate.self}
|
|
323
498
|
def first_or_create!: (?untyped) ?{ (Elem) -> void } -> Elem
|
|
324
|
-
%a{rigor:v1:effect io.db.read}
|
|
499
|
+
%a{rigor:v1:effect io.db.read, mutate.self}
|
|
325
500
|
def first_or_initialize: (?untyped) ?{ (Elem) -> void } -> Elem
|
|
326
501
|
end
|
|
327
502
|
end
|
|
@@ -37,6 +37,7 @@ module Rigor
|
|
|
37
37
|
class Activestorage < Rigor::Plugin::Base
|
|
38
38
|
manifest(
|
|
39
39
|
id: "activestorage",
|
|
40
|
+
target_gems: ["activestorage"],
|
|
40
41
|
# Bumped 2026-09-02 (#621) — attachment owners are keyed by their de-rooted name and a reopened
|
|
41
42
|
# class's attachments are UNIONed rather than clobbered, so a cached 0.1.0 index can be missing the
|
|
42
43
|
# attachments the merge restores.
|
|
@@ -66,12 +67,15 @@ module Rigor
|
|
|
66
67
|
def init(_services)
|
|
67
68
|
@model_search_paths = Array(config.fetch("model_search_paths")).map(&:to_s)
|
|
68
69
|
@attachment_index = nil
|
|
69
|
-
@load_errors =
|
|
70
|
+
@load_errors = {}
|
|
70
71
|
end
|
|
71
72
|
|
|
72
73
|
def diagnostics_for_file(path:, scope:, root:) # rubocop:disable Lint/UnusedMethodArgument
|
|
73
74
|
index = attachment_index
|
|
74
|
-
|
|
75
|
+
if index.nil?
|
|
76
|
+
disclose_load_errors
|
|
77
|
+
return []
|
|
78
|
+
end
|
|
75
79
|
return [] if index.empty?
|
|
76
80
|
|
|
77
81
|
Analyzer.new(path: path, attachment_index: index).analyze(root).diagnostics
|
|
@@ -125,24 +129,32 @@ module Rigor
|
|
|
125
129
|
# covers model-file additions.
|
|
126
130
|
@attachment_index = cache_for(:attachment_index, params: {}).call
|
|
127
131
|
rescue Plugin::AccessDeniedError => e
|
|
128
|
-
@load_errors
|
|
132
|
+
@load_errors["1-read-refused"] ||= "rigor-activestorage: #{e.message}"
|
|
129
133
|
nil
|
|
130
134
|
rescue StandardError => e
|
|
131
|
-
@load_errors
|
|
135
|
+
@load_errors["2-discovery-failed"] ||=
|
|
136
|
+
"rigor-activestorage: discovery failed: #{e.class}: #{e.message}"
|
|
132
137
|
nil
|
|
133
138
|
end
|
|
134
139
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
# Issue #1056 — "the attachment index did not load" is a fact about the run's INPUTS, not about the
|
|
141
|
+
# file being analysed, so both outcomes are registered rather than returned: see
|
|
142
|
+
# {Plugin::Base#disclose_once} for the channel and the position. Returned from the per-file hook they
|
|
143
|
+
# carried no once-guard at all — the `.uniq` collapsed repeats within one instance's list, but the
|
|
144
|
+
# whole list was re-emitted on every analysed file.
|
|
145
|
+
#
|
|
146
|
+
# The `key`s carry an ordinal prefix because the engine emits a plugin's disclosures in KEY order
|
|
147
|
+
# (#1051), and a refused read must still precede a discovery failure the way `@load_errors` records
|
|
148
|
+
# them — `@load_errors` is now keyed by that same string, which also caps it: `#attachment_index`
|
|
149
|
+
# re-attempts the load per call site, and the old Array appended a fresh interpolated string every
|
|
150
|
+
# time (the unbounded-growth shape #569 measured at 4.2 M retained strings on Redmine). The key, not
|
|
151
|
+
# the message, is the identity: a second refusal naming a different path collapses into the first row
|
|
152
|
+
# rather than adding one — the notice is "the index did not load", said once.
|
|
153
|
+
def disclose_load_errors
|
|
154
|
+
@load_errors.each do |key, message|
|
|
155
|
+
disclose_once(key, message: message, severity: :warning, rule: "load-error")
|
|
145
156
|
end
|
|
157
|
+
nil
|
|
146
158
|
end
|
|
147
159
|
end
|
|
148
160
|
|
data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Rigor
|
|
|
8
8
|
# rigor-activesupport-core-ext's effect contract (ADR-103 WD10; design note § 11.2; issue #387).
|
|
9
9
|
#
|
|
10
10
|
# **Scope note.** This is the *impure* half of ActiveSupport only: the clock, the notification bus and
|
|
11
|
-
# `CurrentAttributes`. The `%a{pure}` sweep over `blank?` / `present?` / `
|
|
11
|
+
# `CurrentAttributes`. The `%a{pure}` sweep over `blank?` / `present?` / `presence` and the rest of
|
|
12
12
|
# the core_ext predicate surface — the single cheapest purity win in a Rails app, per WD10 — is issue
|
|
13
13
|
# #388 and lands in this plugin's shipped RBS, not here (`try` was audited and skipped: it dispatches
|
|
14
14
|
# to whatever method the caller names, so its purity is a fact about the call site, not about `try`).
|
|
@@ -115,11 +115,18 @@ module Rigor
|
|
|
115
115
|
# which is what earns `Date` its row here — the label is a fact about the module, not about the
|
|
116
116
|
# receiver, and the three only ever differed in which spellings the bundle had got round to
|
|
117
117
|
# declaring.
|
|
118
|
+
#
|
|
119
|
+
# `String#in_time_zone` is the exception: it has no instant to convert. It parses through
|
|
120
|
+
# `TimeZone#parse(str, now = now())`, whose default argument reads the clock on every call, or through
|
|
121
|
+
# `to_time` when no zone is set — so it takes `CLOCK`, not `ZONE_READ`.
|
|
118
122
|
def in_time_zone_rows
|
|
119
123
|
[TIME, DATE, DATETIME].map do |receiver|
|
|
120
124
|
row(receiver, :in_time_zone, ZONE_READ,
|
|
121
125
|
why: "the default argument reads `Time.zone` when the caller doesn't name one explicitly")
|
|
122
|
-
end
|
|
126
|
+
end + [
|
|
127
|
+
row("String", :in_time_zone, CLOCK,
|
|
128
|
+
why: "parses in `Time.zone` (the default argument) and fills the parts from the zone's `now`")
|
|
129
|
+
]
|
|
123
130
|
end
|
|
124
131
|
|
|
125
132
|
def current_rows
|
|
@@ -42,9 +42,13 @@ module Rigor
|
|
|
42
42
|
class ActivesupportCoreExt < Rigor::Plugin::Base
|
|
43
43
|
manifest(
|
|
44
44
|
id: "activesupport-core-ext",
|
|
45
|
+
target_gems: ["activesupport"],
|
|
46
|
+
# Bumped 2026-09-10 (#534 item 7) — `ActiveSupport::Concern` is declared, so `extend
|
|
47
|
+
# ActiveSupport::Concern` resolves instead of reading as an unresolved constant.
|
|
48
|
+
#
|
|
45
49
|
# Bumped 2026-09-02 (#632) — `ActiveSupport::Duration`'s reader surface (`ago`/`to_i`/`iso8601`/…)
|
|
46
50
|
# is now declared, open_receivers-protected; see the class comment above.
|
|
47
|
-
version: "0.
|
|
51
|
+
version: "0.5.0",
|
|
48
52
|
description: "RBS bundle for the most-frequently-flagged ActiveSupport core_ext extensions, " \
|
|
49
53
|
"plus the `ActiveSupport::Duration` type of the numeric time multipliers and its " \
|
|
50
54
|
"reader surface.",
|
|
@@ -55,7 +59,10 @@ module Rigor
|
|
|
55
59
|
# `call.undefined-method` fire against it. Distinct from the RECEIVER-side FP the multiplier
|
|
56
60
|
# `dynamic_return` gate guards (`Time#day` vs `Duration#day`, in the class comment above) — this is
|
|
57
61
|
# the class's OWN unenumerable member set.
|
|
58
|
-
|
|
62
|
+
# `ActiveSupport::Concern` (#534 item 7) is here for the same reason at a different scale: the
|
|
63
|
+
# declaration names `included` / `prepended` / `class_methods` so `extend ActiveSupport::Concern`
|
|
64
|
+
# resolves, and everything else the module really responds to must stay lenient.
|
|
65
|
+
open_receivers: ["ActiveSupport::Duration", "ActiveSupport::Concern"],
|
|
59
66
|
# ADR-103 WD10 (#387) — the IMPURE half of ActiveSupport: the clock, the notification bus and
|
|
60
67
|
# `CurrentAttributes`. The `%a{pure}` sweep over the predicate surface is issue #388 and lands in
|
|
61
68
|
# `sig/`, not here. See {Effects}.
|