Skip to content

Commit

Permalink
Avoid ivar name collisions
Browse files Browse the repository at this point in the history
  • Loading branch information
shioyama committed Jul 4, 2022
1 parent 19349d6 commit 81d3d93
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 15 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,12 @@ def fetch_aggregate_data
end
```

By default, Michie prepends `__michie_` to the method name to generate the
instance variable name. This can be changed by passing a `prefix` option to
`memoize` (see specs for details).
By default, Michie generates an instance variable name prefix combining a
"base" string `__michie_` with either an `m_` (normal methods), `b_` (bang
methods ending in `!`) or `q_` (query methods ending in `?`). This prefix is
combined with the method name of the method to be memoized to generate the
instance variable name. The base prefix can be changed by passing a `prefix`
option to `memoize` (see specs for details).

Since Michie uses the presence of an instance variable to signal memoization,
`false` and `nil` values can be memoized (unlike techniques which use `||=`).
Expand Down
12 changes: 7 additions & 5 deletions lib/michie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ def initialize(*, &block)

module Helpers
def ivar_name(method_name, memoization_prefix)
string = "#{memoization_prefix}_#{method_name.to_s}"
string = String === method_name ? method_name.dup : method_name.to_s
method_type_prefix = "m"

if string.end_with?("?", "!")
string = string.dup
string.sub!(/\?\Z/, "_query") || string.sub!(/!\Z/, "_bang")
if string.chomp!("?")
method_type_prefix = "q"
elsif string.chomp!("!")
method_type_prefix = "b"
end
"@#{string}"
"@#{memoization_prefix}_#{method_type_prefix}_#{string}"
end
module_function :ivar_name
end
Expand Down
14 changes: 7 additions & 7 deletions spec/michie_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def my_method
expect(foo.my_method).to eq("result")
end

expect(foo.instance_variables).to eq([:"@__michie_my_method"])
expect(foo.instance_variables).to eq([:"@__michie_m_my_method"])
end

it "memoizes methods passed as args" do
Expand All @@ -47,12 +47,12 @@ def method2

expect(Listener).to receive(:call).once.and_return("result")
2.times { expect(foo.method1).to eq("result") }
expect(foo.instance_variables).to eq([:"@__michie_method1"])
expect(foo.instance_variables).to eq([:"@__michie_m_method1"])

expect(OtherListener).to receive(:call).once.and_return("result")
2.times { expect(foo.method2).to eq("result") }
expect(foo.instance_variables).to match_array(
[:"@__michie_method1", :"@__michie_method2"]
[:"@__michie_m_method1", :"@__michie_m_method2"]
)
end

Expand Down Expand Up @@ -127,9 +127,9 @@ def my_method?
foo.my_method?

expect(foo.instance_variables).to match_array([
:"@__michie_my_method",
:"@__michie_my_method_bang",
:"@__michie_my_method_query"
:"@__michie_m_my_method",
:"@__michie_b_my_method",
:"@__michie_q_my_method"
])
end

Expand All @@ -146,7 +146,7 @@ def my_method
foo = klass.new
foo.my_method

expect(foo.instance_variables).to eq([:"@foo_my_method"])
expect(foo.instance_variables).to eq([:"@foo_m_my_method"])
end

it "maintains visibility of memoized methods" do
Expand Down

0 comments on commit 81d3d93

Please sign in to comment.