Hash auto-true ({:a} == {:a => true})

I have a unix-inspired desire to pass arguments to a method where some
are toggle flags and some are values, aka “bash$ method --flag
–config=/etc/method”. I can think of a few ways to do it that are
close, but if I had a hash that initiated value-less keys to true, I
would have it.

Example:

method(:flag, :another, :config => “/etc/whatever”)

For some of the functionality I colud use *args and check
args.include?(:foo), but then I couldn’t pass in key-value pairs easily.

The closest way would be to use *args to pass in things of the form
method(:flag, [:config, “/etc/whatever”]), then use args.include?(:flag)
for flags and args.assoc(:config)[1] for value-based options.

Example:

method(:flag, [:config, “/etc/whatever”])

ex. code:

if args.include?(:flag) do; stuff; end
if args.assoc(:config) do; @config = args.assoc(:config)[1]; end

I’d have to make the args.assoc logic prettier with a helper method to
set up default values, but that’s the basics of it. Much easier/prettier
if I could modify Hash to auto-assign empty keys to true. Note that
there’s a way to set the default value for empty keys from nil to
another value (and even a proc), but this wouldn’t be what I want. I
want empty keys to be nil, and specified lone keys set to true.

Thoughts? Anybody else think this would be really handy, or am I missing
something?

2008/9/8 Woody P. [email protected]

I have a unix-inspired desire to pass arguments to a method where some
are toggle flags and some are values, aka “bash$ method --flag
–config=/etc/method”. I can think of a few ways to do it that are
close, but if I had a hash that initiated value-less keys to true, I
would have it.

If you make the restriction that flags always come first you could do
something like this:

def my_method(arg1, arg2, *args)
options = (Hash === args.last) ? args.pop : {}
puts args.inspect
puts options.inspect
end

my_method(‘foo’, ‘bar’, :flag, :value => ‘something’)
[:flag]
{:value=>“something”}

my_method(‘foo’, ‘bar’, :flag)
[:flag]
{}

my_method(‘foo’, ‘bar’, :value => ‘something’)
[]
{:value=>“something”}

Then you can check for flags using args.include?(:foo), or you could
loop
over them and set them to true in the hash:

args.each { |key| options[key] = true }

Yeah, that all would work pretty well. I think the restriction that
value pairs come last is fair, and it’s a pretty clean solution. Thanks!

Now I’m wondering what it would take to define a hash explode (sidenote:
is that what * on *args is called? explode?). How would one go about
defining something like {}args that explodes args into a
true-for-value-less hash (even using the code you posted)? I’m not sure
exactly how *args works internally, and it’s pretty hard to find info
about it, actually. Any idea what kind of method it is, and how would
you define another one?

Anyways, thanks for your suggestion. It’ll work great. I can’t help but
wonder what the world would be like with a “hash explode” for this
purpose, though :slight_smile:

Now I’m wondering what it would take to define a hash explode (sidenote:
is that what * on *args is called? explode?). How would one go about
defining something like {}args that explodes args into a
true-for-value-less hash (even using the code you posted)? I’m not sure
exactly how *args works internally, and it’s pretty hard to find info
about it, actually. Any idea what kind of method it is, and how would
you define another one?

Far as I know, the *args is part of Ruby’s syntax, it’s not a method
that
you can change. Even if you could change it, I’ve no idea which class
the
method would be in. The best you can do is use *args to mean “the
remaining
args” and pop the last one off if it’s a hash.

You could add a method in Hash to set one value to many keys:

class Hash
def set_many(value, *keys)
keys.each { |key| self[key] = value }
end
end

Then do the following:

def my_method(arg1, arg2, *args)
options = (Hash === args.last) ? args.pop : {}
options.set_many(true, *args)

end

def my_method(arg1, arg2, *args)
options = (Hash === args.last) ? args.pop : {}
options.set_many(true, *args)

end

Or this, to build the hash from the args array:

module Enumerable
def to_option_hash(value = true)
ary = entries
options = (Hash === ary.last) ? ary.pop : {}
ary.each { |key| options[key] = value }
options
end
end

Then you can do:

def my_method(arg1, arg2, *options)
options = options.to_option_hash

end

backwards compatible with my_method(:flag => true, :config =>
“whatever”)

err, following your examlpe, my_method(“arg1”, “arg2”, :flag => true,
:config => “whatever”).

def my_method(arg1, arg2, *options)
options = options.to_option_hash

end

That’s pretty cool. I was thinking something similar, but got stuck on
naming the method :-p

The advantage of this strategy over args.include?(:flag) is that it’s
backwards compatible with my_method(:flag => true, :config =>
“whatever”). Also, although I’m sure it’s negligible, after you hash it
you have a seek time of O(1), whereas I assume you have a seek time of
O(n) every time you call include?(). But mostly the backwards
compatibility.