Skip to content

Instantly share code, notes, and snippets.

@lukaszx0
Last active August 29, 2015 14:21
Show Gist options
  • Save lukaszx0/50a29c0aff87f3aefd89 to your computer and use it in GitHub Desktop.
Save lukaszx0/50a29c0aff87f3aefd89 to your computer and use it in GitHub Desktop.
kwargs polyfill

kwargs

This is a simple hash extension which imitates behaviour of ruby's 2.1 keyword arguments. Check out examples below and spec file for sample usage.

Examples

Required args

def foobar(args = {})
  # require :foo and :bar keys
  foo, bar = args.kwargs!(:foo, :bar)
  puts foo, bar
end

Default args

def foobar(args = {})
  # set default values for args
  foo = args.kwargs!([:foo, "bar"])
  puts foo
end

Mixed

def foobar(args = {})
  foo, bar = args.kwargs!([:foo, "bar"], :bar)
  puts foo
  puts args[:bar]
end
class Hash
def kwargs!(*args)
return_args = []
expected_args = []
key, val = nil, nil
args.each do |arg|
if arg.is_a?(Symbol) && has_key?(arg)
val = self[arg]
expected_args << arg
elsif arg.is_a?(Array) && arg.first.is_a?(Symbol)
key = arg.first
val = self[key] || arg.last
expected_args << key
else
raise ArgumentError
end
self[key] = val unless key.nil?
return_args << val
key = val = nil
end
raise ArgumentError unless keys & expected_args == keys
return_args
end
end
require 'spec_helper'
describe Hash do
describe 'required' do
context "mising argument" do
it { expect { { foo: "bar" }.kwargs!(:bar) }.to raise_error ArgumentError }
end
context "extra args" do
it { expect { { foo: "foo", bar: "bar" }.kwargs!(:foo) }.to raise_error ArgumentError }
end
end
describe 'defaults' do
it 'should set default value' do
hash = {}
hash.kwargs!([:foo, "foo"])
expect(hash[:foo]).to eq "foo"
end
it 'required and default arg' do
hash = { bar: "yolo" }
hash.kwargs!([:foo, "foo"], :bar)
expect(hash).to eq(foo: "foo", bar: "yolo")
end
end
describe 'returning' do
it 'should return array with args values' do
foo, bar = { bar: "yolo" }.kwargs!([:foo, "foo"], :bar)
expect(foo).to eq "foo"
expect(bar).to eq "yolo"
end
end
end
@ecin
Copy link

ecin commented May 18, 2015

Why not set the default keyword args in the hash itself?

def foo(args = { default: 1 })
  …
end

@ecin
Copy link

ecin commented May 18, 2015

Also, could make a new class (Kwargs.new(hash)) instead of monkeypatching hash.

@lukaszx0
Copy link
Author

Because if you'd have mixed args - required and default one, the default one will get overwritten and lost in translation (hash won't get merged) See this case:

def foo(args = { default: 1})
  puts args
end

foo(required: "yolo") => # { required: "yolo" }

@ecin
Copy link

ecin commented May 18, 2015

Oh, of course!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment