Class: Ryac::KeywordRenameMapping
- Inherits:
-
Object
- Object
- Ryac::KeywordRenameMapping
- Includes:
- UnionFind, UnionFind[method_key]
- Defined in:
- lib/ryac/analysis/keyword/rename_mapping.rb,
sig/ryac/analysis/keyword/rename_mapping.rbs
Instance Method Summary collapse
- #add_keyword_call(method_key, keyword_sym, symbol_node, val_node) ⇒ void
- #add_keyword_def(method_key, keyword_sym) ⇒ void
- #assign_short_names ⇒ void
-
#build_variable_hints {|arg0| ... } ⇒ Hash[scope_id, Hash[Symbol, String]]
A call passing a local as a keyword value —
f(code: c)— pays nothing when the local is named like the keyword, because the shorthand formf(code:)applies. -
#def_node_mapping(def_node_registry) ⇒ Hash[location_key, Hash[Symbol, String]]
Keyed by the def's location, the coordinate the scope analysis works in.
- #each_method_key {|arg0| ... } ⇒ void
- #exclude_method(method_key) ⇒ void
- #exclude_methods_by_mid(mids) ⇒ void
- #init_method(method_key) ⇒ void
-
#initialize ⇒ KeywordRenameMapping
constructor
A new instance of KeywordRenameMapping.
- #merge_groups(key1, key2) ⇒ void
- #node_mapping ⇒ Hash[location_key, String]
Methods included from UnionFind
#uf_add, #uf_init, #uf_remove, #uf_root
Constructor Details
#initialize ⇒ KeywordRenameMapping
Returns a new instance of KeywordRenameMapping.
7 8 9 10 11 12 13 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 7 def initialize uf_init @methods = {} @node_short_names = {} @keyword_maps = {} @frozen = false end |
Instance Method Details
#add_keyword_call(method_key, keyword_sym, symbol_node, val_node) ⇒ void
This method returns an undefined value.
20 21 22 23 24 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 20 def add_keyword_call(method_key, keyword_sym, symbol_node, val_node) init_method(method_key) @methods[method_key][:call_entries][keyword_sym] ||= [] @methods[method_key][:call_entries][keyword_sym] << { symbol_node: symbol_node, val_node: val_node } end |
#add_keyword_def(method_key, keyword_sym) ⇒ void
This method returns an undefined value.
15 16 17 18 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 15 def add_keyword_def(method_key, keyword_sym) init_method(method_key) @methods[method_key][:keywords] << keyword_sym end |
#assign_short_names ⇒ void
This method returns an undefined value.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 50 def assign_short_names groups = Hash.new { |h, k| h[k] = [] } #: Hash[method_key, Array[method_key]] @methods.each_key { |key| groups[uf_root(key)] << key } groups.each do |_root, keys| next if keys.any? { |k| @methods[k][:excluded] } all_keywords = keys.flat_map { |k| @methods[k][:keywords].to_a }.uniq total_call_entries = keys.sum { |k| @methods[k][:call_entries].values.sum(&:size) } next if total_call_entries == 0 generator = NameGenerator.new keyword_map = {} #: Hash[Symbol, String] occurrences_by_sym = Hash.new(0) #: Hash[Symbol, Integer] keys.each do |k| info = @methods[k] info[:keywords].each { |sym| occurrences_by_sym[sym] += 1 } info[:call_entries].each { |sym, entries| occurrences_by_sym[sym] += entries.size } end # Sorted by total bytes at stake — the same greedy order every other # rename family uses, so the shortest names go where they pay most. all_keywords.sort_by { |sym| -(sym.to_s.size * occurrences_by_sym[sym]) }.each do |sym| next if sym.to_s.size <= NameGenerator::KEPT_NAME_MAX short = generator.next_name savings = (sym.to_s.size - short.size) * occurrences_by_sym[sym] next unless savings > MethodRenameMapping::MIN_GROUP_SAVINGS keyword_map[sym] = short end next if keyword_map.empty? @keyword_maps[_root] = keyword_map keys.each do |key| @methods[key][:call_entries].each do |sym, entries| short = keyword_map[sym] next unless short entries.each { |e| @node_short_names[AstUtils.location_key(e[:symbol_node])] = short } end end end @frozen = true end |
#build_variable_hints {|arg0| ... } ⇒ Hash[scope_id, Hash[Symbol, String]]
A call passing a local as a keyword value — f(code: c) — pays nothing
when the local is named like the keyword, because the shorthand form
f(code:) applies. These hints suggest that name to the local's scope.
The scope containing the call site is the caller's concern: pass a block mapping a call-argument node to its scope id.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 128 def build_variable_hints hints = {} #: scope_mapping_table @methods.each do |method_key, info| next if info[:excluded] root = uf_root(method_key) keyword_map = @keyword_maps[root] || {} info[:call_entries].each do |keyword_sym, entries| # Use renamed name if available; for already-short keywords, # use original name to preserve idempotency across re-minification passes final_name = keyword_map[keyword_sym] final_name ||= keyword_sym.to_s if keyword_sym.to_s.size <= NameGenerator::KEPT_NAME_MAX next unless final_name entries.each do |entry| val_node = entry[:val_node] next unless val_node.is_a?(Prism::LocalVariableReadNode) scope_id = yield(val_node) next unless scope_id hints[scope_id] ||= {} hints[scope_id][val_node.name] ||= final_name end end end hints end |
#def_node_mapping(def_node_registry) ⇒ Hash[location_key, Hash[Symbol, String]]
Keyed by the def's location, the coordinate the scope analysis works in.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 102 def def_node_mapping(def_node_registry) result = {} #: Hash[location_key, Hash[Symbol, String]] def_node_registry.each do |method_key, def_nodes| root = uf_root(method_key) keyword_map = @keyword_maps[root] next unless keyword_map next if @methods[method_key]&.[](:excluded) def_nodes.each do |def_node| mapping = {} #: Hash[Symbol, String] keyword_map.each do |sym, short| mapping[sym] = short end result[AstUtils.location_key(def_node)] = mapping unless mapping.empty? end end result end |
#each_method_key {|arg0| ... } ⇒ void
This method returns an undefined value.
46 47 48 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 46 def each_method_key(&block) @methods.each_key(&block) end |
#exclude_method(method_key) ⇒ void
This method returns an undefined value.
26 27 28 29 30 31 32 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 26 def exclude_method(method_key) init_method(method_key) root = uf_root(method_key) @methods.each_key do |k| @methods[k][:excluded] = true if uf_root(k) == root end end |
#exclude_methods_by_mid(mids) ⇒ void
This method returns an undefined value.
34 35 36 37 38 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 34 def exclude_methods_by_mid(mids) @methods.keys.each do |key| exclude_method(key) if mids.include?(key[2]) end end |
#init_method(method_key) ⇒ void
This method returns an undefined value.
161 162 163 164 165 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 161 def init_method(method_key) return if @methods.key?(method_key) @methods[method_key] = { keywords: Set.new, call_entries: {}, excluded: false } uf_add(method_key) end |
#merge_groups(key1, key2) ⇒ void
This method returns an undefined value.
40 41 42 43 44 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 40 def merge_groups(key1, key2) init_method(key1) init_method(key2) super end |
#node_mapping ⇒ Hash[location_key, String]
97 98 99 |
# File 'lib/ryac/analysis/keyword/rename_mapping.rb', line 97 def node_mapping @node_short_names.dup end |