-
-
Save pboling/79e5b7f6633dc0e5f7ee53e87246520d to your computer and use it in GitHub Desktop.
Rails `delegate to:` for hashes
This file contains hidden or 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
module HashDelegate | |
# Like `delegate :foo, to: :bar` only for hashes instead | |
# of objects. So these are the same: | |
# | |
# def foo | |
# bar[:foo] | |
# end | |
# | |
# hash_delegate :foo, to: :bar | |
# | |
# Like `delegate` instance variable can also be used: | |
# | |
# def foo | |
# @bar[:foo] | |
# end | |
# | |
# hash_delegate :foo, to: :@bar | |
# | |
# The above examples assume the keys are symbols. If they are strings you | |
# can still using this DSL you just need to provide a string regarding the | |
# key you are delegating: | |
# | |
# hash_delegate 'foo', to: :bar | |
# | |
# Is the same as: | |
# | |
# def foo | |
# bar['foo'] | |
# end | |
# | |
# `prefix` and `private` options also exist and work just like `delegate` | |
def hash_delegate *keys, to:, prefix: false, private: false | |
methods = [] | |
location = caller_locations(1, 1).first | |
file, line = location.path, location.lineno | |
keys.each do |key| | |
method = if prefix | |
"#{prefix == true ? to : prefix}_#{key}" | |
else | |
key | |
end | |
methods << method | |
module_eval <<~METH, file, line | |
def #{method} | |
#{to}[#{key.inspect}] | |
end | |
METH | |
end | |
private(*methods) if private | |
end | |
end |
This file contains hidden or 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
RSpec.describe HashDelegate do | |
let :klass do | |
Class.new do | |
extend HashDelegate | |
def initialize hsh | |
@hsh = hsh | |
end | |
def hsh | |
@hsh | |
end | |
hash_delegate :ivar, to: :@hsh | |
hash_delegate :meth, to: :hsh | |
hash_delegate 'str', to: :hsh | |
hash_delegate :pvt, to: :hsh, private: true | |
hash_delegate :prefix, to: :hsh, prefix: true | |
hash_delegate :prefix, to: :hsh, prefix: :named | |
end | |
end | |
it 'can delegate to an instance variable' do | |
obj = klass.new ivar: 'val' | |
expect( obj.ivar ).to eq 'val' | |
end | |
it 'can delegate to a method' do | |
obj = klass.new meth: 'val' | |
expect( obj.meth ).to eq 'val' | |
end | |
it 'can delegate a string' do | |
obj = klass.new 'str' => 'val' | |
expect( obj.str ).to eq 'val' | |
end | |
it 'can make delegation private' do | |
obj = klass.new pvt: 'val' | |
expect( obj.respond_to? :pvt ).to be false | |
expect( obj.send(:pvt) ).to eq 'val' | |
end | |
it 'can add prefix to delegation' do | |
obj = klass.new prefix: 'val' | |
expect( obj.hsh_prefix ).to eq 'val' | |
end | |
it 'can add named prefix to delegation' do | |
obj = klass.new prefix: 'val' | |
expect( obj.named_prefix ).to eq 'val' | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment