rigortype 0.4.0 → 0.4.2
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 +4 -3
- data/data/builtins/ruby_core/io.yml +1 -0
- data/data/builtins/ruby_core/proc.yml +4 -0
- data/data/builtins/ruby_core/random.yml +4 -0
- data/data/builtins/ruby_core/struct.yml +3 -0
- data/data/core_overlay/env.rbs +34 -0
- data/data/core_overlay/gc.rbs +50 -0
- data/data/core_overlay/hash.rbs +45 -0
- data/data/core_overlay/integer.rbs +31 -0
- data/data/core_overlay/io_buffer.rbs +27 -0
- data/data/core_overlay/kernel.rbs +40 -0
- data/data/core_overlay/match_data.rbs +28 -0
- data/data/core_overlay/module.rbs +51 -0
- data/data/core_overlay/object_space.rbs +29 -0
- data/data/core_overlay/proc.rbs +45 -0
- data/data/core_overlay/range.rbs +40 -0
- data/data/core_overlay/source_range.rbs +78 -0
- data/data/core_overlay/string.rbs +86 -0
- data/data/vendored_gem_sigs/prime/integer-extension.rbs +41 -0
- data/data/vendored_gem_sigs/prime/prime.rbs +372 -0
- data/docs/handbook/01-getting-started.md +3 -3
- data/docs/handbook/06-classes.md +3 -1
- data/docs/handbook/08-understanding-errors.md +3 -2
- data/docs/handbook/11-sig-gen.md +6 -0
- data/docs/handbook/appendix-liskov.md +5 -0
- data/docs/install.md +87 -15
- data/docs/manual/02-cli-reference.md +2 -2
- data/docs/manual/03-configuration.md +6 -1
- data/docs/manual/04-diagnostics.md +2 -1
- data/docs/manual/06-baseline.md +2 -0
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/08-skills.md +4 -3
- data/docs/manual/12-caching.md +43 -4
- data/docs/manual/14-rails-quickstart.md +19 -11
- data/docs/manual/18-removing-dead-code.md +32 -2
- data/docs/manual/plugins/README.md +6 -1
- data/docs/manual/plugins/rigor-activerecord.md +21 -0
- data/docs/manual/plugins/rigor-alba.md +60 -0
- data/docs/manual/plugins/rigor-minitest.md +22 -4
- data/docs/manual/plugins/rigor-typelizer.md +71 -0
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +27 -3
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +21 -92
- data/lib/rigor/analysis/check_rules/ruby_deprecations.rb +275 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +4 -0
- data/lib/rigor/analysis/check_rules/source_arity.rb +184 -61
- data/lib/rigor/analysis/check_rules.rb +407 -144
- data/lib/rigor/analysis/dependency_recorder.rb +215 -18
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +8 -1
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +21 -0
- data/lib/rigor/analysis/dependency_source_inference/index.rb +36 -11
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +196 -27
- data/lib/rigor/analysis/erb_template_detector.rb +2 -1
- data/lib/rigor/analysis/incremental.rb +29 -9
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +291 -0
- data/lib/rigor/analysis/incremental_run_slot.rb +173 -0
- data/lib/rigor/analysis/incremental_session.rb +287 -50
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +24 -13
- data/lib/rigor/analysis/reachability/graph.rb +123 -23
- data/lib/rigor/analysis/reachability/scan.rb +290 -36
- data/lib/rigor/analysis/reachability/scan_cache.rb +2 -1
- data/lib/rigor/analysis/rule_catalog.rb +43 -0
- data/lib/rigor/analysis/run_cache_key.rb +43 -9
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +88 -6
- data/lib/rigor/analysis/runner/pool_coordinator.rb +52 -13
- data/lib/rigor/analysis/runner/project_pre_passes.rb +21 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +371 -49
- 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_paths.rb +6 -4
- data/lib/rigor/analysis/template_units.rb +15 -5
- data/lib/rigor/analysis/worker_session.rb +11 -7
- data/lib/rigor/cache/descriptor.rb +40 -1
- data/lib/rigor/cache/file_digest.rb +28 -0
- data/lib/rigor/cache/incremental_snapshot.rb +92 -8
- data/lib/rigor/cache/store.rb +63 -3
- data/lib/rigor/cache/value_digest.rb +325 -0
- data/lib/rigor/cli/annotate_command.rb +5 -0
- data/lib/rigor/cli/baseline_command.rb +7 -18
- data/lib/rigor/cli/check_command.rb +85 -14
- data/lib/rigor/cli/doctor_command.rb +1 -1
- data/lib/rigor/cli/effects_report.rb +2 -2
- data/lib/rigor/cli/trace_command.rb +5 -0
- data/lib/rigor/cli/type_of_command.rb +5 -3
- data/lib/rigor/cli/unused_command.rb +16 -10
- data/lib/rigor/cli.rb +11 -3
- data/lib/rigor/config_audit.rb +3 -2
- data/lib/rigor/config_path.rb +29 -0
- data/lib/rigor/configuration/severity_profile.rb +11 -0
- data/lib/rigor/configuration.rb +52 -7
- data/lib/rigor/effects/plugin_facts.rb +6 -6
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -3
- data/lib/rigor/environment/gated_signature_guard.rb +43 -0
- data/lib/rigor/environment/gated_signature_plan.rb +339 -0
- data/lib/rigor/environment/lockfile_resolver.rb +10 -1
- data/lib/rigor/environment/rbs_collection_discovery.rb +10 -1
- data/lib/rigor/environment/rbs_coverage_report.rb +1 -1
- data/lib/rigor/environment/rbs_loader.rb +284 -15
- data/lib/rigor/environment/required_features.rb +206 -0
- data/lib/rigor/environment/source_rbs_synthesis.rb +147 -0
- data/lib/rigor/environment.rb +34 -73
- data/lib/rigor/inference/acceptance.rb +28 -3
- data/lib/rigor/inference/block_parameter_binder.rb +29 -13
- data/lib/rigor/inference/builtins/cruby_definers.rb +61 -0
- data/lib/rigor/inference/builtins/method_catalog.rb +3 -0
- data/lib/rigor/inference/captured_locals.rb +7 -1
- 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 +26 -3
- data/lib/rigor/inference/definer_resolution.rb +266 -0
- data/lib/rigor/inference/expression_typer.rb +351 -61
- data/lib/rigor/inference/external_ancestor_resolution.rb +13 -16
- data/lib/rigor/inference/global_write_census.rb +7 -4
- data/lib/rigor/inference/guard_rebinding.rb +54 -13
- data/lib/rigor/inference/in_effect_refinements/proc_literals.rb +83 -0
- data/lib/rigor/inference/in_effect_refinements/refine_defs.rb +54 -0
- data/lib/rigor/inference/in_effect_refinements/scope_reads.rb +282 -0
- data/lib/rigor/inference/in_effect_refinements/walk.rb +276 -0
- data/lib/rigor/inference/in_effect_refinements.rb +256 -0
- data/lib/rigor/inference/key_presence_guard/scan.rb +281 -0
- data/lib/rigor/inference/key_presence_guard.rb +303 -0
- data/lib/rigor/inference/macro_block_self_type.rb +73 -14
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/arithmetic_sequence_elements.rb +73 -0
- data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +68 -0
- data/lib/rigor/inference/method_dispatcher/integer_step_block_params.rb +81 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -0
- data/lib/rigor/inference/method_dispatcher/keyword_arguments.rb +267 -0
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -1
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +122 -105
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +305 -54
- data/lib/rigor/inference/method_dispatcher/splat_arity.rb +71 -0
- data/lib/rigor/inference/method_dispatcher.rb +44 -11
- data/lib/rigor/inference/module_function_state.rb +214 -0
- data/lib/rigor/inference/multi_target_binder.rb +21 -16
- data/lib/rigor/inference/narrowing.rb +166 -22
- data/lib/rigor/inference/object_mixins.rb +180 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +10 -9
- data/lib/rigor/inference/project_patched_methods.rb +10 -5
- data/lib/rigor/inference/project_patched_scanner.rb +71 -3
- data/lib/rigor/inference/refine_census.rb +239 -0
- data/lib/rigor/inference/refine_self.rb +317 -0
- data/lib/rigor/inference/refined_dispatch/own_method.rb +403 -0
- data/lib/rigor/inference/refined_dispatch.rb +272 -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 +143 -0
- data/lib/rigor/inference/scope_indexer/superclasses_collector.rb +64 -0
- data/lib/rigor/inference/scope_indexer.rb +2129 -354
- data/lib/rigor/inference/singleton_hook_decline.rb +253 -0
- data/lib/rigor/inference/statement_evaluator.rb +149 -32
- data/lib/rigor/inference/string_mutation.rb +9 -3
- data/lib/rigor/inference/synthetic_method_scanner.rb +2 -1
- data/lib/rigor/inference/version_guard.rb +19 -10
- data/lib/rigor/language_server/project_context.rb +31 -0
- data/lib/rigor/language_server/server.rb +18 -0
- data/lib/rigor/plugin/base.rb +28 -8
- data/lib/rigor/plugin/inflector.rb +1 -1
- data/lib/rigor/plugin/io_boundary.rb +124 -7
- data/lib/rigor/plugin/isolation.rb +1 -1
- data/lib/rigor/plugin/macro/block_as_method.rb +51 -8
- data/lib/rigor/plugin/trust_policy.rb +3 -3
- data/lib/rigor/project_environment.rb +29 -6
- data/lib/rigor/protection/discovery_seed.rb +18 -9
- data/lib/rigor/protection/mutation_cache.rb +4 -4
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/reflection/constant_ancestors.rb +211 -46
- data/lib/rigor/reflection/constant_path.rb +33 -7
- data/lib/rigor/reflection.rb +41 -10
- data/lib/rigor/scope/discovery_index.rb +258 -3
- data/lib/rigor/scope/resolution_chain/relevance.rb +165 -0
- data/lib/rigor/scope/resolution_chain.rb +1032 -0
- data/lib/rigor/scope.rb +480 -328
- data/lib/rigor/sig_gen/alias_index.rb +1 -1
- data/lib/rigor/sig_gen/classification.rb +4 -1
- data/lib/rigor/sig_gen/effect_annotation.rb +2 -2
- data/lib/rigor/sig_gen/generator.rb +77 -21
- data/lib/rigor/sig_gen/method_candidate.rb +2 -2
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +12 -0
- data/lib/rigor/source/alias_names.rb +52 -0
- data/lib/rigor/source/literals.rb +3 -2
- data/lib/rigor/source/symbol_name.rb +20 -0
- data/lib/rigor/type/combinator.rb +59 -3
- data/lib/rigor/type/float_range.rb +4 -1
- data/lib/rigor/type/nominal.rb +6 -1
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-ac-library-rb/lib/rigor/plugin/ac_library_rb.rb +28 -0
- data/plugins/rigor-ac-library-rb/lib/rigor-ac-library-rb.rb +3 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/convolution.rbs +7 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/data_structures.rbs +160 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/graph.rbs +94 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/math.rbs +42 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/modint.rbs +71 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/object.rbs +37 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/segtree.rbs +83 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +2 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +100 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +94 -10
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +43 -2
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +3 -1
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +149 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +74 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +104 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba.rb +85 -0
- data/plugins/rigor-alba/lib/rigor-alba.rb +3 -0
- data/plugins/rigor-alba/sig/alba.rbs +4 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +2 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/target_detector.rb +29 -12
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +13 -2
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +130 -21
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +6 -4
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +4 -4
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +31 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +102 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +87 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +76 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer.rb +73 -0
- data/plugins/rigor-typelizer/lib/rigor-typelizer.rb +3 -0
- data/sig/rigor/analysis/dependency_source_inference/index.rbs +1 -1
- data/sig/rigor/environment.rbs +2 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/scope.rbs +69 -4
- data/sig/rigor/source.rbs +4 -0
- data/sig/rigor.rbs +3 -1
- data/skills/rigor-project-init/SKILL.md +37 -11
- data/skills/rigor-project-init/references/02-configure.md +7 -2
- metadata +90 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
module AcLibraryRb
|
|
2
|
+
class DSU
|
|
3
|
+
attr_reader parent_or_size: Array[Integer]
|
|
4
|
+
attr_reader n: Integer
|
|
5
|
+
|
|
6
|
+
def initialize: (?Integer n) -> void
|
|
7
|
+
|
|
8
|
+
# The leader of the merged component.
|
|
9
|
+
def merge: (Integer a, Integer b) -> Integer
|
|
10
|
+
alias unite merge
|
|
11
|
+
|
|
12
|
+
def same?: (Integer a, Integer b) -> bool
|
|
13
|
+
alias same same?
|
|
14
|
+
|
|
15
|
+
def leader: (Integer a) -> Integer
|
|
16
|
+
alias root leader
|
|
17
|
+
alias find leader
|
|
18
|
+
|
|
19
|
+
# Like `leader`, growing the set to hold `a` when it is out of range.
|
|
20
|
+
def []: (Integer a) -> Integer
|
|
21
|
+
|
|
22
|
+
def size: (Integer a) -> Integer
|
|
23
|
+
|
|
24
|
+
def groups: () -> Array[Array[Integer]]
|
|
25
|
+
|
|
26
|
+
def to_s: () -> String
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class UnionFind = DSU
|
|
30
|
+
|
|
31
|
+
# Element values are whatever the caller adds: the tree starts from `0` and adds with `+`, so an
|
|
32
|
+
# `Integer`, a `Float` and a `ModInt` all work.
|
|
33
|
+
class FenwickTree
|
|
34
|
+
attr_reader data: Array[untyped]
|
|
35
|
+
attr_reader size: Integer
|
|
36
|
+
|
|
37
|
+
def initialize: (Array[untyped] | Integer arg) -> void
|
|
38
|
+
|
|
39
|
+
def add: (Integer i, untyped x) -> void
|
|
40
|
+
|
|
41
|
+
def sum: (Integer l, Integer r) -> untyped
|
|
42
|
+
| (Integer r) -> untyped
|
|
43
|
+
| (Range[Integer] range) -> untyped
|
|
44
|
+
|
|
45
|
+
def _sum: (Integer i) -> untyped
|
|
46
|
+
alias left_sum _sum
|
|
47
|
+
|
|
48
|
+
def to_s: () -> String
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# A binary heap that pops the highest-priority element first: the largest by default, or the first
|
|
52
|
+
# argument of the block when it returns truthy.
|
|
53
|
+
class PriorityQueue[T]
|
|
54
|
+
# The factories answer `PriorityQueue[untyped]`: bound from a literal array, `T` would be the literals it
|
|
55
|
+
# starts with, and a later `pop` would read as one of them.
|
|
56
|
+
def self.max: (Array[untyped] array) -> PriorityQueue[untyped]
|
|
57
|
+
|
|
58
|
+
def self.min: (Array[untyped] array) -> PriorityQueue[untyped]
|
|
59
|
+
|
|
60
|
+
def self.[]: (*untyped array) ?{ (untyped, untyped) -> boolish } -> PriorityQueue[untyped]
|
|
61
|
+
|
|
62
|
+
def initialize: (?Array[T] array) ?{ (T, T) -> boolish } -> void
|
|
63
|
+
|
|
64
|
+
attr_reader heap: Array[T]
|
|
65
|
+
alias to_a heap
|
|
66
|
+
|
|
67
|
+
def push: (T item) -> self
|
|
68
|
+
alias << push
|
|
69
|
+
alias append push
|
|
70
|
+
|
|
71
|
+
def pop: () -> T?
|
|
72
|
+
|
|
73
|
+
def get: () -> T?
|
|
74
|
+
alias top get
|
|
75
|
+
alias first get
|
|
76
|
+
|
|
77
|
+
def empty?: () -> bool
|
|
78
|
+
|
|
79
|
+
def size: () -> Integer
|
|
80
|
+
|
|
81
|
+
def to_s: () -> String
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class HeapQueue = PriorityQueue
|
|
85
|
+
|
|
86
|
+
class Deque[T]
|
|
87
|
+
include Enumerable[T]
|
|
88
|
+
|
|
89
|
+
def self.[]: (*untyped args) -> Deque[untyped]
|
|
90
|
+
|
|
91
|
+
def initialize: (?Array[T] arg, ?untyped value, ?initial_capacity: Integer) -> void
|
|
92
|
+
| (Integer size, ?T value, ?initial_capacity: Integer) -> void
|
|
93
|
+
|
|
94
|
+
def empty?: () -> bool
|
|
95
|
+
|
|
96
|
+
def size: () -> Integer
|
|
97
|
+
alias length size
|
|
98
|
+
|
|
99
|
+
def <<: (T x) -> self
|
|
100
|
+
|
|
101
|
+
def push: (*T args) -> self
|
|
102
|
+
alias append push
|
|
103
|
+
|
|
104
|
+
def unshift: (*T args) -> self
|
|
105
|
+
alias prepend unshift
|
|
106
|
+
|
|
107
|
+
def pop: () -> T?
|
|
108
|
+
|
|
109
|
+
def shift: () -> T?
|
|
110
|
+
|
|
111
|
+
def last: () -> T?
|
|
112
|
+
|
|
113
|
+
def slice: (Integer idx) -> T?
|
|
114
|
+
|
|
115
|
+
def []: (Integer idx) -> T?
|
|
116
|
+
| (Integer start, Integer length) -> Deque[T]?
|
|
117
|
+
| (Range[Integer] range) -> Deque[T]?
|
|
118
|
+
|
|
119
|
+
def at: (Integer idx) -> T?
|
|
120
|
+
|
|
121
|
+
def []=: (Integer idx, T value) -> T
|
|
122
|
+
|
|
123
|
+
def ==: (untyped other) -> bool
|
|
124
|
+
|
|
125
|
+
def hash: () -> Integer
|
|
126
|
+
|
|
127
|
+
def reverse: () -> Deque[T]
|
|
128
|
+
|
|
129
|
+
def reverse!: () -> self
|
|
130
|
+
|
|
131
|
+
def reversed?: () -> bool
|
|
132
|
+
|
|
133
|
+
def dig: (int idx, *untyped) -> untyped
|
|
134
|
+
|
|
135
|
+
def each: () { (T) -> void } -> Array[T]
|
|
136
|
+
| () -> Enumerator[T, Array[T]]
|
|
137
|
+
|
|
138
|
+
def clear: () -> self
|
|
139
|
+
|
|
140
|
+
def join: (?String? sep) -> String
|
|
141
|
+
|
|
142
|
+
def rotate!: (?Integer cnt) -> self
|
|
143
|
+
|
|
144
|
+
def rotate: (?Integer cnt) -> Deque[T]
|
|
145
|
+
|
|
146
|
+
def sample: () -> T?
|
|
147
|
+
|
|
148
|
+
def shuffle: () -> Deque[T]
|
|
149
|
+
|
|
150
|
+
def replace: (_ToA[T] other) -> self
|
|
151
|
+
|
|
152
|
+
def swap: (Integer i, Integer j) -> self
|
|
153
|
+
|
|
154
|
+
def to_a: () -> Array[T]
|
|
155
|
+
|
|
156
|
+
def to_s: () -> String
|
|
157
|
+
|
|
158
|
+
def inspect: () -> String
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module AcLibraryRb
|
|
2
|
+
class MaxFlow
|
|
3
|
+
def initialize: (Integer n) -> void
|
|
4
|
+
|
|
5
|
+
# The index of the added edge.
|
|
6
|
+
def add_edge: (Integer from, Integer to, Integer cap) -> Integer
|
|
7
|
+
|
|
8
|
+
def add_edges: (_Each[[Integer, Integer, Integer]] edges) -> self
|
|
9
|
+
|
|
10
|
+
def add: (Integer from, Integer to, Integer cap) -> Integer
|
|
11
|
+
| (_Each[[Integer, Integer, Integer]] edges) -> self
|
|
12
|
+
|
|
13
|
+
# `[from, to, cap]`, as `gets.split.map(&:to_i)` reads it.
|
|
14
|
+
def push: (Array[Integer] edge) -> Integer
|
|
15
|
+
alias << push
|
|
16
|
+
|
|
17
|
+
# `[from, to, cap, flow]` of the `i`-th edge.
|
|
18
|
+
def []: (Integer i) -> [Integer, Integer, Integer, Integer]
|
|
19
|
+
alias get_edge []
|
|
20
|
+
alias edge []
|
|
21
|
+
|
|
22
|
+
def edges: () -> Array[[Integer, Integer, Integer, Integer]]
|
|
23
|
+
|
|
24
|
+
def change_edge: (Integer i, Integer new_cap, Integer new_flow) -> void
|
|
25
|
+
|
|
26
|
+
# A `Float` limit the capacities do not bound comes back as the flow.
|
|
27
|
+
def flow: (Integer s, Integer t, ?Integer flow_limit) -> Integer
|
|
28
|
+
| (Integer s, Integer t, (Integer | Float) flow_limit) -> (Integer | Float)
|
|
29
|
+
alias max_flow flow
|
|
30
|
+
|
|
31
|
+
# Whether each vertex is reachable from `s` in the residual graph.
|
|
32
|
+
def min_cut: (Integer s) -> Array[bool]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class MinCostFlow
|
|
36
|
+
def initialize: (Integer n) -> void
|
|
37
|
+
|
|
38
|
+
# The index of the added edge.
|
|
39
|
+
def add_edge: (Integer from, Integer to, Integer cap, Integer cost) -> Integer
|
|
40
|
+
|
|
41
|
+
def add_edges: (_Each[[Integer, Integer, Integer, Integer]] edges) -> self
|
|
42
|
+
|
|
43
|
+
def add: (Integer from, Integer to, Integer cap, Integer cost) -> Integer
|
|
44
|
+
| (_Each[[Integer, Integer, Integer, Integer]] edges) -> self
|
|
45
|
+
|
|
46
|
+
# `[from, to, cap, flow, cost]` of the `i`-th edge.
|
|
47
|
+
def get_edge: (Integer i) -> [Integer, Integer, Integer, Integer, Integer]
|
|
48
|
+
alias edge get_edge
|
|
49
|
+
alias [] get_edge
|
|
50
|
+
|
|
51
|
+
def edges: () -> Array[[Integer, Integer, Integer, Integer, Integer]]
|
|
52
|
+
|
|
53
|
+
# `[flow, cost]`.
|
|
54
|
+
# The default limit is `Float::MAX`, which the capacities always bound; a smaller `Float` limit may not.
|
|
55
|
+
def flow: (Integer s, Integer t, ?Integer flow_limit) -> [Integer, Integer]
|
|
56
|
+
| (Integer s, Integer t, (Integer | Float) flow_limit) -> [Integer | Float, Integer | Float]
|
|
57
|
+
alias min_cost_max_flow flow
|
|
58
|
+
|
|
59
|
+
def dual_ref: (Integer s, Integer t) -> bool
|
|
60
|
+
|
|
61
|
+
# The `[flow, cost]` breakpoints of the cost curve.
|
|
62
|
+
def slope: (Integer s, Integer t, ?Integer flow_limit) -> Array[[Integer, Integer]]
|
|
63
|
+
| (Integer s, Integer t, (Integer | Float) flow_limit) -> Array[[Integer | Float, Integer | Float]]
|
|
64
|
+
alias min_cost_slop slope
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class SCC
|
|
68
|
+
def initialize: (Integer n) -> void
|
|
69
|
+
|
|
70
|
+
def add_edge: (Integer from, Integer to) -> self
|
|
71
|
+
|
|
72
|
+
def add_edges: (_Each[[Integer, Integer]] edges) -> self
|
|
73
|
+
|
|
74
|
+
def add: (Integer from, Integer to) -> self
|
|
75
|
+
| (_Each[[Integer, Integer]] edges) -> self
|
|
76
|
+
|
|
77
|
+
# The strongly connected components in topological order.
|
|
78
|
+
def scc: () -> Array[Array[Integer]]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class TwoSAT
|
|
82
|
+
def initialize: (Integer n) -> void
|
|
83
|
+
|
|
84
|
+
# One assignment per variable once `satisfiable?` has answered true; `nil` before that.
|
|
85
|
+
attr_reader answer: Array[bool?]
|
|
86
|
+
|
|
87
|
+
def add_clause: (Integer i, boolish f, Integer j, boolish g) -> nil
|
|
88
|
+
|
|
89
|
+
def satisfiable?: () -> bool
|
|
90
|
+
alias satisfiable satisfiable?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
class TwoSat = TwoSAT
|
|
94
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# ac-library-rb's math and string algorithms, instance methods of `AcLibraryRb` that a caller reaches by
|
|
2
|
+
# including the module.
|
|
3
|
+
module AcLibraryRb
|
|
4
|
+
# A callable taking two arguments: a `Proc`, a lambda or a `Method`.
|
|
5
|
+
interface _Call2[A, B, R]
|
|
6
|
+
def call: (A, B) -> R
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# An object `Deque#replace` can read elements from.
|
|
10
|
+
interface _ToA[T]
|
|
11
|
+
def to_a: () -> Array[T]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def convolution: (Array[Integer] a, Array[Integer] b, ?mod: Integer, ?k: Integer, ?z: Integer) -> Array[Integer]
|
|
15
|
+
|
|
16
|
+
# `[remainder, modulus]`, or `[0, 0]` when there is no solution.
|
|
17
|
+
def crt: (Array[Integer] r, Array[Integer] m) -> [Integer, Integer]
|
|
18
|
+
|
|
19
|
+
def inv_gcd: (Integer a, Integer b) -> [Integer, Integer]
|
|
20
|
+
|
|
21
|
+
def floor_sum: (Integer n, Integer m, Integer a, Integer b) -> Integer
|
|
22
|
+
|
|
23
|
+
def floor_sum_unsigned: (Integer n, Integer m, Integer a, Integer b) -> Integer
|
|
24
|
+
|
|
25
|
+
def inv_mod: (Integer x, Integer m) -> Integer
|
|
26
|
+
|
|
27
|
+
def _inv_gcd: (Integer a, Integer b) -> [Integer, Integer]
|
|
28
|
+
|
|
29
|
+
def pow_mod: (Integer x, Integer n, Integer m) -> Integer
|
|
30
|
+
|
|
31
|
+
def suffix_array: (String s) -> Array[Integer]
|
|
32
|
+
| (Array[untyped] a, ?Integer? upper) -> Array[Integer]
|
|
33
|
+
|
|
34
|
+
def sa_is: (Array[Integer] s, Integer upper) -> Array[Integer]
|
|
35
|
+
|
|
36
|
+
def sa_is_induce: (Array[Integer] s, Array[bool] ls, Array[Integer] sum_l, Array[Integer] sum_s,
|
|
37
|
+
Array[Integer] lms) -> Array[Integer]
|
|
38
|
+
|
|
39
|
+
def lcp_array: (String | Array[untyped] s, Array[Integer] sa) -> Array[Integer]
|
|
40
|
+
|
|
41
|
+
def z_algorithm: (String | Array[untyped] s) -> Array[Integer]
|
|
42
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module AcLibraryRb
|
|
2
|
+
# An integer modulo the global modulus set by `ModInt.set_mod`.
|
|
3
|
+
class ModInt < ::Numeric
|
|
4
|
+
def self.set_mod: (Integer mod) -> bool
|
|
5
|
+
|
|
6
|
+
def self.mod=: (Integer mod) -> bool
|
|
7
|
+
|
|
8
|
+
def self.mod: () -> Integer
|
|
9
|
+
|
|
10
|
+
def self.raw: (_ToI val) -> ModInt
|
|
11
|
+
|
|
12
|
+
def self.prime?: (Integer n) -> bool
|
|
13
|
+
|
|
14
|
+
def self.inv_gcd: (Integer a, Integer b) -> [Integer, Integer]
|
|
15
|
+
|
|
16
|
+
attr_accessor val: Integer
|
|
17
|
+
alias to_i val
|
|
18
|
+
|
|
19
|
+
def initialize: (?_ToI val) -> void
|
|
20
|
+
|
|
21
|
+
def inc!: () -> self
|
|
22
|
+
|
|
23
|
+
def dec!: () -> self
|
|
24
|
+
|
|
25
|
+
def add!: (_ToI other) -> self
|
|
26
|
+
|
|
27
|
+
def sub!: (_ToI other) -> self
|
|
28
|
+
|
|
29
|
+
def mul!: (_ToI other) -> self
|
|
30
|
+
|
|
31
|
+
def div!: (_ToI other) -> self
|
|
32
|
+
|
|
33
|
+
def +@: () -> self
|
|
34
|
+
|
|
35
|
+
def -@: () -> ModInt
|
|
36
|
+
|
|
37
|
+
# Answers the Integer `0` when the modulus is 1. Declared `ModInt` all the same: a union return reached
|
|
38
|
+
# `1 + m ** 2` as an argument, where overload selection reads a union whole (#1356), typed the sum `Integer`
|
|
39
|
+
# and reported `call.undefined-method` for `.val` on correct code.
|
|
40
|
+
def **: (Integer other) -> ModInt
|
|
41
|
+
alias pow **
|
|
42
|
+
|
|
43
|
+
def inv: () -> ModInt
|
|
44
|
+
|
|
45
|
+
def coerce: (_ToI other) -> [ModInt, ModInt]
|
|
46
|
+
|
|
47
|
+
def +: (_ToI other) -> ModInt
|
|
48
|
+
|
|
49
|
+
def -: (_ToI other) -> ModInt
|
|
50
|
+
|
|
51
|
+
def *: (_ToI other) -> ModInt
|
|
52
|
+
|
|
53
|
+
def /: (_ToI other) -> ModInt
|
|
54
|
+
|
|
55
|
+
def ==: (untyped other) -> bool
|
|
56
|
+
|
|
57
|
+
def pred: () -> ModInt
|
|
58
|
+
|
|
59
|
+
def succ: () -> ModInt
|
|
60
|
+
|
|
61
|
+
def zero?: () -> bool
|
|
62
|
+
|
|
63
|
+
def dup: () -> ModInt
|
|
64
|
+
|
|
65
|
+
def to_int: () -> Integer
|
|
66
|
+
|
|
67
|
+
def to_s: () -> String
|
|
68
|
+
|
|
69
|
+
def inspect: () -> String
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# The core extensions under `ac-library-rb/core_ext/`. `ac-library-rb/modint` loads the `ModInt` conversions;
|
|
2
|
+
# `Integer#divisors` and the `Array` conversions need `ac-library-rb/core_ext/all` (or `integer`).
|
|
3
|
+
class Object
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def ModInt: (_ToI val) -> AcLibraryRb::ModInt
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class Array[unchecked out Elem]
|
|
10
|
+
def to_fenwick_tree: () -> AcLibraryRb::FenwickTree
|
|
11
|
+
alias to_fetree to_fenwick_tree
|
|
12
|
+
|
|
13
|
+
# The element type is not carried over: a literal array would pin it to the literals it starts with.
|
|
14
|
+
def to_priority_queue: () -> AcLibraryRb::PriorityQueue[untyped]
|
|
15
|
+
alias to_pq to_priority_queue
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class Integer
|
|
19
|
+
# `ModInt#coerce` makes an Integer on the left answer a `ModInt`.
|
|
20
|
+
def +: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
|
|
21
|
+
def -: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
|
|
22
|
+
def *: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
|
|
23
|
+
def /: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
|
|
24
|
+
|
|
25
|
+
def divisors: () -> Array[Integer]
|
|
26
|
+
|
|
27
|
+
def each_divisor: () { (Integer) -> void } -> Array[Integer]
|
|
28
|
+
| () -> Enumerator[Integer, Array[Integer]]
|
|
29
|
+
|
|
30
|
+
def to_modint: () -> AcLibraryRb::ModInt
|
|
31
|
+
alias to_m to_modint
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class String
|
|
35
|
+
def to_modint: () -> AcLibraryRb::ModInt
|
|
36
|
+
alias to_m to_modint
|
|
37
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module AcLibraryRb
|
|
2
|
+
# A segment tree over the monoid `(S, op, e)`.
|
|
3
|
+
class Segtree[S]
|
|
4
|
+
attr_reader d: Array[S]
|
|
5
|
+
attr_reader op: _Call2[S, S, S]
|
|
6
|
+
attr_reader n: Integer
|
|
7
|
+
attr_reader leaf_size: Integer
|
|
8
|
+
attr_reader log: Integer
|
|
9
|
+
|
|
10
|
+
def initialize: (Array[S] | Integer v, S e) { (S, S) -> S } -> void
|
|
11
|
+
| (Array[S] | Integer v, _Call2[S, S, S] op, S e) -> void
|
|
12
|
+
|
|
13
|
+
def set: (Integer pos, S x) -> void
|
|
14
|
+
alias []= set
|
|
15
|
+
|
|
16
|
+
def get: (Integer pos) -> S
|
|
17
|
+
alias [] get
|
|
18
|
+
|
|
19
|
+
def prod: (Integer l, Integer r) -> S
|
|
20
|
+
| (Range[Integer] range) -> S
|
|
21
|
+
|
|
22
|
+
def all_prod: () -> S
|
|
23
|
+
|
|
24
|
+
def max_right: (Integer l) { (S) -> boolish } -> Integer
|
|
25
|
+
|
|
26
|
+
def min_left: (Integer r) { (S) -> boolish } -> Integer
|
|
27
|
+
|
|
28
|
+
def update: (Integer k) -> S
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class SegTree = Segtree
|
|
32
|
+
|
|
33
|
+
# A lazy segment tree over the monoid `(S, op, e)` acted on by the maps `(F, composition, id)`, where
|
|
34
|
+
# `mapping.call(f, x)` applies `f` to `x` and `composition.call(f, g)` is `f` after `g`.
|
|
35
|
+
class LazySegtree[S, F]
|
|
36
|
+
attr_reader d: Array[S]
|
|
37
|
+
attr_reader lz: Array[F]
|
|
38
|
+
attr_reader e: S
|
|
39
|
+
attr_reader id: F
|
|
40
|
+
attr_accessor op: _Call2[S, S, S]
|
|
41
|
+
attr_accessor mapping: _Call2[F, S, S]?
|
|
42
|
+
attr_accessor composition: _Call2[F, F, F]?
|
|
43
|
+
|
|
44
|
+
# The first form is chosen when the second argument is a `Proc`.
|
|
45
|
+
def initialize: (Array[S] | Integer v, ^(S, S) -> S op, S e, _Call2[F, S, S] mapping,
|
|
46
|
+
_Call2[F, F, F] composition, F id) -> void
|
|
47
|
+
| (Array[S] | Integer v, S e, F id, ?_Call2[S, S, S]? op, ?_Call2[F, S, S]? mapping,
|
|
48
|
+
?_Call2[F, F, F]? composition) ?{ (S, S) -> S } -> void
|
|
49
|
+
|
|
50
|
+
def set_mapping: () { (F, S) -> S } -> Proc
|
|
51
|
+
|
|
52
|
+
def set_composition: () { (F, F) -> F } -> Proc
|
|
53
|
+
|
|
54
|
+
def set: (Integer pos, S x) -> void
|
|
55
|
+
alias []= set
|
|
56
|
+
|
|
57
|
+
def get: (Integer pos) -> S
|
|
58
|
+
alias [] get
|
|
59
|
+
|
|
60
|
+
def prod: (Integer l, Integer r) -> S
|
|
61
|
+
| (Range[Integer] range) -> S
|
|
62
|
+
|
|
63
|
+
def all_prod: () -> S
|
|
64
|
+
|
|
65
|
+
def apply: (Integer pos, F f) -> void
|
|
66
|
+
| (Integer l, Integer r, F f) -> void
|
|
67
|
+
| (Range[Integer] range, F f) -> void
|
|
68
|
+
|
|
69
|
+
def range_apply: (Integer l, Integer r, F f) -> void
|
|
70
|
+
|
|
71
|
+
def max_right: (Integer l) { (S) -> boolish } -> Integer
|
|
72
|
+
|
|
73
|
+
def min_left: (Integer r) { (S) -> boolish } -> Integer
|
|
74
|
+
|
|
75
|
+
def update: (Integer k) -> S
|
|
76
|
+
|
|
77
|
+
def all_apply: (Integer k, F f) -> void
|
|
78
|
+
|
|
79
|
+
def push: (Integer k) -> void
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class LazySegTree = LazySegtree
|
|
83
|
+
end
|
|
@@ -309,8 +309,9 @@ module Rigor
|
|
|
309
309
|
args
|
|
310
310
|
end
|
|
311
311
|
|
|
312
|
+
# The name is interned later (`filter_name.to_sym`), so a name no Symbol can hold reads as nil.
|
|
312
313
|
def literal_symbol_or_string(node)
|
|
313
|
-
Rigor::Source::Literals.
|
|
314
|
+
Rigor::Source::Literals.symbol_or_string(node)&.to_s
|
|
314
315
|
end
|
|
315
316
|
|
|
316
317
|
def filter_lookup_violation(call_node, arg_node, filter_name, methods, spell_checker, ambiguous_filters:)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Plugin
|
|
5
|
+
class Activerecord < Rigor::Plugin::Base
|
|
6
|
+
# The model classes ActiveRecord loads BY NAME from an association (`belongs_to :user` → `User`), for
|
|
7
|
+
# `rigor unused` (ADR-102 WD3). The name is derived at runtime and never written in source, so a
|
|
8
|
+
# reference index sees a model reached only this way as unreferenced.
|
|
9
|
+
#
|
|
10
|
+
# The rows come from the {ModelIndex}'s association list, which {ModelDiscoverer} already extracts
|
|
11
|
+
# (class-body declarations and `with_options` groups only — not `class << self`, a `def` or another
|
|
12
|
+
# block). This module only resolves them, mirroring ActiveRecord:
|
|
13
|
+
#
|
|
14
|
+
# - `class_name:` (String or Symbol) wins; `"::Foo"` is rooted.
|
|
15
|
+
# - otherwise `has_many` / `has_and_belongs_to_many` → `name.singularize.camelize`, and
|
|
16
|
+
# `belongs_to` / `has_one` → `name.camelize` (`Reflection#derive_class_name`).
|
|
17
|
+
# - the name is tried as nested in the owner itself, then in each enclosing namespace innermost first,
|
|
18
|
+
# then at top level (`ActiveRecord::Inheritance#compute_type`).
|
|
19
|
+
# - a root is published only when the project declares a model of that name.
|
|
20
|
+
#
|
|
21
|
+
# Declined — no root, never a guess: a polymorphic association (no single target), a non-literal
|
|
22
|
+
# `class_name:` / `**opts`, `anonymous_class:`, a `with_options` group with non-literal options, and a
|
|
23
|
+
# `through:` association without a literal `class_name:` / `source_type:`. Without them a `through:` target is the SOURCE association's class on the through model, and
|
|
24
|
+
# that association (declared there, hence in this same index) roots it itself.
|
|
25
|
+
#
|
|
26
|
+
# A computed name equal to the owner's own demodulized name declines too (Rails 7.2+ tries `::Name`
|
|
27
|
+
# first; the target is then the owner itself or a top-level class).
|
|
28
|
+
#
|
|
29
|
+
# ActiveRecord takes the first candidate that is a defined constant. The index knows only models, so the
|
|
30
|
+
# walk stops (declines) at a candidate that is not a model but is a namespace of one: Rails would pick
|
|
31
|
+
# that module and fail, never the next candidate. A non-model class at an earlier candidate is invisible
|
|
32
|
+
# here.
|
|
33
|
+
#
|
|
34
|
+
# The roots are flat: an association on a model `rigor unused` itself reports as dead still roots its
|
|
35
|
+
# target, exactly as the other plugins' roots do.
|
|
36
|
+
module AssociationRoots
|
|
37
|
+
COLLECTION_MACROS = %i[has_many has_and_belongs_to_many].freeze
|
|
38
|
+
ROOTED_MACROS = (COLLECTION_MACROS + %i[belongs_to has_one]).freeze
|
|
39
|
+
VALID_NAME = /\A(?:::)?[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*\z/
|
|
40
|
+
private_constant :VALID_NAME
|
|
41
|
+
|
|
42
|
+
module_function
|
|
43
|
+
|
|
44
|
+
# Sorted, unique model class names. Raises {Rigor::Plugin::Inflector::Unavailable} when a name had to
|
|
45
|
+
# be inflected and could not be.
|
|
46
|
+
def call(model_index)
|
|
47
|
+
namespaces = model_index.class_names.flat_map { |name| prefixes(name) }.to_set
|
|
48
|
+
roots = model_index.entries.each_value.flat_map do |entry|
|
|
49
|
+
entry.associations.filter_map { |row| resolve(entry.class_name, row, model_index, namespaces) }
|
|
50
|
+
end
|
|
51
|
+
roots.uniq.sort
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def prefixes(name)
|
|
55
|
+
segments = name.split("::")
|
|
56
|
+
(1...segments.length).map { |n| segments.first(n).join("::") }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def resolve(owner, row, model_index, namespaces)
|
|
60
|
+
return nil unless ROOTED_MACROS.include?(row[:macro])
|
|
61
|
+
return nil if row[:polymorphic] || row[:roots_declined]
|
|
62
|
+
|
|
63
|
+
type_name = type_name(row)
|
|
64
|
+
return nil if type_name.nil? || !VALID_NAME.match?(type_name)
|
|
65
|
+
# Rails 7.2+ (`MacroReflection#_klass`) tries `::Name` first when the computed name is the owner's
|
|
66
|
+
# own demodulized name, so the target may be the owner or a top-level class: decline.
|
|
67
|
+
return nil if type_name == owner.split("::").last
|
|
68
|
+
|
|
69
|
+
candidates(owner, type_name).each do |candidate|
|
|
70
|
+
return candidate if model_index.model?(candidate)
|
|
71
|
+
return nil if namespaces.include?(candidate)
|
|
72
|
+
end
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def type_name(row)
|
|
77
|
+
option = row[:class_name_option]
|
|
78
|
+
option = row[:source_type_option] if option.nil? && row[:through]
|
|
79
|
+
return nil if option == :dynamic
|
|
80
|
+
return option unless option.nil?
|
|
81
|
+
return nil if row[:through]
|
|
82
|
+
|
|
83
|
+
name = row[:name].to_s
|
|
84
|
+
name = Rigor::Plugin::Inflector.singularize(name) if COLLECTION_MACROS.include?(row[:macro])
|
|
85
|
+
Rigor::Plugin::Inflector.camelize(name)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# `compute_type`: a rooted name is looked up as is; otherwise the owner ITSELF first (`Post has_many
|
|
89
|
+
# :comments` tries `Post::Comment`), then its enclosing namespaces innermost first, then top level.
|
|
90
|
+
def candidates(owner, type_name)
|
|
91
|
+
return [type_name.delete_prefix("::")] if type_name.start_with?("::")
|
|
92
|
+
|
|
93
|
+
segments = owner.split("::")
|
|
94
|
+
nested = segments.length.downto(1).map { |n| "#{segments.first(n).join('::')}::#{type_name}" }
|
|
95
|
+
nested + [type_name]
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|