rigortype 0.3.9 → 0.4.1
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 +5 -4
- 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 +127 -4
- data/docs/handbook/03-narrowing.md +95 -10
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/07-rbs-and-extended.md +16 -11
- data/docs/handbook/08-understanding-errors.md +3 -2
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +454 -13
- data/docs/install.md +87 -15
- data/docs/manual/02-cli-reference.md +65 -4
- data/docs/manual/03-configuration.md +12 -0
- data/docs/manual/04-diagnostics.md +4 -0
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/08-skills.md +4 -3
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/12-caching.md +43 -4
- data/docs/manual/14-rails-quickstart.md +19 -11
- data/docs/manual/16-rbs-extended-annotations.md +40 -7
- 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 +243 -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 +110 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +11 -5
- 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 +212 -25
- 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 +1 -1
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -3
- data/lib/rigor/analysis/check_rules/rule_ids.rb +20 -5
- data/lib/rigor/analysis/check_rules/rule_walk.rb +2 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +427 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +36 -2
- data/lib/rigor/analysis/check_rules.rb +638 -136
- data/lib/rigor/analysis/dependency_recorder.rb +222 -17
- data/lib/rigor/analysis/fact_store.rb +9 -0
- data/lib/rigor/analysis/incremental.rb +26 -0
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +266 -0
- data/lib/rigor/analysis/incremental_run_slot.rb +171 -0
- data/lib/rigor/analysis/incremental_session.rb +309 -53
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +24 -13
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/plugin_roots.rb +0 -1
- data/lib/rigor/analysis/reachability/scan_cache.rb +3 -1
- data/lib/rigor/analysis/rule_catalog.rb +127 -0
- data/lib/rigor/analysis/run_cache_key.rb +46 -18
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +168 -12
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -4
- data/lib/rigor/analysis/runner/pool_coordinator.rb +109 -17
- data/lib/rigor/analysis/runner/project_pre_passes.rb +44 -17
- data/lib/rigor/analysis/runner.rb +603 -54
- data/lib/rigor/analysis/shadow_harness.rb +27 -0
- data/lib/rigor/analysis/source_rbs_gate.rb +157 -0
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +93 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +409 -0
- data/lib/rigor/analysis/worker_session.rb +57 -13
- data/lib/rigor/bleeding_edge.rb +0 -2
- data/lib/rigor/builtins/hkt_builtins.rb +1 -0
- data/lib/rigor/builtins/imported_refinements.rb +4 -0
- data/lib/rigor/builtins/regex_refinement.rb +17 -9
- data/lib/rigor/builtins/static_return_refinements.rb +2 -0
- data/lib/rigor/cache/descriptor.rb +45 -1
- data/lib/rigor/cache/engine_source.rb +29 -1
- data/lib/rigor/cache/file_digest.rb +28 -0
- data/lib/rigor/cache/incremental_snapshot.rb +102 -8
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_descriptor.rb +37 -7
- data/lib/rigor/cache/store.rb +63 -4
- data/lib/rigor/cache/value_digest.rb +325 -0
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/check_command.rb +83 -13
- data/lib/rigor/cli/doc_links.rb +1 -1
- data/lib/rigor/cli/docs_command.rb +4 -4
- data/lib/rigor/cli/doctor_command.rb +1 -1
- data/lib/rigor/cli/effects_report.rb +2 -2
- data/lib/rigor/cli/plugin_command.rb +3 -3
- data/lib/rigor/cli/prism_colorizer.rb +0 -1
- data/lib/rigor/cli/sig_gen_command.rb +210 -29
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +0 -1
- data/lib/rigor/cli/type_of_command.rb +19 -5
- 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/unused_command.rb +3 -3
- data/lib/rigor/cli.rb +21 -3
- data/lib/rigor/config_audit.rb +3 -2
- data/lib/rigor/config_path.rb +29 -0
- data/lib/rigor/configuration/severity_profile.rb +24 -3
- data/lib/rigor/configuration.rb +71 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +11 -2
- 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 +9 -2
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/effect_table.rb +11 -3
- data/lib/rigor/effects/envelope_check.rb +1 -1
- data/lib/rigor/effects/envelope_index.rb +15 -0
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/identity.rb +16 -0
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +21 -0
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +49 -37
- data/lib/rigor/effects/propagator.rb +295 -16
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +121 -72
- data/lib/rigor/effects/signature_sources.rb +1 -1
- data/lib/rigor/effects/snapshot.rb +2 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +385 -30
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -3
- data/lib/rigor/environment/lockfile_resolver.rb +27 -1
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/rbs_collection_discovery.rb +10 -1
- data/lib/rigor/environment/rbs_loader.rb +400 -134
- data/lib/rigor/environment/source_rbs_synthesis.rb +147 -0
- data/lib/rigor/environment.rb +104 -96
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +139 -9
- 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 +88 -26
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +2 -1
- data/lib/rigor/inference/budget_trace.rb +2 -1
- 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 +393 -15
- data/lib/rigor/inference/closure_escape_analyzer.rb +157 -13
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/declaration_walk/context.rb +195 -0
- data/lib/rigor/inference/declaration_walk/errors.rb +18 -0
- data/lib/rigor/inference/declaration_walk/shadow.rb +147 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +441 -0
- data/lib/rigor/inference/declaration_walk.rb +7 -0
- data/lib/rigor/inference/def_node_resolver.rb +3 -2
- 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/definer_resolution.rb +266 -0
- data/lib/rigor/inference/element_read_widening.rb +22 -10
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +1665 -538
- data/lib/rigor/inference/external_ancestor_resolution.rb +264 -0
- 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 +488 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/index_write_widening.rb +16 -3
- 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 +179 -17
- 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 +85 -24
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +4 -0
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +113 -73
- 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/rbs_dispatch.rb +901 -38
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +128 -53
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +214 -13
- data/lib/rigor/inference/method_parameter_binder.rb +8 -3
- data/lib/rigor/inference/module_function_state.rb +213 -0
- data/lib/rigor/inference/multi_target_binder.rb +345 -52
- data/lib/rigor/inference/mutation_rejoin.rb +4 -1
- data/lib/rigor/inference/mutation_widening.rb +70 -48
- data/lib/rigor/inference/narrowing.rb +674 -124
- 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 +152 -9
- data/lib/rigor/inference/parameter_inference_collector.rb +13 -11
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +7 -2
- data/lib/rigor/inference/project_patched_scanner.rb +7 -3
- data/lib/rigor/inference/receiver_alias.rb +90 -1
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +15 -11
- 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/certainty.rb +176 -0
- data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +35 -0
- data/lib/rigor/inference/scope_indexer/def_nestings_collector.rb +47 -0
- data/lib/rigor/inference/scope_indexer/layered_def_nestings.rb +36 -0
- data/lib/rigor/inference/scope_indexer/member_layouts_collector.rb +61 -0
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +130 -0
- data/lib/rigor/inference/scope_indexer/superclasses_collector.rb +64 -0
- data/lib/rigor/inference/scope_indexer.rb +5913 -701
- data/lib/rigor/inference/singleton_hook_decline.rb +253 -0
- data/lib/rigor/inference/statement_evaluator.rb +3249 -497
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +44 -7
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +3 -2
- data/lib/rigor/language_server/hover_renderer.rb +3 -3
- data/lib/rigor/language_server/project_context.rb +5 -3
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +196 -13
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +1 -1
- data/lib/rigor/plugin/effect_attribution.rb +58 -4
- data/lib/rigor/plugin/io_boundary.rb +82 -4
- data/lib/rigor/plugin/isolation.rb +1 -1
- data/lib/rigor/plugin/loader.rb +2 -1
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/manifest.rb +71 -10
- data/lib/rigor/plugin/registry.rb +35 -1
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +9 -3
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/protection/discovery_seed.rb +20 -9
- data/lib/rigor/protection/kill_signature.rb +0 -1
- data/lib/rigor/protection/mutation_cache.rb +4 -5
- data/lib/rigor/rbs_extended.rb +27 -0
- data/lib/rigor/reflection/constant_ancestors.rb +146 -0
- data/lib/rigor/reflection/constant_path.rb +41 -13
- data/lib/rigor/reflection.rb +73 -107
- data/lib/rigor/scope/discovery_index.rb +351 -2
- data/lib/rigor/scope/resolution_chain/relevance.rb +165 -0
- data/lib/rigor/scope/resolution_chain.rb +884 -0
- data/lib/rigor/scope.rb +981 -198
- 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 +580 -47
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +1 -1
- data/lib/rigor/sig_gen/renderer.rb +124 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +44 -1
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +166 -35
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +1 -1
- data/lib/rigor/source/node_walker.rb +0 -3
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/type/combinator.rb +112 -12
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/hash_shape.rb +1 -1
- data/lib/rigor/type/refined.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +9 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +13 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +0 -1
- 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 +239 -4
- 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/effects.rb +1 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +9 -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 +380 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +281 -35
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +25 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +171 -5
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +2 -0
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +10 -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.rb +72 -2
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +11 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +35 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +9 -17
- 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 +217 -36
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +9 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +0 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +46 -1
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -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/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 +14 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +6 -4
- 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 +2 -1
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +50 -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 +7 -6
- data/sig/rigor/scope.rbs +177 -20
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -7
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +6 -0
- data/sig/rigor.rbs +38 -20
- data/skills/rigor-ask/SKILL.md +8 -5
- 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 +12 -25
- 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 +46 -18
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +40 -10
- 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-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +4 -6
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +12 -8
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +0 -3
- data/skills/rigor-unused-adjudicate/SKILL.md +4 -2
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +132 -1
data/docs/install.md
CHANGED
|
@@ -10,19 +10,42 @@ skill (`rigor-project-init` for a project that has never run Rigor).
|
|
|
10
10
|
**Do not add Rigor to the project's `Gemfile`** — Rigor is a
|
|
11
11
|
standalone tool, not a library.
|
|
12
12
|
|
|
13
|
+
**Install the latest release, not whatever is already on the
|
|
14
|
+
machine.** A `rigor` already on PATH, or a version manager that
|
|
15
|
+
resolves to an older release, is not a reason to stop early: Rigor
|
|
16
|
+
changes quickly, and the skills this guide hands off to are written
|
|
17
|
+
for the current release. Step 1 looks up the latest version; Step 2
|
|
18
|
+
installs it and Step 3 checks it.
|
|
19
|
+
|
|
13
20
|
---
|
|
14
21
|
|
|
15
22
|
## Step 1 — Detect the environment
|
|
16
23
|
|
|
17
|
-
Run these
|
|
24
|
+
Run these checks and note which tools are available:
|
|
18
25
|
|
|
19
26
|
```sh
|
|
20
27
|
which mise # preferred — see Step 2A
|
|
21
28
|
which asdf # fallback — see Step 2B
|
|
22
29
|
ruby --version 2>/dev/null | head -1 # is Ruby 4.0 already on PATH?
|
|
23
|
-
which docker # last resort — see
|
|
30
|
+
which docker # last resort — see "Last resort — Docker"
|
|
31
|
+
rigor --version 2>/dev/null # an existing install, if any
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then look up the latest Rigor release on RubyGems:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
curl -fsS https://rubygems.org/api/v1/versions/rigortype/latest.json
|
|
24
38
|
```
|
|
25
39
|
|
|
40
|
+
It prints `{"version":"X.Y.Z"}`. Below, `<LATEST>` stands for that
|
|
41
|
+
`X.Y.Z`: replace it with the version you got, never type `<LATEST>`
|
|
42
|
+
literally. Without `curl`, `gem search --remote --exact rigortype`
|
|
43
|
+
gives the same answer once Ruby is available. If neither works, tell
|
|
44
|
+
the user you could not determine the latest version instead of
|
|
45
|
+
guessing one.
|
|
46
|
+
|
|
47
|
+
An existing `rigor` older than `<LATEST>` still goes through Step 2;
|
|
48
|
+
tell the user which version they have and which you are installing.
|
|
26
49
|
Then proceed to the **first** matching case below.
|
|
27
50
|
|
|
28
51
|
---
|
|
@@ -40,23 +63,51 @@ that can be committed alongside the code. Other contributors — and CI
|
|
|
40
63
|
— run `mise install` to restore those versions with no `Gemfile`
|
|
41
64
|
involvement.
|
|
42
65
|
|
|
43
|
-
|
|
66
|
+
First ask mise which Rigor version it would pick:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
mise latest gem:rigortype
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If that is older than `<LATEST>`, mise is holding the newer release
|
|
73
|
+
back — usually its `minimum_release_age` quarantine, which hides
|
|
74
|
+
releases for a while after they are published (`mise ls-remote
|
|
75
|
+
gem:rigortype` then warns `1 newer gem:rigortype release hidden by
|
|
76
|
+
minimum_release_age` on stderr). A bare `mise use gem:rigortype`
|
|
77
|
+
would install the older version with no error, so this is the step where agents
|
|
78
|
+
silently end up on a stale Rigor. The quarantine is a supply-chain
|
|
79
|
+
safeguard, so do not bypass it on your own: tell the user both
|
|
80
|
+
versions and ask which to install. `mise settings get
|
|
81
|
+
minimum_release_age` tells you whose choice it is: an error ("not
|
|
82
|
+
set") means mise's built-in default is in effect and you can recommend
|
|
83
|
+
`<LATEST>`; a value means the user configured it, so recommend
|
|
84
|
+
respecting it.
|
|
85
|
+
|
|
86
|
+
Then run in the project root, with the version the user agreed to:
|
|
44
87
|
|
|
45
88
|
```sh
|
|
46
89
|
mise use ruby@4.0
|
|
47
|
-
mise use --pin gem:rigortype
|
|
90
|
+
mise use --pin gem:rigortype@<LATEST>
|
|
48
91
|
```
|
|
49
92
|
|
|
50
93
|
`mise use` installs the tools and writes their versions to `mise.toml`
|
|
51
|
-
in one step. Commit `mise.toml` so the version is shared.
|
|
94
|
+
in one step. Commit `mise.toml` so the version is shared. Name the
|
|
95
|
+
version explicitly, as above: an explicit version is installed even
|
|
96
|
+
while the quarantine hides it from `mise latest`.
|
|
52
97
|
|
|
53
|
-
`--pin` records the exact Rigor version (`"gem:rigortype" = "
|
|
98
|
+
`--pin` records the exact Rigor version (`"gem:rigortype" = "X.Y.Z"`).
|
|
54
99
|
Without it mise writes `"gem:rigortype" = "latest"`, which every
|
|
55
100
|
machine re-resolves to whatever is newest when it first installs — so
|
|
56
101
|
a committed `latest` does not give the team one shared version. The
|
|
57
102
|
trade-off: a pin will not move on its own, and `mise outdated` cannot
|
|
58
|
-
report a pinned tool as behind. Upgrade
|
|
59
|
-
gem:rigortype
|
|
103
|
+
report a pinned tool as behind. Upgrade by running `mise use --pin
|
|
104
|
+
gem:rigortype@<version>` again with the newer version; `mise upgrade
|
|
105
|
+
--bump gem:rigortype` goes through the same quarantine as a bare
|
|
106
|
+
`mise use`.
|
|
107
|
+
|
|
108
|
+
A user-wide `~/.config/mise/config.toml` entry for `gem:rigortype`
|
|
109
|
+
keeps applying outside this project. Mention it if it names an older
|
|
110
|
+
version, but do not edit global config without the user's consent.
|
|
60
111
|
|
|
61
112
|
Then verify:
|
|
62
113
|
|
|
@@ -88,7 +139,8 @@ gem is installed with `gem install` after setting the Ruby version.
|
|
|
88
139
|
```sh
|
|
89
140
|
asdf install ruby latest:4.0
|
|
90
141
|
asdf local ruby latest:4.0
|
|
91
|
-
gem install rigortype
|
|
142
|
+
gem install rigortype -v <LATEST>
|
|
143
|
+
asdf reshim ruby
|
|
92
144
|
```
|
|
93
145
|
|
|
94
146
|
Verify:
|
|
@@ -108,7 +160,7 @@ pinning; see <https://mise.jdx.dev/getting-started.html>.
|
|
|
108
160
|
If `ruby --version` reports `ruby 4.0.*`, install the gem directly:
|
|
109
161
|
|
|
110
162
|
```sh
|
|
111
|
-
gem install rigortype
|
|
163
|
+
gem install rigortype -v <LATEST>
|
|
112
164
|
```
|
|
113
165
|
|
|
114
166
|
Verify:
|
|
@@ -152,6 +204,11 @@ and does not integrate well with editor LSP. Use it only when a
|
|
|
152
204
|
host-side Ruby 4.0 is genuinely unavailable (for example, Windows
|
|
153
205
|
without WSL). For all other environments, prefer Case A–D above.
|
|
154
206
|
|
|
207
|
+
With Docker there is no `rigor` on the host PATH, so Step 3 checks the
|
|
208
|
+
image instead: `docker run --rm ghcr.io/rigortype/rigor:latest rigor
|
|
209
|
+
--version`. The image can trail RubyGems by a release; report its
|
|
210
|
+
version to the user rather than treating a mismatch as a failure.
|
|
211
|
+
|
|
155
212
|
---
|
|
156
213
|
|
|
157
214
|
## Step 3 — Verify the installation
|
|
@@ -160,8 +217,23 @@ without WSL). For all other environments, prefer Case A–D above.
|
|
|
160
217
|
rigor --version
|
|
161
218
|
```
|
|
162
219
|
|
|
163
|
-
|
|
164
|
-
If
|
|
220
|
+
The reported version should be the one you installed in Step 2
|
|
221
|
+
(normally `<LATEST>`). If it is older, you are running a different
|
|
222
|
+
`rigor` than the one just installed. With mise, first check what the
|
|
223
|
+
project resolves to:
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
mise exec -- rigor --version
|
|
227
|
+
mise which rigor
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
If `mise exec` reports the new version, the shell's PATH is stale (a
|
|
231
|
+
non-interactive shell does not re-run mise's activation after `mise
|
|
232
|
+
use`); run `eval "$(mise hook-env)"`, or use `mise exec -- rigor` for
|
|
233
|
+
the remaining steps. Otherwise run `which -a rigor` to find the older
|
|
234
|
+
install. Do not uninstall anything to fix this without asking, and do
|
|
235
|
+
not continue on the older version without telling the user. If the
|
|
236
|
+
command is not found, revisit Step 2 for your case.
|
|
165
237
|
|
|
166
238
|
---
|
|
167
239
|
|
|
@@ -192,6 +264,6 @@ project is set up, re-run `rigor skill describe` for the step after
|
|
|
192
264
|
that.
|
|
193
265
|
|
|
194
266
|
If `rigor skill describe` is not recognised, your Rigor version predates
|
|
195
|
-
it
|
|
196
|
-
|
|
197
|
-
|
|
267
|
+
it: you are not on the version Step 1 found. Go back to Step 3. If
|
|
268
|
+
you are staying on an older version with the user's agreement, run
|
|
269
|
+
`rigor skill rigor-project-init` directly.
|
|
@@ -34,8 +34,8 @@ the `paths:` list from the configuration file.
|
|
|
34
34
|
| `--format=FORMAT` | Output format. Default `text`. Also `json` (structured stream), plus the CI-native renderings `sarif`, `github`, `gitlab`, `checkstyle`, `junit`, and `teamcity` — see [Running Rigor in CI](11-ci.md). |
|
|
35
35
|
| `--no-ci-detect` | Disable CI auto-detection — by default `text` output also emits the running CI's native annotations / hint (`RIGOR_CI_DETECT=0` does the same). See [Running Rigor in CI § auto-detection](11-ci.md). |
|
|
36
36
|
| `--explain` | Surface fail-soft fallback events as `info` diagnostics. |
|
|
37
|
-
| `--no-cache` | Skip the persistent cache for this run. |
|
|
38
|
-
| `--incremental` | Re-analyse only the files changed since the last run plus the files that depend on them, serving the rest from a cross-process disk snapshot (ADR-46). Diagnostics are identical to a full run; a config / gem / version change (or a file added or removed) transparently forces a full re-analysis. See [Caching](12-caching.md). |
|
|
37
|
+
| `--no-cache` | Skip the persistent cache for this run. With `--incremental` it is a cold full analysis: the incremental snapshot and the run-result cache are neither read nor written, so the next plain `--incremental` run still uses the snapshot it had before. |
|
|
38
|
+
| `--incremental` | Re-analyse only the files changed since the last run plus the files that depend on them, serving the rest from a cross-process disk snapshot (ADR-46). Diagnostics are identical to a full run; a config / gem / version change (or a file added or removed) transparently forces a full re-analysis. A run with nothing changed is answered from the cache without starting the analyzer. See [Caching](12-caching.md). |
|
|
39
39
|
| `--verify-incremental` | Acceptance gate: run the incremental analyzer against a full `--no-cache` run and assert the diagnostics are byte-identical, then exit (0 on match, 1 with the differing diagnostics on mismatch). Used in CI to guarantee `--incremental` never serves a stale result. |
|
|
40
40
|
| `--clear-cache` | Delete the cache directory before running. |
|
|
41
41
|
| `--cache-stats` | Print the on-disk cache inventory when finished — on stdout under `--format text`, on stderr under every other format, so machine-readable output stays a parseable document. `--clear-cache`'s and `--verify-incremental`'s notes follow the same rule. |
|
|
@@ -138,6 +138,28 @@ truncation explicit. `--trace` records fail-soft fallbacks,
|
|
|
138
138
|
after the rows of a line table in text output. The editor-mode
|
|
139
139
|
`--tmp-file` / `--instead-of` pair is accepted as on `check`.
|
|
140
140
|
|
|
141
|
+
A template a plugin compiles into Ruby (an ERB view under
|
|
142
|
+
`rigor-actionpack`) is probed the way `rigor check` analyses
|
|
143
|
+
it: the compiled Ruby is typed under the view's declared
|
|
144
|
+
`self`, locals and instance variables, and `LINE:COL` are the
|
|
145
|
+
template's own. A column answers only when it lies in Ruby the
|
|
146
|
+
compiler copied verbatim — the `@user.name` in
|
|
147
|
+
`<%= @user.name %>` — and denotes exactly one compiled
|
|
148
|
+
expression. A column in HTML text, in code the plugin rewrote
|
|
149
|
+
(a layout's `<%= yield %>`), or in bytes copied to more than
|
|
150
|
+
one place prints `no expression found at …` with the reason
|
|
151
|
+
and exits `1`; the command never answers about a nearby
|
|
152
|
+
node instead. Two tags that name the same thing (`<%= v %>`
|
|
153
|
+
beside `<% if "a" <= v %>`, or `<%= v %> <%= v.to_s %>`)
|
|
154
|
+
decline for that reason as well; a name repeated inside ONE
|
|
155
|
+
tag still answers. A bare `FILE:LINE` lists only the expressions
|
|
156
|
+
that map back to a template column. `--trace` fallbacks are
|
|
157
|
+
reported at the template line, and a JSON fallback carries a
|
|
158
|
+
`column` only when its position maps back to one. A template
|
|
159
|
+
the plugin declined to compile prints
|
|
160
|
+
`plugin declined the template; probing its bytes as Ruby`
|
|
161
|
+
and is probed as plain Ruby, parse error included.
|
|
162
|
+
|
|
141
163
|
The four probe commands — `type-of`, `type-scan`, `trace` and
|
|
142
164
|
`annotate` — build their environment fresh on every invocation
|
|
143
165
|
and never read or write the persistent cache. That is why none
|
|
@@ -477,13 +499,52 @@ rigor sig-gen [paths]
|
|
|
477
499
|
| `--print` | Write RBS to stdout. Default. |
|
|
478
500
|
| `--diff` | Write a unified diff against existing RBS. |
|
|
479
501
|
| `--write` | Write RBS to `sig/<path>.rbs` files. |
|
|
480
|
-
| `--
|
|
502
|
+
| `--check` | Write nothing; print what `--write` with the same options would change, and exit `1` if anything would. The CI freshness gate. |
|
|
503
|
+
| `--overwrite` | Allow tighter-return updates, and inline declarations that disagree with `sig/`, to replace user-authored RBS. |
|
|
481
504
|
| `--include-private` | Emit private and protected methods too. |
|
|
482
505
|
| `--params=untyped\|observed\|observed-strict` | Parameter-typing policy. Default `untyped`. |
|
|
483
|
-
| `--observe=PATH` | Scan `PATH` for call-site observations. Repeatable. |
|
|
506
|
+
| `--observe=PATH` | Scan `PATH` for call-site observations. Repeatable. Default: the configured `test_paths:` (unset: whichever of `spec/` and `test/` exist). |
|
|
484
507
|
| `--new-files` / `--new-methods` / `--tighter-returns` | Emit only that classification. |
|
|
508
|
+
| `--effect-envelopes` | Also emit `%a{rigor:v1:effect …}` for effectful methods. Needs the `effects:` opt-in. |
|
|
509
|
+
| `--no-cache` | Do not read or write the analysis cache. Only effect collection uses it. |
|
|
485
510
|
| `--format=text\|json` | Output format. |
|
|
486
511
|
|
|
512
|
+
`--print`, `--diff`, `--write` and `--check` are mutually exclusive.
|
|
513
|
+
`--check` fails exactly when `--write` would create, change or
|
|
514
|
+
refuse a file, so a tighter return `--write` declines without
|
|
515
|
+
`--overwrite` does not fail it; `--check --overwrite` counts one.
|
|
516
|
+
See [handbook chapter 11](../handbook/11-sig-gen.md#keeping-sig-current-in-ci).
|
|
517
|
+
|
|
518
|
+
A method declared inline with `# @rbs` / `#:` is written as that
|
|
519
|
+
declaration, not as what its body infers; a parameter-only
|
|
520
|
+
annotation keeps its parameters and takes the return from the body,
|
|
521
|
+
and `initialize` is always `-> void`. When `sig/` already declares
|
|
522
|
+
the method (a `def` or an `attr_*`) and the two disagree as types —
|
|
523
|
+
parameter names and union spelling do not count, overload order
|
|
524
|
+
does — sig-gen changes neither: the method is refused
|
|
525
|
+
(`sig.skipped.inline-differs`, listed under `refused` in `--format=json`),
|
|
526
|
+
and `--write` / `--check` exit `1` until you make them agree or pass
|
|
527
|
+
`--overwrite`, which replaces the whole `sig/` member with the inline
|
|
528
|
+
declaration. For a parameter-only annotation only the parameters are
|
|
529
|
+
compared; the return follows the ordinary proposal rules. A class
|
|
530
|
+
made generic inline is not written unless `sig/` declares it with the
|
|
531
|
+
same type parameters. A project whose Steep reads the same
|
|
532
|
+
annotations sets `sig_gen.inline_declared: skip` in `.rigor.yml` to
|
|
533
|
+
keep those methods out of `sig/`. See
|
|
534
|
+
[handbook chapter 11](../handbook/11-sig-gen.md#methods-declared-inline).
|
|
535
|
+
|
|
536
|
+
When `.rigor.yml` carries an `effects:` block, sig-gen also writes
|
|
537
|
+
`%a{pure}` above a method whose effect summary is **exhaustive**
|
|
538
|
+
(every call it reaches was resolved), **undischarged** (nothing in
|
|
539
|
+
its footprint is only invisible because `effects.tolerated:` says
|
|
540
|
+
so), **claimed** (every callee is described by a catalogue row, a
|
|
541
|
+
plugin, an envelope or a project definition), carries no authored
|
|
542
|
+
bound of its own, and is free of surviving labels in the `≤` lane. Nothing else is annotated, and
|
|
543
|
+
`--effect-envelopes` adds Rigor's own labelled spelling for methods
|
|
544
|
+
that do have a footprint. With no `effects:` block the output is
|
|
545
|
+
byte-for-byte what it was before. See
|
|
546
|
+
[handbook chapter 11](../handbook/11-sig-gen.md#emitting-effect-annotations).
|
|
547
|
+
|
|
487
548
|
Every signature is parsed before it is emitted. A method whose
|
|
488
549
|
generated RBS does not parse is **skipped** (`sig.skipped.unrenderable-rbs`)
|
|
489
550
|
and reported on stderr rather than written — an unparseable
|
|
@@ -21,6 +21,11 @@ discovery entirely.
|
|
|
21
21
|
|
|
22
22
|
All relative paths in a config file resolve against that
|
|
23
23
|
file's own directory.
|
|
24
|
+
A leading `~/` (or a bare `~`) in a path setting expands to your home directory; `~name` is an ordinary
|
|
25
|
+
directory called `~name`, not another user's home. This covers `paths:`, `signature_paths:`, `test_paths:`,
|
|
26
|
+
`pre_eval:`, `plugins_io.allowed_paths:`, `includes:`, `bundler.bundle_path:`, `bundler.lockfile:` and
|
|
27
|
+
`rbs_collection.lockfile:`. It does not apply to `cache.path:`, `baseline:` or `effects.snapshot.path:`, which stay
|
|
28
|
+
literal and relative to the working directory.
|
|
24
29
|
|
|
25
30
|
## Editor validation
|
|
26
31
|
|
|
@@ -60,6 +65,7 @@ cache:
|
|
|
60
65
|
| `target_ruby` | String | `"4.0"` | The Ruby version *your* project runs — `"X.Y"`, `"X.Y.Z"`, or `"latest"`. Independent of the Ruby Rigor itself runs on. |
|
|
61
66
|
| `paths` | Array | `["lib"]` | Directories or files to analyse. |
|
|
62
67
|
| `exclude` | Array | `[]` | Glob patterns to skip. `vendor/bundle`, `.bundle`, and `node_modules` are always excluded. |
|
|
68
|
+
| `test_paths` | Array | `nil` | The project's test roots: the directories (or files) holding its tests. Relative entries resolve against the config file's directory. Unset auto-detects whichever of `spec/` and `test/` exist; `[]` declares none. `rigor sig-gen --params=observed` reads call sites there to type parameters, and names on stderr a declared root that does not exist. Test roots are not analysed unless `paths:` also lists them, and changing them invalidates no cache. |
|
|
63
69
|
| `includes` | Array | `[]` | Other config files to layer underneath this one. |
|
|
64
70
|
| `fold_platform_specific_paths` | Boolean | `false` | Resolve Ruby-version-conditional load paths when discovering sources. |
|
|
65
71
|
| `parameter_inference` | Boolean | `false` | Opt-in call-site parameter type inference on the `check` walk ([ADR-67](../adr/67-parameter-type-inference.md) WD6). When `true`, an undeclared `def` / `initialize` / setter parameter is typed to the union of its resolved call-site argument types, sharpening downstream ivar reads, folds, and protection coverage. Precision-additive only — the negative rules never fire against an inferred parameter. Cannot be combined with `--incremental`. |
|
|
@@ -73,6 +79,12 @@ cache:
|
|
|
73
79
|
| `pre_eval` | Array | `[]` | Files (or globs) walked before per-file analysis, to register project monkey-patches and publish their top-level constants project-wide. |
|
|
74
80
|
| `plugins` | Array | `[]` | Plugins to activate — see [Using plugins](07-plugins.md). |
|
|
75
81
|
|
|
82
|
+
### Signature generation
|
|
83
|
+
|
|
84
|
+
| Key | Type | Default | Meaning |
|
|
85
|
+
| --- | --- | --- | --- |
|
|
86
|
+
| `sig_gen.inline_declared` | String | `"write"` | What `rigor sig-gen` does with a method already declared inline by `# @rbs` / `#:`. `write` copies the inline declaration into `sig/`, so the generated signature is the complete contract a gem ships, and refuses (exit 1) a `sig/` declaration that later disagrees with the inline one until the two agree or `--overwrite` replaces it. `skip` leaves every method the inline reader declares out of `sig/` (`sig.skipped.inline-declared`): set it when Steep reads the same annotations (`inline: true` beside `signature "sig"`), where a copy would declare each method twice (`DuplicatedMethodDefinition`). The cost of `skip`: a consumer reading only your shipped `sig/` never sees those methods, and an annotation on one — a Rigor refinement included — takes effect only where the source itself is analysed. Any other value, or any other key under `sig_gen:`, is a load error. Only `rigor sig-gen` reads this key, and changing it invalidates no cache. See [handbook chapter 11](../handbook/11-sig-gen.md#methods-declared-inline). |
|
|
87
|
+
|
|
76
88
|
### Config validation warnings
|
|
77
89
|
|
|
78
90
|
`rigor check` warns on STDERR when a configured value silently resolves to
|
|
@@ -16,6 +16,7 @@ Every rule has a two-segment `family.rule` identifier:
|
|
|
16
16
|
| `call` | Call sites — undefined methods, arity, argument types, nil receivers. |
|
|
17
17
|
| `flow` | Control-flow proofs — always-raises, dead branches, constant conditions. |
|
|
18
18
|
| `def` | Method definitions — return types, ivar writes, visibility. |
|
|
19
|
+
| `global` | Writes to special globals — a value the setter rejects, a read-only variable. |
|
|
19
20
|
| `assert` | `assert_type` checks. |
|
|
20
21
|
| `dump` | `dump_type` notices. |
|
|
21
22
|
|
|
@@ -70,11 +71,14 @@ carries no `documentation_url`.
|
|
|
70
71
|
| <a id="rule-def-override-visibility-reduced"></a>`def.override-visibility-reduced` | An override reduces the visibility it inherits from a project-defined ancestor. | high |
|
|
71
72
|
| <a id="rule-def-override-return-widened"></a>`def.override-return-widened` | An override's declared return type widens the inherited return (covariance). | high |
|
|
72
73
|
| <a id="rule-def-override-param-narrowed"></a>`def.override-param-narrowed` | An override narrows an inherited parameter type (contravariance). | high |
|
|
74
|
+
| <a id="rule-global-write-type-mismatch"></a>`global.write-type-mismatch` | A special global is assigned a literal its setter rejects, so the write raises `TypeError` every time it runs. `$/`, `$-0`, `$,` and `$\` take only a String or nil (`$/ = 1` and `$/ = /x/` report). `$;` and `$-F` take a String, a Regexp, nil, or an object with `to_str`. `$~` takes a MatchData or nil. `$0` and `$PROGRAM_NAME` take a String or an object with `to_str`, so `$0 = nil` and `$0 = :name` report. `$.` takes an Integer, a Float, or an object with `to_int`, so `$. = "3"` reports and `$. = 3r` does not. `$-i` takes a String, nil, false, or an object with `to_str`. `$stdout`, `$>` and `$stderr` take anything that responds to `write`: `$stdout = 1` reports, `$stdout = StringIO.new` does not. Ruby's setter decides, not the global's RBS type. Only a value written as a literal is judged — a number, a string, a symbol, an array, a hash or a regexp literal (interpolated or not), or `nil`, `true` or `false` — so a variable, a method call or a constant never reports, whatever its type. A literal stays silent when your program defines the method the setter asks for (`write`, `to_str`, `to_int`) or a `method_missing` / `respond_to_missing?` / `respond_to?` anywhere, in any spelling and on any class — Rigor cannot always tell which objects such a definition reaches, so it does not try — or when a top-level `include` / `extend` or an ancestor's `include` names a module Rigor has no RBS for. For `$stdout`, `$>` and `$stderr` it also stays silent where a `using` is in effect for a refinement that may add `write`. `$/`, `$-0`, `$,`, `$\` and `$~` accept only their classes, so none of that silences them. A write to `$stdin` is never checked, and a special any file aliases (`alias $stdout $out`, including a `pre_eval:` file) is exempt. `warning` under `lenient`. | high |
|
|
75
|
+
| <a id="rule-global-readonly-write"></a>`global.readonly-write` | A read-only special global is written — `$!`, `$$`, `$?`, `$<`, `$FILENAME`, `$*`, `$:` / `$LOAD_PATH` / `$-I`, `$"` / `$LOADED_FEATURES`, `$-W`, `$-p`, `$-l` or `$-a` — which raises `NameError` whatever the value. Covers `$g = value`, `$g += value` and a multiple-assignment target. `$LOAD_PATH ||= []` never writes and `$LOAD_PATH << dir` is a method call, so neither fires. A special any file aliases (`alias $! $err`) is exempt. An error in every profile. | high |
|
|
73
76
|
| <a id="rule-static-value-use-void"></a>`static.value-use.void` | A value recovered from an author-declared `-> void` return is used in value context (an assignment right-hand side, a call receiver, or a call argument). Off by default; reaches a run only through the `use-of-void-value` bleeding-edge feature (ADR-100). A bare-statement `void` call and a legitimate `top` value both stay silent. | high |
|
|
74
77
|
| <a id="rule-effect-envelope-exceeded"></a>`effect.envelope-exceeded` | A method performs an effect its declared envelope does not admit — its proven effect labels (its own body plus everything it calls) are not covered by the `%a{pure}` or `%a{rigor:v1:effect …}` bound written on it or on its class. Opt-in twice over: it needs an `effects:` block in `.rigor.yml` and an envelope you wrote. Positioned at the Ruby `def`. Unproven ("and possibly more") effects never fire, and `mutate.local` is tolerated by every envelope. | high |
|
|
75
78
|
| <a id="rule-effect-liskov-widened"></a>`effect.liskov-widened` | An override escapes the envelope written on the method it overrides. A `PgRepo` is usable wherever a `Repo` is, so a `%a{rigor:v1:effect io.db}` on `Repo#find` binds `PgRepo#find` too: an implementation may be purer than the bound it inherits, never less pure. Either what the override *does* exceeds the inherited bound, or the envelope the override *declares for itself* is wider than it. Both sides must be authored — nothing fires unless someone wrote an envelope on the ancestor — and only subclassing counts, not `include`. Positioned at the override's `def`. Needs an `effects:` block. | high |
|
|
76
79
|
| <a id="rule-effect-unknown-label"></a>`effect.unknown-label` | An effect declaration names a label the registry does not know — a typo in an envelope (`%a{rigor:v1:effect io.bd}`), or a member of `effects.tolerated:`. The whole tag then reads as unbounded, so the declaration quietly stops doing anything; this says so. Positioned at the declaration: the `.rbs` line, the `.rb` line for an rbs-inline annotation, or `.rigor.yml` for a config value. `# rigor:disable` comments are not read out of `.rbs` or `.rigor.yml`, so use `disable:` or the baseline there. Only fires where the spelling is evidently meant to be a label (close to a known one, next to a known one, dotted, or retired) — a word nothing resembles stays silent, because you may be opening your own vocabulary. Needs an `effects:` block. | high |
|
|
77
80
|
| <a id="rule-effect-annotations-unchecked"></a>`effect.annotations-unchecked` | Your signatures carry `%a{pure}` / `%a{rigor:v1:effect …}` but `.rigor.yml` has no `effects:` block, so nothing checks them. One `:info` per run, positioned at the first annotation. An annotation never turns effect collection on by itself — that would make one line in one file more expensive for every run — so this is how it tells you instead. Add `effects: {}` to opt in, or `disable:` it to keep the annotations documentary. Reads both annotation lanes — `sig/*.rbs` and rbs-inline comments — on every run, a warm `--incremental` with nothing changed included. | — |
|
|
81
|
+
| <a id="rule-rbs-contradicting-signature"></a>`rbs.contradicting-signature` | A method is declared both in your `sig/` and by an inline `# @rbs` / `#:` annotation, and the two provably contradict — no value or call satisfies both: in the return or a parameter every call must pass, the two types share no value (`::String` against `::Integer`). Only absolutely written Ruby core or stdlib classes count: a module such as `Comparable`, a class your project declares, a gem's class, or a relative name like plain `String` never does, or two keyword-free declarations accept positional counts that cannot meet, or one requires a keyword the other cannot take in any form. Overloads are paired by correspondence, not order. Also fires when a member-level `%a{rigor:v1:return: …}` / `%a{rigor:v1:param: …}` refinement shares no value with the type its own member declares. Positioned at the `.rbs` member; Rigor reads that declaration. A stale generated signature is the usual cause: regenerate it, or fix the annotation. Two declarations where one refines the other merge to the more precise one without a word, and a pair Rigor cannot rank drops the inline side with a `source-rbs-annotation-not-honoured` `:info` instead ([Precedence](plugins/rigor-rbs-inline.md#precedence)). An error in every profile. | high |
|
|
78
82
|
| <a id="rule-suppression-unknown-rule"></a>`suppression.unknown-rule` | A `# rigor:disable[-file]` comment names a rule that does not exist (typically a typo), so the suppression silently does nothing. `plugin.`-prefixed tokens are never flagged. | high |
|
|
79
83
|
| <a id="rule-suppression-empty"></a>`suppression.empty` | A `# rigor:disable[-file]` comment lists no rules, so it suppresses nothing. | high |
|
|
80
84
|
| <a id="rule-suppression-unknown-marker"></a>`suppression.unknown-marker` | A comment uses a suppression marker Rigor does not recognise — typically the RuboCop reflex `# rigor:disable-next-line <rule>` or `# rigor:enable <rule>`. Rigor's only markers are `# rigor:disable <rules>` (suppresses on its own line) and `# rigor:disable-file <rules>`, so the comment suppresses nothing. | high |
|
data/docs/manual/07-plugins.md
CHANGED
|
@@ -95,7 +95,7 @@ with the `plugins_isolation:` configuration key or the
|
|
|
95
95
|
| --- | --- |
|
|
96
96
|
| `process` (default) | Run the call in a forked, crash-contained worker, so the target library's monkey-patches and any crash never contaminate Rigor. Falls back to `none` where `fork` is unavailable (Windows / JRuby). |
|
|
97
97
|
| `none` | Load the library into Rigor's own process and call it directly. |
|
|
98
|
-
| `ruby_box` | Run inside an experimental `Ruby::Box` sandbox. This needs the `RUBY_BOX=1` start flag, so the `rigor` launcher re-execs itself with it set when you select this strategy. **Environment variable only** — the configuration file is read long after Ruby has booted, so `plugins_isolation: ruby_box` is reported as a configuration error instead. |
|
|
98
|
+
| `ruby_box` | Run inside an experimental `Ruby::Box` sandbox. This needs the `RUBY_BOX=1` start flag, so the `rigor` launcher re-execs itself with it set when you select this strategy. It also needs a Ruby that fixes [Ruby Bug #22260](https://bugs.ruby-lang.org/issues/22260), which no release up to 4.0.7 does. The launcher checks for the fix first, and without it prints a warning and uses the configured strategy instead. **Environment variable only** — the configuration file is read long after Ruby has booted, so `plugins_isolation: ruby_box` is reported as a configuration error instead. |
|
|
99
99
|
|
|
100
100
|
The environment variable wins over `plugins_isolation:`, so you can
|
|
101
101
|
override a project's committed choice for one invocation. The legacy
|
data/docs/manual/08-skills.md
CHANGED
|
@@ -60,9 +60,10 @@ is not repeated here.)
|
|
|
60
60
|
- **`rigor-project-init`** — onboards a project from a cold start. It
|
|
61
61
|
detects the stack (Rails, RSpec, dry-rb, …), proposes the matching
|
|
62
62
|
[plugins](07-plugins.md), picks an adoption mode — a
|
|
63
|
-
[baseline](06-baseline.md) snapshot
|
|
64
|
-
zero-diagnostic gate for
|
|
65
|
-
|
|
63
|
+
[baseline](06-baseline.md) snapshot by default, new projects
|
|
64
|
+
included, or an opt-in zero-diagnostic gate for users fluent in type
|
|
65
|
+
theory and RBS — writes a `.rigor.dist.yml`, and generates the first
|
|
66
|
+
baseline. Reach for it when setting Rigor up for
|
|
66
67
|
the first time.
|
|
67
68
|
- **`rigor-rbs-setup`** — installs community RBS for your gems
|
|
68
69
|
(`rbs collection install`) so RBS-less dependencies stop typing as
|
|
@@ -358,8 +358,9 @@ Generate RBS skeleton signatures inferred from Ruby source files.
|
|
|
358
358
|
| `params` | `"untyped"` \| `"observed"` | no | `"untyped"` |
|
|
359
359
|
| `config` | `string` | no | session default |
|
|
360
360
|
|
|
361
|
-
`params: "observed"` harvests call-site argument types from
|
|
362
|
-
|
|
361
|
+
`params: "observed"` harvests call-site argument types from the
|
|
362
|
+
project's test roots: the configured `test_paths:`, or whichever of
|
|
363
|
+
`spec/` and `test/` exist.
|
|
363
364
|
|
|
364
365
|
**Returns:** JSON — the same as `rigor sig-gen --print --format json`.
|
|
365
366
|
|
data/docs/manual/12-caching.md
CHANGED
|
@@ -135,7 +135,7 @@ CI detection that `auto` relies on.
|
|
|
135
135
|
|
|
136
136
|
| Flag | Effect |
|
|
137
137
|
| --- | --- |
|
|
138
|
-
| `rigor check --no-cache` | Run without reading or writing the persistent cache. |
|
|
138
|
+
| `rigor check --no-cache` | Run without reading or writing the persistent cache. With `--incremental` this includes the snapshot: every file is analysed and the snapshot on disk is left untouched. |
|
|
139
139
|
| `rigor check --clear-cache` | Delete the cache directory, then run. |
|
|
140
140
|
| `rigor check --cache-stats` | Print the on-disk cache inventory when the run finishes (on stderr under every `--format` but `text`, so the document on stdout stays parseable). |
|
|
141
141
|
| `rigor check --incremental` | Re-analyse only what changed; serve the rest from the incremental snapshot (see below). |
|
|
@@ -144,9 +144,12 @@ There is no config key to disable caching permanently — the
|
|
|
144
144
|
flags are per-run toggles. To run without a persistent cache
|
|
145
145
|
habitually, point `cache.path` at a disposable directory.
|
|
146
146
|
|
|
147
|
+
With `--incremental --no-cache` and an editor buffer (`--tmp-file` with `--instead-of`), the buffer is analysed on its own, as it is when no snapshot exists, and the note says that `--no-cache` skipped the snapshot rather than suggesting `rigor check --incremental`.
|
|
148
|
+
|
|
147
149
|
## Size and eviction
|
|
148
150
|
|
|
149
|
-
A project's active cache set is
|
|
151
|
+
A project's active cache set is a few megabytes (about 10 MB
|
|
152
|
+
for a Rails application the size of Mastodon). Entries
|
|
150
153
|
are content-keyed, so events like a gem upgrade or an `.rbs`
|
|
151
154
|
edit write fresh entries and leave the old ones *orphaned* —
|
|
152
155
|
nothing references them, and no run would otherwise delete
|
|
@@ -219,9 +222,45 @@ dependents of removed ones.) As with the rest of the cache, a
|
|
|
219
222
|
missing or corrupt snapshot is simply a full run; it can never
|
|
220
223
|
wedge analysis.
|
|
221
224
|
|
|
225
|
+
When nothing has changed since the last `--incremental` run, the
|
|
226
|
+
answer comes straight from the cache, without starting the
|
|
227
|
+
analyzer at all. Rigor first checks the inputs that answer was
|
|
228
|
+
computed from — your source files and view templates, your RBS,
|
|
229
|
+
your configuration and the files your plugins read — and runs the
|
|
230
|
+
ordinary incremental re-check the moment any of them differs. On
|
|
231
|
+
a Rails application the size of Mastodon, an unchanged
|
|
232
|
+
`--incremental` run takes about a quarter of a second. An
|
|
233
|
+
unchanged plain `rigor check` skips the analyzer the same way,
|
|
234
|
+
except when a plugin compiles your view templates, as
|
|
235
|
+
rigor-actionpack does.
|
|
236
|
+
|
|
237
|
+
The shortcut stands aside under `--workers=N` (or
|
|
238
|
+
`parallel.workers:`), `--explain`, `--cache-stats`, `--coverage`,
|
|
239
|
+
an editor buffer, and an `effects:` block, and when the cache
|
|
240
|
+
directory is on a different filesystem from the project; those
|
|
241
|
+
runs re-check as before. It also switches itself off, silently:
|
|
242
|
+
|
|
243
|
+
- when an input changes that the ordinary re-check does not look
|
|
244
|
+
at itself: an auto-detected `sig/` directory (one you did not
|
|
245
|
+
list under `signature_paths:`), a file a narrower
|
|
246
|
+
`rigor check --incremental DIR` only discovers from the rest of
|
|
247
|
+
your configured `paths:`, or a `pre_eval:` file outside the
|
|
248
|
+
analysed paths. The re-check may keep printing the answer from
|
|
249
|
+
before that change; the shortcut does not repeat it;
|
|
250
|
+
- when an `--incremental` run cannot record its answer safely:
|
|
251
|
+
after a run with `--workers=N` that re-analysed files, when a file or directory changes while a run is reading
|
|
252
|
+
it, after a CI cache is restored onto a fresh checkout, or when
|
|
253
|
+
two runs race.
|
|
254
|
+
|
|
255
|
+
Either way it stays off, and every run is an ordinary re-check,
|
|
256
|
+
until the next full analysis. The ordinary re-check never starts
|
|
257
|
+
one by itself: only a configuration, `Gemfile.lock` or Rigor
|
|
258
|
+
version change does, or `--clear-cache`. So the shortcut can stay
|
|
259
|
+
off indefinitely; run `rigor check --incremental --clear-cache`
|
|
260
|
+
once to turn it back on.
|
|
261
|
+
|
|
222
262
|
`--incremental` is most useful for fast local re-checks and CI
|
|
223
|
-
on a changed branch.
|
|
224
|
-
the ordinary cache already serves the whole result in one step.
|
|
263
|
+
on a changed branch.
|
|
225
264
|
|
|
226
265
|
## Concurrency
|
|
227
266
|
|
|
@@ -90,8 +90,9 @@ It runs eight phases in order:
|
|
|
90
90
|
2. **Choose an adoption mode** — proposes either *acknowledge*
|
|
91
91
|
(snapshot today's diagnostics into a baseline; catch
|
|
92
92
|
regressions going forward) or *strict* (drive the project to
|
|
93
|
-
zero and keep it there). It recommends acknowledge for
|
|
94
|
-
|
|
93
|
+
zero and keep it there). It recommends acknowledge for every
|
|
94
|
+
project, new ones included; strict is an opt-in for users
|
|
95
|
+
fluent in type theory and RBS.
|
|
95
96
|
3. **Select plugins** — proposes the plugin set matching your
|
|
96
97
|
detected stack; you confirm or trim the list.
|
|
97
98
|
4. **Write `.rigor.dist.yml`** — the committed shared config,
|
|
@@ -151,14 +152,19 @@ source-of-truth copy is
|
|
|
151
152
|
|
|
152
153
|
| Mode | When | What happens |
|
|
153
154
|
| --- | --- | --- |
|
|
154
|
-
| **Acknowledge** |
|
|
155
|
-
| **Strict** |
|
|
155
|
+
| **Acknowledge** | Recommended for every project, new ones included | Record today's diagnostics in a baseline; surface only new ones on each PR. |
|
|
156
|
+
| **Strict** | Opt-in, for users fluent in type theory and RBS | Zero outstanding diagnostics; no baseline. |
|
|
156
157
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
Start with acknowledge mode even on a brand-new project. Rigor's
|
|
159
|
+
inference still has gaps, so a zero-diagnostic gate meets
|
|
160
|
+
diagnostics on correct code, and clearing those means fixing
|
|
161
|
+
signatures or RBS rather than your code. Choose strict only if
|
|
162
|
+
you are comfortable doing that yourself. You can tighten later.
|
|
163
|
+
|
|
164
|
+
In `.rigor.dist.yml` (Step 3) the mode maps to a
|
|
165
|
+
`severity_profile:`. Acknowledge mode uses the default `balanced`
|
|
166
|
+
(omit the key), or `lenient` when the first `rigor check` reports
|
|
167
|
+
more than ~100 diagnostics; strict mode uses `strict`.
|
|
162
168
|
|
|
163
169
|
### Step 3 — Write .rigor.dist.yml
|
|
164
170
|
|
|
@@ -198,7 +204,7 @@ plugins:
|
|
|
198
204
|
- rigor-rspec
|
|
199
205
|
- rigor-factorybot
|
|
200
206
|
|
|
201
|
-
severity_profile: lenient # "strict" for strict mode
|
|
207
|
+
# severity_profile: lenient # only for >100 initial diagnostics; "strict" for strict mode
|
|
202
208
|
|
|
203
209
|
# baseline: .rigor-baseline.yml # uncomment after Step 6 (acknowledge mode only)
|
|
204
210
|
```
|
|
@@ -288,7 +294,9 @@ first, then large clusters to record in a baseline.
|
|
|
288
294
|
|
|
289
295
|
### Step 6 — Generate a baseline (acknowledge mode)
|
|
290
296
|
|
|
291
|
-
*Skip this step if you chose strict mode.*
|
|
297
|
+
*Skip this step if you chose strict mode.* Settle `severity_profile:`
|
|
298
|
+
first: changing it afterwards changes which rules fire and leaves the
|
|
299
|
+
baseline out of step.
|
|
292
300
|
|
|
293
301
|
```sh
|
|
294
302
|
rigor baseline generate
|
|
@@ -22,25 +22,56 @@ The plain `() -> String` stays the compatibility contract; the
|
|
|
22
22
|
annotation tells Rigor the return is a non-empty string.
|
|
23
23
|
|
|
24
24
|
You may also write any of them **in a `.rb` file**, as an
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
inline-RBS comment — `%a{}` is RBS's own annotation grammar, and
|
|
26
|
+
the annotation reaches Rigor on the same path the generated
|
|
27
|
+
signature does. Rigor reads three spellings:
|
|
28
28
|
|
|
29
29
|
```rb
|
|
30
30
|
# rbs_inline: enabled
|
|
31
31
|
|
|
32
32
|
class Reader
|
|
33
|
+
# Own line: the annotation, then the type on its own tag.
|
|
33
34
|
# @rbs %a{rigor:v1:return: non-empty-string}
|
|
34
35
|
# @rbs return: String
|
|
35
36
|
def read_name = "x"
|
|
37
|
+
|
|
38
|
+
# Same line, `@rbs` method type.
|
|
39
|
+
# @rbs %a{rigor:v1:return: non-empty-string} () -> String
|
|
40
|
+
def title = "x"
|
|
41
|
+
|
|
42
|
+
# Same line, `#:` method type.
|
|
43
|
+
#: %a{rigor:v1:return: non-empty-string} () -> String
|
|
44
|
+
def label = "x"
|
|
36
45
|
end
|
|
37
46
|
```
|
|
38
47
|
|
|
48
|
+
Several annotations may stand before the method type
|
|
49
|
+
(`#: %a{pure} %a{rigor:v1:return: non-empty-string} () -> String`).
|
|
50
|
+
The other inline-RBS readers do not accept all three:
|
|
51
|
+
|
|
52
|
+
| spelling | rbs's built-in inline parser, Steep with `inline: true` | the `rbs-inline` gem's own `--output` |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| own line | syntax error (`expected a token pARROW`), annotation lost | annotation kept |
|
|
55
|
+
| same line | annotation and method type kept | annotation kept, method type **dropped** |
|
|
56
|
+
|
|
57
|
+
Rigor keeps both halves of every row. If you also run Steep in
|
|
58
|
+
inline mode, use the same-line spelling. The measurement is in
|
|
59
|
+
[ADR-111](../adr/111-inline-refinement-carrier.md). If the method type after a same-line annotation
|
|
60
|
+
does not parse, the method is left untyped and Rigor reports it as
|
|
61
|
+
[`plugin.rbs-inline.source-rbs-annotation-not-honoured`](plugins/rigor-rbs-inline.md#same-line-annotations).
|
|
62
|
+
|
|
39
63
|
This needs the `rbs-inline` library installed; Rigor ingests
|
|
40
64
|
inline annotations by default when it is
|
|
41
|
-
([ADR-93](../adr/93-default-rbs-inline-ingestion.md)).
|
|
42
|
-
|
|
43
|
-
|
|
65
|
+
([ADR-93](../adr/93-default-rbs-inline-ingestion.md)). `# rigor:`
|
|
66
|
+
comments remain suppression-only.
|
|
67
|
+
|
|
68
|
+
A dedicated `# @extrbs` comment for what RBS cannot spell is
|
|
69
|
+
accepted in [ADR-112](../adr/112-extrbs-comment-channel.md) but
|
|
70
|
+
not implemented yet ([#1073](https://github.com/rigortype/rigor/issues/1073)).
|
|
71
|
+
Until it ships, the `%a{}` forms above are the inline route. A type
|
|
72
|
+
plain RBS can spell, such as `:asc | :desc`, belongs in `# @rbs` or
|
|
73
|
+
`#:` either way.
|
|
74
|
+
|
|
44
75
|
This page is the *operational* reference — the directives you can
|
|
45
76
|
write and their syntax. For the normative rules (conflict
|
|
46
77
|
handling, merging, provenance) see
|
|
@@ -183,7 +214,9 @@ class UserRepository
|
|
|
183
214
|
end
|
|
184
215
|
```
|
|
185
216
|
|
|
186
|
-
The same two work as rbs-inline comments in a `.rb` file
|
|
217
|
+
The same two work as rbs-inline comments in a `.rb` file, in any of
|
|
218
|
+
the three spellings shown above — the own-line
|
|
219
|
+
one here:
|
|
187
220
|
|
|
188
221
|
```rb
|
|
189
222
|
# rbs_inline: enabled
|
|
@@ -214,6 +214,16 @@ rigor effects --pure
|
|
|
214
214
|
436 methods on Redmine, and they are your `%a{pure}` candidates — the on-ramp to
|
|
215
215
|
the last section of this chapter.
|
|
216
216
|
|
|
217
|
+
You do not have to write them all out by hand. With the `effects:` block in
|
|
218
|
+
place, `rigor sig-gen` annotates the methods in this set whose signature it is
|
|
219
|
+
proposing anyway: `%a{pure}` above every method that is exhaustive, undischarged,
|
|
220
|
+
free of surviving `≤` labels, not already carrying a bound you wrote, and calling
|
|
221
|
+
nothing the analyzer had no description for; and, under `--effect-envelopes`, the labelled spelling for the methods that
|
|
222
|
+
do have a footprint. A method that is clean only because `effects.tolerated:`
|
|
223
|
+
says so is deliberately left bare — the annotation would travel to readers who
|
|
224
|
+
do not share your tolerated list. See
|
|
225
|
+
[handbook chapter 11](../handbook/11-sig-gen.md#emitting-effect-annotations).
|
|
226
|
+
|
|
217
227
|
### Asking it a question
|
|
218
228
|
|
|
219
229
|
**By label.** The question this chapter opens with, in one command:
|
|
@@ -54,6 +54,9 @@ The full catalogue, with a one-line scope for every plugin, is
|
|
|
54
54
|
`Result` / `Option` unwrap types and synthesises `Enum` variants.
|
|
55
55
|
- [rigor-pundit](rigor-pundit.md) — policy-class existence and
|
|
56
56
|
`authorize(record, :action)` predicate validation.
|
|
57
|
+
- [rigor-active-model-serializers](rigor-active-model-serializers.md) —
|
|
58
|
+
types the `object` reader inside a serializer as the serializer's
|
|
59
|
+
model (no diagnostics).
|
|
57
60
|
- [rigor-sidekiq](rigor-sidekiq.md) — Sidekiq `Worker.perform_*`
|
|
58
61
|
argument arity against the discovered `#perform`.
|
|
59
62
|
- [rigor-actioncable](rigor-actioncable.md) — `broadcast_to` channel
|
|
@@ -62,6 +65,10 @@ The full catalogue, with a one-line scope for every plugin, is
|
|
|
62
65
|
through Minitest / Test::Unit assertions and spec matchers.
|
|
63
66
|
- [rigor-graphql](rigor-graphql.md) — GraphQL-Ruby type / enum / input
|
|
64
67
|
/ mutation table publication (cross-plugin facts, no diagnostics).
|
|
68
|
+
- [rigor-grape](rigor-grape.md) — types the `Grape::API` endpoint DSL
|
|
69
|
+
(`params`, `namespace`, verb macros, `desc`, `route_setting`) and
|
|
70
|
+
`Grape::Entity` `expose` declarations, including the `instance_eval`'d
|
|
71
|
+
block `self` bindings.
|
|
65
72
|
- [rigor-rspec-rails](rigor-rspec-rails.md) — `have_http_status`
|
|
66
73
|
argument validation (out-of-range codes, unknown status symbols).
|
|
67
74
|
- [rigor-shoulda-matchers](rigor-shoulda-matchers.md) — shoulda matcher
|