Module: Audition::Rewriters::Memoization
- Defined in:
- lib/audition/rewriters.rb
Overview
Rewrites singleton-scope ivar state to Ractor-local storage:
@x ||= expr -> Ractor.store_if_absent(:"Klass/@x") { expr }
@x = expr -> Ractor.current[:"Klass/@x"] = expr
@x -> Ractor.current[:"Klass/@x"]
Only when every reference in singleton scope is visible in this file, none sit directly in the class body, and no compound writes exist. Caveat (why this is unsafe): each Ractor computes its own copy, and store_if_absent treats a stored nil as present where ||= would recompute.
Defined Under Namespace
Classes: SingletonIvars
Class Method Summary collapse
Class Method Details
.edit_for(op, key) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/audition/rewriters.rb', line 117 def self.edit_for(op, key) node = op[:node] case op[:kind] when :or_write value = node.value.location.slice Autofix.new( start_offset: node.location.start_offset, end_offset: node.location.end_offset, replacement: "Ractor.store_if_absent(#{key}) { #{value} }", safety: :unsafe ) when :write Autofix.new( start_offset: node.name_loc.start_offset, end_offset: node.name_loc.end_offset, replacement: "Ractor.current[#{key}]", safety: :unsafe ) when :read Autofix.new( start_offset: node.location.start_offset, end_offset: node.location.end_offset, replacement: "Ractor.current[#{key}]", safety: :unsafe ) end end |
.plan(file, findings) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/audition/rewriters.rb', line 97 def self.plan(file, findings) return [] if findings.none? { |f| f.check == "class-level-state" } collector = SingletonIvars.new collector.visit(file.root) edits = [] collector.groups.each do |(namespace, name), ops| next if namespace.empty? kinds = ops.map { |op| op[:kind] } next unless kinds.include?(:or_write) next if kinds.include?(:other) next if ops.any? { |op| op[:body] } key = %(:"#{namespace}/#{name}") ops.each { |op| edits << edit_for(op, key) } end edits end |