Skip to content

Instantly share code, notes, and snippets.

@k3rni
Last active July 5, 2017 13:07
Show Gist options
  • Save k3rni/e8bc3a0d08dc9030da087584a0818234 to your computer and use it in GitHub Desktop.
Save k3rni/e8bc3a0d08dc9030da087584a0818234 to your computer and use it in GitHub Desktop.
Private `Module.delegate` behavior is wrong?
source 'https://rubygems.org'
gem 'activesupport', '~> 5.0'
gem 'minitest'
#! /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