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
|
@@ -163,6 +163,95 @@ class Object
|
|
|
163
163
|
# exception to the try-shaped-dispatch rule above (design note § 11.2).
|
|
164
164
|
%a{pure}
|
|
165
165
|
def in?: (untyped) -> bool
|
|
166
|
+
# `in?(another_object) ? self : nil` — `params[:kind].presence_in(%w[a b])`.
|
|
167
|
+
# The same `#include?` dispatch as `in?`, and the same exception.
|
|
168
|
+
%a{pure}
|
|
169
|
+
def presence_in: (untyped) -> self?
|
|
170
|
+
|
|
171
|
+
# Issue #673 — `core_ext/object/to_query`, `core_ext/object/duplicable` and
|
|
172
|
+
# `core_ext/object/instance_variables` all hang off `Object`, so every
|
|
173
|
+
# RBS-known receiver reaches them; declaring them only on `Hash` (as
|
|
174
|
+
# `to_param` / `to_query` were) or only on `NilClass` (as `duplicable?` /
|
|
175
|
+
# `instance_values` were) left `"x".to_param`, `1.duplicable?` and friends a
|
|
176
|
+
# `call.undefined-method` on ordinary Rails code.
|
|
177
|
+
#
|
|
178
|
+
# `to_param` is `to_s`; `to_query(key)` interpolates two `CGI.escape` results.
|
|
179
|
+
# `key` is `untyped` because the body only calls `to_param` on it, and both
|
|
180
|
+
# `:name` and `"user[name]"` are ordinary call sites. Neither is `%a{pure}`:
|
|
181
|
+
# both dispatch `to_param` on a value whose own override is invisible here,
|
|
182
|
+
# the same reason `Hash#to_query` below carries no envelope.
|
|
183
|
+
def to_param: () -> String
|
|
184
|
+
def to_query: (untyped key) -> String
|
|
185
|
+
|
|
186
|
+
# `bool` and not `true`: `Object#duplicable?` answers true, but the
|
|
187
|
+
# `Singleton` (and, on a Ruby where methods are not duplicable, `Method` /
|
|
188
|
+
# `UnboundMethod`) overrides answer false. `-> true` on the universal
|
|
189
|
+
# receiver would make every `if x.duplicable?` an always-truthy branch —
|
|
190
|
+
# a false positive on the only shape anybody writes.
|
|
191
|
+
%a{pure}
|
|
192
|
+
def duplicable?: () -> bool
|
|
193
|
+
|
|
194
|
+
# Keys without the leading `@` for `instance_values`, with it for
|
|
195
|
+
# `instance_variable_names`.
|
|
196
|
+
def instance_values: () -> Hash[String, untyped]
|
|
197
|
+
def instance_variable_names: () -> Array[String]
|
|
198
|
+
|
|
199
|
+
# `core_ext/object/deep_dup` — `duplicable? ? dup : self`, plus `Array`
|
|
200
|
+
# (`map(&:deep_dup)`), `Hash` and `Module` overrides. `self` over-claims on
|
|
201
|
+
# an `Array` subclass, whose override answers a plain `Array`. Declared on
|
|
202
|
+
# `Object` and not only on `Hash`, where it sat alone: `[[1], [2]].deep_dup`
|
|
203
|
+
# is the common shape.
|
|
204
|
+
#
|
|
205
|
+
# NOT `%a{pure}`: on `Object` the `dup` runs the receiver class's own
|
|
206
|
+
# `initialize_copy`, an unknown-at-this-declaration dispatch like the one
|
|
207
|
+
# that keeps `as_json` bare. `Hash#deep_dup` below reaches the same `dup`
|
|
208
|
+
# through `value.deep_dup` on every value and is bare for the same reason.
|
|
209
|
+
def deep_dup: () -> self
|
|
210
|
+
|
|
211
|
+
# `core_ext/object/with` (ActiveSupport 7.1+) — sets each keyword through
|
|
212
|
+
# its public writer, yields `self`, and restores the old values in an
|
|
213
|
+
# `ensure`; the answer is the block's. There is no blockless form: `yield` without a block raises.
|
|
214
|
+
# ActiveSupport `undef_method`s it on `NilClass`, `TrueClass`, `FalseClass`,
|
|
215
|
+
# `Integer`, `Float` and `Symbol`, which RBS cannot express, so `1.with(a: 1)`
|
|
216
|
+
# resolves here where Ruby raises — a missed error, not a false one.
|
|
217
|
+
# `Data#with` (core) is a subclass override and keeps its own `-> self`.
|
|
218
|
+
#
|
|
219
|
+
# NOT `%a{pure}`: it writes the receiver's attributes through `public_send`.
|
|
220
|
+
def with: [T] (**untyped attributes) { (self) -> T } -> T
|
|
221
|
+
|
|
222
|
+
# `core_ext/object/with_options` — without a block, the
|
|
223
|
+
# `ActiveSupport::OptionMerger` proxy (not declared here); with one, the
|
|
224
|
+
# block's value. A zero-arity block is `instance_eval`ed on the proxy, the
|
|
225
|
+
# `with_options dependent: :destroy do has_many … end` model-body shape.
|
|
226
|
+
#
|
|
227
|
+
# NOT `%a{pure}`: the proxy forwards every call to the receiver through
|
|
228
|
+
# `method_missing`, a dispatch this audit cannot see.
|
|
229
|
+
def with_options: (untyped options) -> untyped
|
|
230
|
+
| [T] (untyped options) { (?) -> T } -> T
|
|
231
|
+
|
|
232
|
+
# `core_ext/string/output_safety` — `false` on `Object`, `true` on
|
|
233
|
+
# `Numeric`, the buffer's own state on `ActiveSupport::SafeBuffer`. `bool`
|
|
234
|
+
# for the reason `duplicable?` is: `-> false` on the universal receiver makes
|
|
235
|
+
# every `if x.html_safe?` an always-falsy branch on the subclasses that answer
|
|
236
|
+
# true. All three bodies are a constant or an ivar read.
|
|
237
|
+
%a{pure}
|
|
238
|
+
def html_safe?: () -> bool
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# ---------------------------------------------------------------
|
|
242
|
+
# Kernel — `core_ext/kernel/singleton_class`
|
|
243
|
+
# ---------------------------------------------------------------
|
|
244
|
+
|
|
245
|
+
# `singleton_class.class_eval(*args, &block)` on any object. Declared on
|
|
246
|
+
# `Kernel`, where ActiveSupport defines it; a `Module` receiver still answers
|
|
247
|
+
# core `Module#class_eval`, which is its own alias of `module_eval`. The two
|
|
248
|
+
# overloads mirror that `module_eval`: a string, or a block given the
|
|
249
|
+
# singleton class.
|
|
250
|
+
module Kernel
|
|
251
|
+
# NOT `%a{pure}`: it evaluates a string or a block in the singleton class,
|
|
252
|
+
# and a block that defines methods is the point.
|
|
253
|
+
def class_eval: (string code, ?string? filename, ?int lineno) -> untyped
|
|
254
|
+
| [U] () { (untyped singleton_class) -> U } -> U
|
|
166
255
|
end
|
|
167
256
|
|
|
168
257
|
# `nil.blank?` / `nil.present?` / `nil.try` are the most frequent
|
|
@@ -185,6 +274,13 @@ class NilClass
|
|
|
185
274
|
%a{pure}
|
|
186
275
|
def duplicable?: () -> true
|
|
187
276
|
def instance_values: () -> Hash[String, untyped]
|
|
277
|
+
# `core_ext/object/to_query` overrides `to_param` on the three singleton
|
|
278
|
+
# values to return `self` rather than `Object#to_param`'s `to_s`, so the
|
|
279
|
+
# `Object` row above would carry a wrong return here. `NilClass#to_query`
|
|
280
|
+
# is its own method (`CGI.escape(key.to_param)`), still a String.
|
|
281
|
+
%a{pure}
|
|
282
|
+
def to_param: () -> nil
|
|
283
|
+
def to_query: (untyped key) -> String
|
|
188
284
|
end
|
|
189
285
|
|
|
190
286
|
class TrueClass
|
|
@@ -192,6 +288,8 @@ class TrueClass
|
|
|
192
288
|
def blank?: () -> false
|
|
193
289
|
%a{pure}
|
|
194
290
|
def present?: () -> true
|
|
291
|
+
%a{pure}
|
|
292
|
+
def to_param: () -> true
|
|
195
293
|
end
|
|
196
294
|
|
|
197
295
|
class FalseClass
|
|
@@ -199,6 +297,8 @@ class FalseClass
|
|
|
199
297
|
def blank?: () -> true
|
|
200
298
|
%a{pure}
|
|
201
299
|
def present?: () -> false
|
|
300
|
+
%a{pure}
|
|
301
|
+
def to_param: () -> false
|
|
202
302
|
end
|
|
203
303
|
|
|
204
304
|
# ---------------------------------------------------------------
|
|
@@ -230,6 +330,8 @@ class String
|
|
|
230
330
|
def dasherize: () -> String
|
|
231
331
|
%a{pure}
|
|
232
332
|
def upcase_first: () -> String
|
|
333
|
+
%a{pure}
|
|
334
|
+
def downcase_first: () -> String # ActiveSupport 7.1+
|
|
233
335
|
# NOT %a{pure}: transliterates through `I18n.transliterate`, which reads
|
|
234
336
|
# `I18n.locale` when `locale:` is left at its `nil` default — a request-
|
|
235
337
|
# scoped global read the inflection-table assumption does not cover.
|
|
@@ -245,6 +347,11 @@ class String
|
|
|
245
347
|
%a{pure}
|
|
246
348
|
def humanize: (?capitalize: bool, ?keep_id_suffix: bool) -> String
|
|
247
349
|
|
|
350
|
+
# `core_ext/string/behavior` — the `acts_like?(:string)` duck-type hook, a
|
|
351
|
+
# hardcoded `true`.
|
|
352
|
+
%a{pure}
|
|
353
|
+
def acts_like_string?: () -> true
|
|
354
|
+
|
|
248
355
|
# `core_ext/string/filters`
|
|
249
356
|
%a{pure}
|
|
250
357
|
def squish: () -> String
|
|
@@ -297,6 +404,15 @@ class String
|
|
|
297
404
|
# follow-up to confirm and either implement or remove the declaration.
|
|
298
405
|
def to_hours: () -> Float
|
|
299
406
|
|
|
407
|
+
# `core_ext/string/zones` — `Time.find_zone!(zone).parse(self)`, or
|
|
408
|
+
# `to_time` when no zone is set. `untyped` like the `Time` / `Date` rows:
|
|
409
|
+
# the parse answers an `ActiveSupport::TimeWithZone`, or `nil` on a string
|
|
410
|
+
# with no date parts. NOT `%a{pure}`: the default argument reads
|
|
411
|
+
# `Time.zone`, and `TimeZone#parse(str, now = now())` reads the clock on
|
|
412
|
+
# every call, whether or not the string names every part. The plugin's
|
|
413
|
+
# `effect_attributions:` carry both labels.
|
|
414
|
+
def in_time_zone: (?untyped zone) -> untyped
|
|
415
|
+
|
|
300
416
|
# `core_ext/string/access`
|
|
301
417
|
%a{pure}
|
|
302
418
|
def at: (Integer | Range[Integer] | Regexp position) -> String?
|
|
@@ -316,12 +432,29 @@ class String
|
|
|
316
432
|
# `core_ext/string/multibyte`
|
|
317
433
|
%a{pure}
|
|
318
434
|
def mb_chars: () -> untyped
|
|
435
|
+
# Reads `encoding` / `valid_encoding?`; the `ASCII-8BIT` branch
|
|
436
|
+
# `force_encoding`s a `dup`, never the receiver.
|
|
437
|
+
%a{pure}
|
|
438
|
+
def is_utf8?: () -> bool
|
|
319
439
|
|
|
320
440
|
# `core_ext/string/inquiry`
|
|
321
441
|
%a{pure}
|
|
322
442
|
def inquiry: () -> untyped # ActiveSupport::StringInquirer
|
|
323
443
|
end
|
|
324
444
|
|
|
445
|
+
# ---------------------------------------------------------------
|
|
446
|
+
# Symbol — `core_ext/symbol/starts_ends_with`
|
|
447
|
+
# ---------------------------------------------------------------
|
|
448
|
+
|
|
449
|
+
# `alias_method`s of core `start_with?` / `end_with?`, declared with the core
|
|
450
|
+
# parameter lists.
|
|
451
|
+
class Symbol
|
|
452
|
+
%a{pure}
|
|
453
|
+
def starts_with?: (*Regexp | string prefixes) -> bool
|
|
454
|
+
%a{pure}
|
|
455
|
+
def ends_with?: (*string suffixes) -> bool
|
|
456
|
+
end
|
|
457
|
+
|
|
325
458
|
# ---------------------------------------------------------------
|
|
326
459
|
# Integer — `core_ext/integer/*`
|
|
327
460
|
# ---------------------------------------------------------------
|
|
@@ -486,6 +619,22 @@ end
|
|
|
486
619
|
# purpose — some are already covered by the separate `dynamic_return` rule for `+`/`-`/`*` below, the rest
|
|
487
620
|
# are simply outside this issue's scope and remain silently `Dynamic` rather than a guess.
|
|
488
621
|
module ActiveSupport
|
|
622
|
+
# Issue #534 item 7 — `ActiveSupport::Concern` was 87 unresolved constant sites on mastodon, essentially
|
|
623
|
+
# all of them the `extend ActiveSupport::Concern` line at the top of a concern module. Naming it is a
|
|
624
|
+
# constant-resolution fix and nothing more: the three members are declared because `extend`ing a module
|
|
625
|
+
# puts them on the extender's singleton, and leaving them out of a now-RBS-known module is what would
|
|
626
|
+
# turn `included do … end` into a false `call.undefined-method` in every concern in the project. The
|
|
627
|
+
# blocks are `(?) -> untyped` because their body is evaluated against the INCLUDING class, which this
|
|
628
|
+
# signature has no way to name.
|
|
629
|
+
#
|
|
630
|
+
# `Concern` is listed in the manifest's `open_receivers:` for the rest of its surface (`append_features`,
|
|
631
|
+
# `class_methods`' generated `ClassMethods` constant, …).
|
|
632
|
+
module Concern
|
|
633
|
+
def included: (?untyped base) ?{ (?) -> untyped } -> untyped
|
|
634
|
+
def prepended: (?untyped base) ?{ (?) -> untyped } -> untyped
|
|
635
|
+
def class_methods: () { (?) -> untyped } -> untyped
|
|
636
|
+
end
|
|
637
|
+
|
|
489
638
|
class Duration
|
|
490
639
|
# The `ago` family (issue #659). `since(time = ::Time.current)` and `ago(time = ::Time.current)` are
|
|
491
640
|
# the only two real methods; `from_now` / `after` are `alias`es of the first and `until` / `before`
|
|
@@ -501,13 +650,17 @@ module ActiveSupport
|
|
|
501
650
|
# help there: it protects a Duration receiver, and the diagnostic lands on the `Time` the call
|
|
502
651
|
# RETURNS. #658 declared that surface and #670 the `Date` / `DateTime` twins, so the chains resolve.
|
|
503
652
|
#
|
|
504
|
-
# `() ->
|
|
505
|
-
#
|
|
506
|
-
#
|
|
507
|
-
#
|
|
508
|
-
#
|
|
509
|
-
#
|
|
510
|
-
#
|
|
653
|
+
# `() -> TimeWithZone` since #673, where the class these actually build under a zone (verified by
|
|
654
|
+
# calling them) was finally declared — as a `::Time` SUBCLASS, so nothing a `Time` return bought is
|
|
655
|
+
# given up: every `Time` instance method still resolves on the result, every `Time`-typed parameter
|
|
656
|
+
# still accepts it, and the four TWZ-only readers (`time_zone`, `time`, `period`, `comparable_time`)
|
|
657
|
+
# stop being a false `call.undefined-method` on `1.hour.ago`. It was `() -> Time` before that, on the
|
|
658
|
+
# ground that Rails overrides `TimeWithZone#is_a?` to answer true for `::Time` — true, and the
|
|
659
|
+
# subclass is the same claim made where the analyser can also see the extra readers. A
|
|
660
|
+
# `Time | TimeWithZone` UNION was measured and rejected: it draws no `undefined-method`, but types
|
|
661
|
+
# every downstream call `Dynamic[top]` (`iso8601`, `beginning_of_day`, `to_date`, `- 1.day`), which is
|
|
662
|
+
# worth no more than leaving them undeclared while still firing a parameter mismatch on the
|
|
663
|
+
# TimeWithZone arm.
|
|
511
664
|
#
|
|
512
665
|
# The with-an-argument form stays `(untyped) -> untyped` on purpose, and this is not caution: the
|
|
513
666
|
# runtime return depends on the argument's class AND on whether the duration carries a date-scale
|
|
@@ -520,17 +673,17 @@ module ActiveSupport
|
|
|
520
673
|
# what stops `created_at > 7.days.ago` folding to a constant. They are already attributed `nondet.time`
|
|
521
674
|
# in `lib/rigor/plugin/activesupport_core_ext/effects.rb` — annotating them here would duplicate an
|
|
522
675
|
# envelope the manifest already owns, and risk the two disagreeing.
|
|
523
|
-
def ago: () ->
|
|
676
|
+
def ago: () -> TimeWithZone
|
|
524
677
|
| (untyped time) -> untyped
|
|
525
|
-
def until: () ->
|
|
678
|
+
def until: () -> TimeWithZone
|
|
526
679
|
| (untyped time) -> untyped
|
|
527
|
-
def before: () ->
|
|
680
|
+
def before: () -> TimeWithZone
|
|
528
681
|
| (untyped time) -> untyped
|
|
529
|
-
def since: () ->
|
|
682
|
+
def since: () -> TimeWithZone
|
|
530
683
|
| (untyped time) -> untyped
|
|
531
|
-
def from_now: () ->
|
|
684
|
+
def from_now: () -> TimeWithZone
|
|
532
685
|
| (untyped time) -> untyped
|
|
533
|
-
def after: () ->
|
|
686
|
+
def after: () -> TimeWithZone
|
|
534
687
|
| (untyped time) -> untyped
|
|
535
688
|
|
|
536
689
|
# `to_i` returns `@value.to_i` — always Integer, whether `@value` itself is Integer (`1.day`) or Float
|
|
@@ -574,6 +727,48 @@ module ActiveSupport
|
|
|
574
727
|
%a{pure}
|
|
575
728
|
def parts: () -> Hash[Symbol, Integer | Float]
|
|
576
729
|
end
|
|
730
|
+
|
|
731
|
+
# ---------------------------------------------------------------
|
|
732
|
+
# ActiveSupport::TimeWithZone — issue #673
|
|
733
|
+
# ---------------------------------------------------------------
|
|
734
|
+
#
|
|
735
|
+
# `Time.current` and the `Duration#ago` family above really answer a `TimeWithZone` under a zone, and
|
|
736
|
+
# this class was not modelled at all, so the four readers a TWZ has and a `Time` does not —
|
|
737
|
+
# `time_zone`, `time`, `period`, `comparable_time` — were a false `call.undefined-method` on every
|
|
738
|
+
# `Time.current` receiver. Declaring them on `Time` instead would have been wrong: a plain `Time`
|
|
739
|
+
# genuinely lacks all four, and the diagnostic would stop firing where it is correct.
|
|
740
|
+
#
|
|
741
|
+
# `< ::Time` rather than a `Time | TimeWithZone` union at the producers. The union was measured during
|
|
742
|
+
# #632 and rejected — it types every downstream call `Dynamic[top]`. Inheritance is both cheaper and
|
|
743
|
+
# more honest: Rails overrides `TimeWithZone#is_a?` to answer true for `::Time`, so `Time` is the class
|
|
744
|
+
# Rails itself tells callers a TWZ is, and TWZ's `method_missing` forwards every name it does not
|
|
745
|
+
# define to the wrapped `::Time`, which is exactly what inheriting `Time`'s surface models. A TWZ
|
|
746
|
+
# therefore satisfies every `Time`-typed parameter, and chains keep resolving instead of collapsing.
|
|
747
|
+
#
|
|
748
|
+
# The cost, taken deliberately: `Time.current` answers a plain `Time` when `Time.zone` is nil, so
|
|
749
|
+
# `Time.current.time_zone` in a zone-less activesupport-only project is a real `NoMethodError` this
|
|
750
|
+
# now types. Rails sets `config.time_zone` ("UTC") by default, so the shape is rare, and the false
|
|
751
|
+
# positive it replaces fired on correct Rails code.
|
|
752
|
+
class TimeWithZone < ::Time
|
|
753
|
+
# `Time`'s own `initialize` takes the `(year, month, …)` parts; inheriting it would make
|
|
754
|
+
# `TimeWithZone.new(utc, zone)` — how Rails constructs one — a `call.argument-type-mismatch`.
|
|
755
|
+
# `untyped` because the zone and period carriers (`ActiveSupport::TimeZone`,
|
|
756
|
+
# `TZInfo::TimezonePeriod`) are not declared anywhere in this bundle.
|
|
757
|
+
def initialize: (untyped utc_time, untyped time_zone, ?untyped local_time, ?untyped period) -> void
|
|
758
|
+
|
|
759
|
+
# The `attr_reader`; an `ActiveSupport::TimeZone`, undeclared here.
|
|
760
|
+
%a{pure}
|
|
761
|
+
def time_zone: () -> untyped
|
|
762
|
+
|
|
763
|
+
# The wall-clock `::Time` in the zone. `utc` / `getutc` / `getgm` / `gmtime` are `Time`'s own names
|
|
764
|
+
# and stay inherited; `comparable_time` is the alias of `utc` that `Time` does not carry. Neither is
|
|
765
|
+
# `%a{pure}`: both memoise into an ivar on first call.
|
|
766
|
+
def time: () -> ::Time
|
|
767
|
+
def comparable_time: () -> ::Time
|
|
768
|
+
|
|
769
|
+
# A `TZInfo::TimezonePeriod`, undeclared here. Memoised like `time`, so not `%a{pure}`.
|
|
770
|
+
def period: () -> untyped
|
|
771
|
+
end
|
|
577
772
|
end
|
|
578
773
|
|
|
579
774
|
# ---------------------------------------------------------------
|
|
@@ -584,7 +779,11 @@ class Time
|
|
|
584
779
|
# NOT %a{pure}: already attributed nondet.time/global.read/global.write
|
|
585
780
|
# by `lib/rigor/plugin/activesupport_core_ext/effects.rb` (issue #387).
|
|
586
781
|
# Duplicating an RBS envelope here risks the two disagreeing.
|
|
587
|
-
|
|
782
|
+
#
|
|
783
|
+
# `Time.zone ? Time.zone.now : Time.now` — an `ActiveSupport::TimeWithZone` under a zone, which since
|
|
784
|
+
# #673 is declared as a `::Time` subclass so the four TWZ-only readers resolve without the rest of the
|
|
785
|
+
# chain losing its `Time` typing. See that class's own note for the zone-less cost.
|
|
786
|
+
def self.current: () -> ActiveSupport::TimeWithZone
|
|
588
787
|
def self.zone: () -> untyped # ActiveSupport::TimeZone | nil
|
|
589
788
|
def self.zone=: (String | Symbol | untyped) -> untyped
|
|
590
789
|
|
|
@@ -1264,6 +1463,10 @@ class Array[unchecked out Elem]
|
|
|
1264
1463
|
def fifth: () -> Elem?
|
|
1265
1464
|
%a{pure}
|
|
1266
1465
|
def forty_two: () -> Elem?
|
|
1466
|
+
%a{pure}
|
|
1467
|
+
def second_to_last: () -> Elem?
|
|
1468
|
+
%a{pure}
|
|
1469
|
+
def third_to_last: () -> Elem?
|
|
1267
1470
|
|
|
1268
1471
|
# `core_ext/array/grouping`
|
|
1269
1472
|
%a{pure}
|
|
@@ -1295,6 +1498,9 @@ class Array[unchecked out Elem]
|
|
|
1295
1498
|
# `core_ext/array/extract`
|
|
1296
1499
|
def extract!: () { (Elem) -> bool } -> Array[Elem] # NOT %a{pure}: bang, mutates in place.
|
|
1297
1500
|
|
|
1501
|
+
# `core_ext/array/extract_options`
|
|
1502
|
+
def extract_options!: () -> Hash[untyped, untyped] # NOT %a{pure}: pops the trailing options Hash.
|
|
1503
|
+
|
|
1298
1504
|
# `core_ext/object/blank` / `core_ext/enumerable` — both
|
|
1299
1505
|
# ActiveSupport additions, shipped on Array specifically.
|
|
1300
1506
|
%a{pure}
|
|
@@ -1339,6 +1545,15 @@ module Enumerable[unchecked out Elem]
|
|
|
1339
1545
|
def sole: () -> Elem
|
|
1340
1546
|
%a{pure}
|
|
1341
1547
|
def compact_blank: () -> Array[Elem]
|
|
1548
|
+
%a{pure}
|
|
1549
|
+
def many?: () -> bool
|
|
1550
|
+
| () { (Elem) -> boolish } -> bool
|
|
1551
|
+
# `key` and `series` are untyped on purpose: the default `filter: true`
|
|
1552
|
+
# path is `group_by(&key).values_at(*series)`, so a Proc key or a Set /
|
|
1553
|
+
# Range series is correct Rails code. `filter:` is ActiveSupport 8.x;
|
|
1554
|
+
# passing it on 7.x raises, which this unversioned row does not catch.
|
|
1555
|
+
%a{pure}
|
|
1556
|
+
def in_order_of: (untyped key, untyped series, ?filter: boolish) -> Array[Elem]
|
|
1342
1557
|
end
|
|
1343
1558
|
|
|
1344
1559
|
# ---------------------------------------------------------------
|
|
@@ -1369,10 +1584,17 @@ class Hash[unchecked out K, unchecked out V]
|
|
|
1369
1584
|
%a{pure}
|
|
1370
1585
|
def deep_transform_values: () { (V) -> untyped } -> Hash[K, untyped]
|
|
1371
1586
|
def deep_transform_values!: () { (V) -> untyped } -> self
|
|
1587
|
+
# `alias_method`s of `symbolize_keys` / `symbolize_keys!`.
|
|
1588
|
+
%a{pure}
|
|
1589
|
+
def to_options: () -> Hash[Symbol, V]
|
|
1590
|
+
def to_options!: () -> self
|
|
1372
1591
|
|
|
1373
1592
|
# `core_ext/hash/deep_dup` — allocates a deep copy, never touches the
|
|
1374
|
-
# receiver.
|
|
1375
|
-
|
|
1593
|
+
# receiver. NOT `%a{pure}`: it calls `deep_dup` on every value, and on
|
|
1594
|
+
# every key that is not a `String` or `Symbol` — an ELEMENT of unknown class
|
|
1595
|
+
# whose `dup` runs that class's own `initialize_copy`. That is the dispatch
|
|
1596
|
+
# the purity rule at the top of this file excludes, and the reason
|
|
1597
|
+
# `Object#deep_dup` above is bare.
|
|
1376
1598
|
def deep_dup: () -> Hash[K, V]
|
|
1377
1599
|
|
|
1378
1600
|
# `core_ext/hash/deep_merge` — the block receives `(key, this_val,
|
|
@@ -1383,6 +1605,10 @@ class Hash[unchecked out K, unchecked out V]
|
|
|
1383
1605
|
| (Hash[K, V]) { (K, V, V) -> V } -> Hash[K, V]
|
|
1384
1606
|
def deep_merge!: (Hash[K, V]) -> self
|
|
1385
1607
|
| (Hash[K, V]) { (K, V, V) -> V } -> self
|
|
1608
|
+
# `other.is_a?(Hash)` — the hook `ActiveSupport::DeepMergeable` asks before
|
|
1609
|
+
# recursing into a value. `:nodoc:`, but public.
|
|
1610
|
+
%a{pure}
|
|
1611
|
+
def deep_merge?: (untyped other) -> bool
|
|
1386
1612
|
|
|
1387
1613
|
# `core_ext/hash/except` — `Hash#except` is in core RBS as of
|
|
1388
1614
|
# Ruby 3.0+; `except!` is ActiveSupport-only. ActiveSupport
|
|
@@ -1407,6 +1633,9 @@ class Hash[unchecked out K, unchecked out V]
|
|
|
1407
1633
|
# `%a{pure}` explicitly.
|
|
1408
1634
|
%a{pure}
|
|
1409
1635
|
def with_indifferent_access: () -> untyped
|
|
1636
|
+
# An `alias` of `with_indifferent_access`.
|
|
1637
|
+
%a{pure}
|
|
1638
|
+
def nested_under_indifferent_access: () -> untyped
|
|
1410
1639
|
|
|
1411
1640
|
# `core_ext/hash/conversions`
|
|
1412
1641
|
def self.from_xml: (String, ?Symbol disallowed_types) -> Hash[String, untyped]
|
|
@@ -1417,15 +1646,57 @@ class Hash[unchecked out K, unchecked out V]
|
|
|
1417
1646
|
def compact_blank: () -> Hash[K, V]
|
|
1418
1647
|
def compact_blank!: () -> self # NOT %a{pure}: bang (`delete_if`), mutates in place.
|
|
1419
1648
|
|
|
1420
|
-
# `core_ext/
|
|
1649
|
+
# `core_ext/array/extract_options`
|
|
1650
|
+
%a{pure}
|
|
1651
|
+
def extractable_options?: () -> bool
|
|
1652
|
+
|
|
1653
|
+
# `core_ext/hash/reverse_merge` — `other_hash.merge(self)`, so the result
|
|
1654
|
+
# carries the argument's keys and values as well as the receiver's, the
|
|
1655
|
+
# same shape as core `Hash#merge`. `-> Hash[K, V]` typed
|
|
1656
|
+
# `opts.reverse_merge(size: 25, velocity: 10)` as `Hash[:size, 1]`.
|
|
1421
1657
|
%a{pure}
|
|
1422
|
-
def reverse_merge: (Hash[
|
|
1658
|
+
def reverse_merge: [A, B] (Hash[A, B] other_hash) -> Hash[A | K, B | V]
|
|
1423
1659
|
def reverse_merge!: (Hash[K, V]) -> self # NOT %a{pure}: bang (`replace`), mutates in place.
|
|
1660
|
+
# `alias_method`s: `with_defaults` of `reverse_merge`, `with_defaults!`
|
|
1661
|
+
# and `reverse_update` of `reverse_merge!`.
|
|
1662
|
+
%a{pure}
|
|
1663
|
+
def with_defaults: [A, B] (Hash[A, B] other_hash) -> Hash[A | K, B | V]
|
|
1664
|
+
def with_defaults!: (Hash[K, V]) -> self # NOT %a{pure}: bang (`replace`), mutates in place.
|
|
1665
|
+
def reverse_update: (Hash[K, V]) -> self # NOT %a{pure}: `reverse_merge!` under another name.
|
|
1424
1666
|
|
|
1425
1667
|
# `core_ext/hash/slice` — `Hash#except` is in core RBS (Ruby 3.0+);
|
|
1426
1668
|
# `Hash#slice` is in core RBS (Ruby 2.5+); the bang variants are
|
|
1427
|
-
# ActiveSupport-only.
|
|
1669
|
+
# ActiveSupport-only. `extract!` deletes the named keys and answers them
|
|
1670
|
+
# as a new hash; a key the receiver lacks is skipped, not `nil`-filled.
|
|
1428
1671
|
def slice!: (*K) -> Hash[K, V] # NOT %a{pure}: bang (`replace`), mutates in place.
|
|
1672
|
+
def extract!: (*K) -> Hash[K, V] # NOT %a{pure}: bang, mutates via `delete`.
|
|
1673
|
+
end
|
|
1674
|
+
|
|
1675
|
+
# ---------------------------------------------------------------
|
|
1676
|
+
# Range — `core_ext/range/*`
|
|
1677
|
+
# ---------------------------------------------------------------
|
|
1678
|
+
|
|
1679
|
+
# `[out E]` matches core `range.rbs`. A reopening whose parameters differ in
|
|
1680
|
+
# count or variance (`class Range`, `class Range[E]`) raises
|
|
1681
|
+
# `RBS::GenericParameterMismatchError` and collapses `Range`.
|
|
1682
|
+
class Range[out E]
|
|
1683
|
+
# `core_ext/range/overlap` — an `alias` of `overlap?`, which rbs declares
|
|
1684
|
+
# since Ruby 3.3 (ActiveSupport defines the method itself only on an older
|
|
1685
|
+
# Ruby). `overlap?` is therefore NOT redeclared here: a second declaration
|
|
1686
|
+
# is a `DuplicatedMethodDefinitionError` that collapses the whole class.
|
|
1687
|
+
%a{pure}
|
|
1688
|
+
def overlaps?: (Range[untyped]) -> bool
|
|
1689
|
+
|
|
1690
|
+
# `core_ext/range/conversions` — `ActiveSupport::RangeWithFormat`, prepended
|
|
1691
|
+
# onto `Range`. An unknown format falls back to `to_s`; `:db` answers `nil`
|
|
1692
|
+
# for a beginless-and-endless range, which the declared `String` does not
|
|
1693
|
+
# model — `(nil..nil).to_fs(:db)` is not a shape correct code writes.
|
|
1694
|
+
#
|
|
1695
|
+
# NOT `%a{pure}`, for the `Array#to_fs` reasons: `RANGE_FORMATS` is a
|
|
1696
|
+
# mutable constant an initializer extends, and `:db` calls `to_fs(:db)` on
|
|
1697
|
+
# both endpoints.
|
|
1698
|
+
def to_fs: (?Symbol format) -> String
|
|
1699
|
+
def to_formatted_s: (?Symbol format) -> String
|
|
1429
1700
|
end
|
|
1430
1701
|
|
|
1431
1702
|
# ---------------------------------------------------------------
|
|
@@ -30,6 +30,7 @@ module Rigor
|
|
|
30
30
|
source_path: __FILE__,
|
|
31
31
|
source_line: __LINE__
|
|
32
32
|
)
|
|
33
|
+
Ractor.make_shareable(RESULT_DEFINITION)
|
|
33
34
|
|
|
34
35
|
MAYBE_DEFINITION = Inference::HktRegistry.definition_with_body_tree(
|
|
35
36
|
uri: :"dry_monads::maybe",
|
|
@@ -38,12 +39,14 @@ module Rigor
|
|
|
38
39
|
source_path: __FILE__,
|
|
39
40
|
source_line: __LINE__
|
|
40
41
|
)
|
|
42
|
+
Ractor.make_shareable(MAYBE_DEFINITION)
|
|
41
43
|
|
|
42
44
|
CONSTRUCTOR_METHODS = %i[Success Failure Some None].freeze
|
|
43
45
|
UNWRAP_METHODS = %i[value! failure value_or].freeze
|
|
44
46
|
|
|
45
47
|
manifest(
|
|
46
48
|
id: "dry-monads",
|
|
49
|
+
target_gems: ["dry-monads"],
|
|
47
50
|
version: "0.1.0",
|
|
48
51
|
description: "Lightweight HKT support for dry-monads Result and Maybe carriers",
|
|
49
52
|
hkt_registrations: [RESULT_REGISTRATION, MAYBE_REGISTRATION],
|
|
@@ -40,24 +40,26 @@ module Rigor
|
|
|
40
40
|
|
|
41
41
|
module_function
|
|
42
42
|
|
|
43
|
-
# @param paths
|
|
44
|
-
# @param
|
|
43
|
+
# @param paths — absolute paths to `.rb` files the project's `paths:` resolves to.
|
|
44
|
+
# @param io_boundary — the plugin's {Rigor::Plugin::IoBoundary}; every source read goes
|
|
45
|
+
# through it (#630) so each scanned file is a recorded cache dependency.
|
|
46
|
+
# @param type_aliases — the ADR-9 `:dry_type_aliases` fact published by
|
|
45
47
|
# `rigor-dry-types` when loaded. Used to resolve `value(Types::Email)` references to their
|
|
46
48
|
# underlying class. Empty when the plugin isn't loaded.
|
|
47
|
-
# @return
|
|
49
|
+
# @return frozen per-schema typed-key
|
|
48
50
|
# table. Empty when no recognisable schema declaration is found.
|
|
49
|
-
def scan(paths:, type_aliases: {})
|
|
51
|
+
def scan(paths:, io_boundary:, type_aliases: {})
|
|
50
52
|
table = {}
|
|
51
53
|
paths.each do |path|
|
|
52
|
-
scan_file(path, type_aliases).each do |schema_const, shape|
|
|
54
|
+
scan_file(path, io_boundary, type_aliases).each do |schema_const, shape|
|
|
53
55
|
table[schema_const] ||= shape
|
|
54
56
|
end
|
|
55
57
|
end
|
|
56
58
|
table.freeze
|
|
57
59
|
end
|
|
58
60
|
|
|
59
|
-
def scan_file(path, type_aliases)
|
|
60
|
-
source =
|
|
61
|
+
def scan_file(path, io_boundary, type_aliases)
|
|
62
|
+
source = io_boundary.read_file(path)
|
|
61
63
|
parse_result = Prism.parse(source, filepath: path)
|
|
62
64
|
return {} unless parse_result.errors.empty?
|
|
63
65
|
|
|
@@ -78,6 +78,7 @@ module Rigor
|
|
|
78
78
|
class DrySchema < Rigor::Plugin::Base
|
|
79
79
|
manifest(
|
|
80
80
|
id: "dry-schema",
|
|
81
|
+
target_gems: ["dry-schema"],
|
|
81
82
|
version: "0.1.0",
|
|
82
83
|
description: "Recognises `Dry::Schema.{Params,JSON,define} { ... }` declarations " \
|
|
83
84
|
"and publishes the per-schema typed-key table.",
|
|
@@ -130,7 +131,8 @@ module Rigor
|
|
|
130
131
|
# `paths:`, parse errors degrade silently.
|
|
131
132
|
def prepare(services)
|
|
132
133
|
type_aliases = services.fact_store.read(plugin_id: "dry-types", name: :dry_type_aliases) || {}
|
|
133
|
-
table = SchemaScanner.scan(paths: scannable_paths(services),
|
|
134
|
+
table = SchemaScanner.scan(paths: scannable_paths(services), io_boundary: io_boundary,
|
|
135
|
+
type_aliases: type_aliases)
|
|
134
136
|
return if table.empty?
|
|
135
137
|
|
|
136
138
|
services.fact_store.publish(
|
|
@@ -164,11 +166,13 @@ module Rigor
|
|
|
164
166
|
shapes[name] = entry.nil? ? nil : ResultShape.build(entry)
|
|
165
167
|
end
|
|
166
168
|
|
|
169
|
+
# ADR-45 WD1b (#613 / #630) — the classification probes go through the boundary, so an entry that
|
|
170
|
+
# is not there yet (or stops being a directory) is a recorded dependency of the scan's input set.
|
|
167
171
|
def scannable_paths(services)
|
|
168
172
|
@scannable_paths ||= services.configuration.paths.flat_map do |entry|
|
|
169
|
-
if
|
|
173
|
+
if io_boundary.directory?(entry)
|
|
170
174
|
Dir.glob(File.join(entry, "**", "*.rb"), sort: true)
|
|
171
|
-
elsif
|
|
175
|
+
elsif io_boundary.file?(entry) && entry.end_with?(".rb")
|
|
172
176
|
[entry]
|
|
173
177
|
else
|
|
174
178
|
[]
|
|
@@ -51,6 +51,7 @@ module Rigor
|
|
|
51
51
|
class DryStruct < Rigor::Plugin::Base
|
|
52
52
|
manifest(
|
|
53
53
|
id: "dry-struct",
|
|
54
|
+
target_gems: ["dry-struct"],
|
|
54
55
|
version: "0.2.0",
|
|
55
56
|
description: "Recognises dry-struct `attribute :name, T` DSL via ADR-16 Tier C; " \
|
|
56
57
|
"promotes the reader's return type through ADR-18's `returns_from_arg:` " \
|
|
@@ -42,11 +42,13 @@ module Rigor
|
|
|
42
42
|
|
|
43
43
|
module_function
|
|
44
44
|
|
|
45
|
-
# @param paths
|
|
46
|
-
# @
|
|
45
|
+
# @param paths — absolute paths to `.rb` files the project's `paths:` resolves to.
|
|
46
|
+
# @param io_boundary — the plugin's {Rigor::Plugin::IoBoundary}; every source read goes
|
|
47
|
+
# through it (#630) so each scanned file is a recorded cache dependency.
|
|
48
|
+
# @return frozen `{aliased_name => underlying_class_name}` map. Empty
|
|
47
49
|
# when no `include Dry.Types()` declaration is found.
|
|
48
|
-
def scan(paths:)
|
|
49
|
-
results = paths.flat_map { |path| scan_file(path) }
|
|
50
|
+
def scan(paths:, io_boundary:)
|
|
51
|
+
results = paths.flat_map { |path| scan_file(path, io_boundary) }
|
|
50
52
|
modules = results.map { |r| r[:module_name] }.uniq
|
|
51
53
|
return {}.freeze if modules.empty?
|
|
52
54
|
|
|
@@ -75,8 +77,8 @@ module Rigor
|
|
|
75
77
|
end
|
|
76
78
|
private_class_method :canonical_table
|
|
77
79
|
|
|
78
|
-
def scan_file(path)
|
|
79
|
-
source =
|
|
80
|
+
def scan_file(path, io_boundary)
|
|
81
|
+
source = io_boundary.read_file(path)
|
|
80
82
|
parse_result = Prism.parse(source, filepath: path)
|
|
81
83
|
return [] unless parse_result.errors.empty?
|
|
82
84
|
|
|
@@ -58,6 +58,7 @@ module Rigor
|
|
|
58
58
|
class DryTypes < Rigor::Plugin::Base
|
|
59
59
|
manifest(
|
|
60
60
|
id: "dry-types",
|
|
61
|
+
target_gems: ["dry-types"],
|
|
61
62
|
version: "0.1.0",
|
|
62
63
|
description: "Recognises `module X; include Dry.Types(); end` and publishes the alias table.",
|
|
63
64
|
produces: [:dry_type_aliases]
|
|
@@ -74,10 +75,11 @@ module Rigor
|
|
|
74
75
|
# `watch:` covers exactly the files the scan reads: one glob per project `paths:` entry, co-extensive
|
|
75
76
|
# with {#scannable_paths}. A {Cache::Descriptor::GlobEntry} digests every file matching its glob, so a
|
|
76
77
|
# content edit, a file addition, and a file removal anywhere under those paths all move the digest and
|
|
77
|
-
# invalidate the entry.
|
|
78
|
-
#
|
|
78
|
+
# invalidate the entry. Since #630 the scan ALSO reads each file through the `IoBoundary`, so the
|
|
79
|
+
# descriptor carries a per-file row beside the globs: the globs alone already covered the scan's
|
|
80
|
+
# input, and the per-file rows are what a subset or incremental run has to invalidate on.
|
|
79
81
|
producer :dry_type_aliases, watch: -> { alias_watch_globs } do |_params|
|
|
80
|
-
AliasScanner.scan(paths: scannable_paths)
|
|
82
|
+
AliasScanner.scan(paths: scannable_paths, io_boundary: io_boundary)
|
|
81
83
|
end
|
|
82
84
|
|
|
83
85
|
# Builds the (cached) alias table and publishes it via the ADR-9 fact store. `producer_value` runs the
|
|
@@ -102,11 +104,13 @@ module Rigor
|
|
|
102
104
|
# Resolves the project's `paths:` to a flat list of `.rb` files the scanner walks. Mirrors
|
|
103
105
|
# `Analysis::Runner`'s `expand_paths` floor; we don't need the runner's full exclude/sort surface
|
|
104
106
|
# because the alias table is a union — any duplicate scan is a no-op.
|
|
107
|
+
# ADR-45 WD1b (#613 / #630) — the classification probes go through the boundary, so an entry that
|
|
108
|
+
# is not there yet (or stops being a directory) is a recorded dependency of the scan's input set.
|
|
105
109
|
def scannable_paths
|
|
106
110
|
@scannable_paths ||= services.configuration.paths.flat_map do |entry|
|
|
107
|
-
if
|
|
111
|
+
if io_boundary.directory?(entry)
|
|
108
112
|
Dir.glob(File.join(entry, "**", "*.rb"), sort: true)
|
|
109
|
-
elsif
|
|
113
|
+
elsif io_boundary.file?(entry) && entry.end_with?(".rb")
|
|
110
114
|
[entry]
|
|
111
115
|
else
|
|
112
116
|
[]
|
|
@@ -122,9 +126,9 @@ module Rigor
|
|
|
122
126
|
# would read is watched, so any edit / addition / removal under those paths invalidates the cache.
|
|
123
127
|
def alias_watch_globs
|
|
124
128
|
services.configuration.paths.filter_map do |entry|
|
|
125
|
-
if
|
|
129
|
+
if io_boundary.directory?(entry)
|
|
126
130
|
[entry, "**/*.rb"]
|
|
127
|
-
elsif
|
|
131
|
+
elsif io_boundary.file?(entry) && entry.end_with?(".rb")
|
|
128
132
|
[File.dirname(entry), File.basename(entry)]
|
|
129
133
|
end
|
|
130
134
|
end
|