Last active
July 5, 2017 13:07
-
-
Save k3rni/e8bc3a0d08dc9030da087584a0818234 to your computer and use it in GitHub Desktop.
Private `Module.delegate` behavior is wrong?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source 'https://rubygems.org' | |
gem 'activesupport', '~> 5.0' | |
gem 'minitest' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env ruby | |
require "bundler"; Bundler.require | |
require "active_support/all" | |
require "minitest/autorun" | |
class Base | |
def initialize(obj) | |
@obj = obj | |
end | |
end | |
describe "public delegates" do | |
before do | |
kls = Class.new(Base) do | |
delegate :foo, to: :@obj | |
end | |
@base = OpenStruct.new(foo: 42) | |
@obj = kls.new(@base) | |
end | |
specify "#foo is public" do | |
assert_respond_to @obj, :foo | |
assert @obj.method(:foo) | |
assert_equal @obj.public_send(:foo), 42 | |
end | |
specify "#foo calls underlying object's method" do | |
assert_equal @obj.foo, 42 | |
def @base.foo; 99; end | |
assert_equal @obj.foo, 99 | |
assert_equal @obj.public_send(:foo), 99 | |
end | |
end | |
describe "prefixed public delegates" do | |
before do | |
kls = Class.new(Base) do | |
delegate :foo, to: :@obj, prefix: :magic | |
end | |
@base = OpenStruct.new(foo: 42) | |
@obj = kls.new(@base) | |
end | |
specify "there is no #foo" do | |
refute_respond_to @obj, :foo | |
end | |
specify "#magic_foo is public" do | |
assert_respond_to @obj, :magic_foo | |
assert @obj.method(:magic_foo) | |
assert_equal @obj.public_send(:magic_foo), 42 | |
end | |
specify "#magic_foo calls underlying object's method" do | |
assert_equal @obj.magic_foo, 42 | |
def @base.foo; 99; end | |
assert_equal @obj.magic_foo, 99 | |
assert_equal @obj.public_send(:magic_foo), 99 | |
end | |
end | |
describe "private delegates" do | |
before do | |
kls = Class.new(Base) do | |
private(*delegate(:foo, to: :@obj)) | |
end | |
@base = OpenStruct.new(foo: 42) | |
@obj = kls.new(@base) | |
end | |
specify "#foo is private" do | |
refute_respond_to @obj, :foo # Because it's private | |
assert @obj.respond_to?(:foo, true) # This is how you check private respond_to? | |
assert @obj.method(:foo) # Can always fetch, even if private | |
assert_raises(NameError) do | |
@obj.public_send :foo | |
end | |
assert_raises(NameError) do | |
@obj.foo | |
end | |
end | |
specify "#foo calls underlying object's method" do | |
assert_equal @obj.send(:foo), 42 | |
def @base.foo; 99; end | |
assert_equal @obj.send(:foo), 99 | |
end | |
end | |
describe "prefixed private delegates" do | |
before do | |
kls = Class.new(Base) do | |
private(*delegate(:foo, to: :@obj, prefix: :magic)) | |
end | |
@base = OpenStruct.new(foo: 42) | |
@obj = kls.new(@base) | |
end | |
specify "there is no #foo" do | |
refute_respond_to @obj, :foo | |
refute @obj.respond_to?(:foo, true) | |
refute @obj.method(:foo) | |
end | |
specify "#magic_foo is private" do | |
refute_respond_to @obj, :magic_foo | |
assert @obj.respond_to?(:magic_foo, true) | |
assert @obj.method(:magic_foo) | |
end | |
specify "#magic_foo calls underlying object's method" do | |
assert_equal @obj.send(:magic_foo), 42 | |
def @base.foo; 99; end | |
assert_equal @obj.send(:magic_foo), 99 | |
end | |
end | |
describe "prefixed private delegates' ACTUAL BEHAVIOR" do | |
before do | |
kls = Class.new(Base) do | |
def foo | |
55 | |
end | |
private(*delegate(:foo, to: :@obj, prefix: :magic)) | |
end | |
@base = OpenStruct.new(foo: 42) | |
@obj = kls.new(@base) | |
end | |
specify "pre-existing #foo method is made private (by `private`)" do | |
refute_respond_to @obj, :foo | |
assert @obj.respond_to?(:foo, true) | |
assert @obj.method(:foo) | |
end | |
specify "newly created #magic_foo is PUBLIC" do | |
assert_respond_to @obj, :magic_foo | |
assert @obj.method(:magic_foo) | |
end | |
specify "#magic_foo calls underlying object's method" do | |
assert_equal @obj.send(:magic_foo), 42 | |
def @base.foo; 99; end | |
assert_equal @obj.send(:magic_foo), 99 | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment