Change implementation from prepend to UnboundMethod#1
Change implementation from prepend to UnboundMethod#1AlexWayfer wants to merge 1 commit intotycooon:masterfrom
prepend to UnboundMethod#1Conversation
Pull Request Test Coverage Report for Build 15
💛 - Coveralls |
| @_memery_module.module_eval do | ||
| define_method(method_name) do |*args, &block| | ||
| return super(*args, &block) if block | ||
| define_method(method_name) do |*args, &block| |
There was a problem hiding this comment.
It should be conviment way to obtain source of original method in pry or irb
Memery allows it with $ method_name -s in pry or method(:method_name).super_method.source in irb which is good
There was a problem hiding this comment.
It should be conviment way to obtain source of original method in pry or irb
Then there should be specs for this.
There was a problem hiding this comment.
I don't think that viewing the source code of memoized method from pry/irb is very important, but OK, it can be an argument.
There was a problem hiding this comment.
Unfortunately, $ method_name -s doesn't work in Pry, but I hope that some day it will get fixed.
A.instance_method(:x).super_method.source technique does work, though, so we might want to just add that spec. I don't see much harm in having some extra ancestors.
There was a problem hiding this comment.
irb(main):002:0> def foo
irb(main):003:1> p :bar
irb(main):004:1> end
=> :foo
irb(main):005:0> method(:foo).source
NoMethodError: undefined method `source' for #<Method: main.foo>
from (irb):5
from /home/alex/.rbenv/versions/2.4.4/bin/irb:11:in `<main>'
What are you talking about?
There was a problem hiding this comment.
A.instance_method(:x).super_method.source works everywhere in case you required method_source gem.
But that's just an example, the idea is, with current implementation it is possible to get the actual method's source code using Ruby, and with this implementation it becomes impossible.
There was a problem hiding this comment.
OK. This MR is just offer, proof of concept, showcase of alternative way. If you think that getting source from Ruby (pry) is more important than a lot of Memery in ancestors in case of inheritance (and maybe some other unpleasant consequences, about which I don't remember or don't know) — you can just close this MR. And in the future, if some obvious shortcomings of the prepend approach will be revealed — you and others will know about another not bad (in my opinion) approach, and apply it, or create a fork with it.
There was a problem hiding this comment.
Unfortunately, $ method_name -s doesn't work in Pry, but I hope that some day it will get fixed.
Just a ref to issue: pry/pry#1756
There was a problem hiding this comment.
With this implementation you can show the source of original method by moving (stepping) into method from memery and calling $ original_method from method body.
There was a problem hiding this comment.
Maybe, but you can't do method(:x).super_method.source as stated in Readme.
`prepend` pollutes `Module#ancestors`: ```ruby module Foo end class Bar prepend Foo end class Baz < Bar prepend Foo end Baz.ancestors # => [Foo, Baz, Foo, Bar, Object, Kernel, BasicObject] ```
0d62f66 to
30cbebb
Compare
|
Cool, closing for now then. The ability to get the source code of the original method was kept in mind when I was building this gem, and it does not rely on |
It would be good to refer to issue in |
|
We have a code in commercial project with Spec added. Maybe you can review your decision. |
|
I often use the |
|
OK. I've fixed our case with |
|
The bad case with # .test.rb
# frozen_string_literal: true
require 'pry-byebug'
require_relative 'lib/memery'
module A
include Memery
memoize def foo
'source'
end
end
module B
include Memery
include A
memoize def foo
"Get this #{super}!"
end
end
class C
include B
end
c = C.new
binding.pry
puts c.foo> ruby .test.rb
From: /home/alex/Projects/ruby/memery/.test.rb @ line 31 :
26:
27: c = C.new
28:
29: binding.pry
30:
=> 31: puts c.foo
pry: main > c.foo
=> "Get this source!"
pry: main > show-source c.foo
From: /home/alex/Projects/ruby/memery/lib/memery.rb @ line 55:
Owner: #<Module:0x000055d0fa6ab460>
Visibility: public
Number of lines: 17
define_method(method_name) do |*args, &block|
if block || (condition && !instance_exec(&condition))
return super(*args, &block)
end
key = "#{method_name}_#{mod_id}"
store = (@_memery_memoized_values ||= {})[key] ||= {}
if store.key?(args) && (ttl.nil? || Memery.monotonic_clock <= store[args][:time] + ttl)
return store[args][:result]
end
result = super(*args)
@_memery_memoized_values[key][args] = { result: result, time: Memery.monotonic_clock }
result
end
pry: main > show-source -s c.foo
From: /home/alex/Projects/ruby/memery/lib/memery.rb @ line 55:
Owner: #<Module:0x000055d0fa6ab460>
Visibility: public
Number of lines: 17
define_method(method_name) do |*args, &block|
if block || (condition && !instance_exec(&condition))
return super(*args, &block)
end
key = "#{method_name}_#{mod_id}"
store = (@_memery_memoized_values ||= {})[key] ||= {}
if store.key?(args) && (ttl.nil? || Memery.monotonic_clock <= store[args][:time] + ttl)
return store[args][:result]
end
result = super(*args)
@_memery_memoized_values[key][args] = { result: result, time: Memery.monotonic_clock }
result
end
pry: main > show-source -ss c.foo
From: /home/alex/Projects/ruby/memery/lib/memery.rb @ line 55:
Owner: #<Module:0x000055d0fa6abd98>
Visibility: public
Number of lines: 17
define_method(method_name) do |*args, &block|
if block || (condition && !instance_exec(&condition))
return super(*args, &block)
end
key = "#{method_name}_#{mod_id}"
store = (@_memery_memoized_values ||= {})[key] ||= {}
if store.key?(args) && (ttl.nil? || Memery.monotonic_clock <= store[args][:time] + ttl)
return store[args][:result]
end
result = super(*args)
@_memery_memoized_values[key][args] = { result: result, time: Memery.monotonic_clock }
result
end
pry: main > show-source -sss c.foo
From: /home/alex/Projects/ruby/memery/lib/memery.rb @ line 55:
Owner: #<Module:0x000055d0fa6abd98>
Visibility: public
Number of lines: 17
define_method(method_name) do |*args, &block|
if block || (condition && !instance_exec(&condition))
return super(*args, &block)
end
key = "#{method_name}_#{mod_id}"
store = (@_memery_memoized_values ||= {})[key] ||= {}
if store.key?(args) && (ttl.nil? || Memery.monotonic_clock <= store[args][:time] + ttl)
return store[args][:result]
end
result = super(*args)
@_memery_memoized_values[key][args] = { result: result, time: Memery.monotonic_clock }
result
end
pry: main > show-source -ssss c.foo
Error: Couldn't locate a definition for c.foo |
|
I've updated the branch if you'll be interested. (but PR is not updated somewhy) Also, with the example ( pry: main > c.method(:foo).owner.memoized_methods[:foo].source
=> " memoize def foo\n \"Get this \#{super}!\"\n end\n"
pry: main > c.method(:foo).super_method.owner.memoized_methods[:foo].source
=> " memoize def foo\n 'source'\n end\n" |
|
And another issue: I can create a literally issue, but this PR is resolving them all. |
prependpollutesModule#ancestors:Also, two modules with included Memery can broke the source of super-method.
And
define_methodwithUnboundMethodis possible now.