Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Created August 24, 2015 04:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/6032d89e9d0ea9b7c39e to your computer and use it in GitHub Desktop.
Save JoshCheek/6032d89e9d0ea9b7c39e to your computer and use it in GitHub Desktop.
How to determine the method delimiter, given a method
# Response to this tweet by Searls: https://twitter.com/searls/status/635638431905902594
require 'rspec/autorun'
def method_delimiter(m)
singleton = m.owner.singleton_class?
bound = !m.respond_to?(:bind)
if singleton && bound
'.'
else
'#'
end
end
RSpec.describe 'method_delimiter' do
def assert_delimiter(expected, meth, owner: nil)
expect(expected).to eq method_delimiter(meth)
expect(meth.owner).to eq owner if owner
end
describe 'true when it is a singleton method, regardless of whether' do
it 'is on an anonymous or named class' do
assert_delimiter '.', Class.new { def self.zomg; end }.method(:zomg)
assert_delimiter '.', File.method(:exist?)
end
it 'is inherited or not' do
assert_delimiter '.', File.method(:exist?), owner: File.singleton_class
assert_delimiter '.', File.method(:open), owner: IO.singleton_class
end
it 'is on a non-class object' do
o = Object.new.tap { |o| def o.zomg; end }
assert_delimiter '.', o.method(:zomg), owner: o.singleton_class
end
end
describe 'false when it is not a singleton method, regardless of whether' do
it 'is on an anonymous or named class' do
assert_delimiter '#', Class.new { def zomg; end }.instance_method(:zomg)
assert_delimiter '#', Object.new.method(:to_s)
end
it 'is inherited or not' do
klass = Class.new { def zomg; end }
assert_delimiter '#', klass.new.method(:zomg)
assert_delimiter '#', Class.new(klass).new.method(:zomg)
end
it 'is inherited from a module' do
assert_delimiter '#', Class.new { include Module.new { def zomg; end } }.new.method(:zomg)
end
it 'is inherited from a module that was mixed into the singleton class' do
assert_delimiter '#', Object.new.extend(Module.new { def zomg; end }).method(:zomg)
end
it 'receiver is a class or an instance' do
assert_delimiter '#', Class.new.method(:to_s)
assert_delimiter '#', Object.new.method(:to_s)
end
end
describe 'wonky ass edge cases' do
it 'is true if it is a bound singleton method, but not a unbound singleton method' do
klass = Class.new { def self.zomg; end }
unbound = klass.singleton_class.instance_method(:zomg)
assert_delimiter '.', klass.method(:zomg) # #<Method: #<Class:0x007fe75b852060>.zomg>
assert_delimiter '#', unbound # #<UnboundMethod: #<Class:#<Class:0x007fe75b852060>>#zomg>
assert_delimiter '.', unbound.bind(klass) # #<Method: #<Class:0x007fe75b852060>.zomg>
assert_delimiter '.', unbound.bind(Class.new klass) # #<Method: #<Class:0x007f947a04e6e0>(#<Class:0x007fe75b852060>).zomg>
assert_delimiter '#', unbound.bind(klass).unbind # #<UnboundMethod: #<Class:#<Class:0x007fe75b852060>>#zomg>
end
end
end
# >> .........
# >>
# >> Finished in 0.00343 seconds (files took 0.16537 seconds to load)
# >> 9 examples, 0 failures
# >>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment