hash as def argument - ruby

Is the following possible in any way? I keep running into a odd number list for Hash
def thores_hammer(bling)
hammer_bling = { bling }
end
thores_hammer :rubys => 5,
:emeralds => 5,
:souls => 333
Thanks ahead of time.

The reason you're running into an error is that the
Hash is implicitly created when the thores_hammer method
is invoked - so when you do { bling } you're creating a hash
with only one key (which is itself a hash) and no value. Thus the
error.
All you need to do is drop the curly braces:
irb> def thores_hammer(bling)
hammer_bling = bling
end
#=> nil
irb> thores_hammer :rubys => 5,
:emeralds => 5,
:souls => 333
#=> {:rubys=>5, :emeralds=>5, :souls=>333}

What you may be intending to do is make a copy of the Hash which could be done as:
def thores_hammer(bling)
hammer_bling = bling.dup
end
It might be a good idea to make a copy if you're intending to use the Hash for a long period of time and aren't sure if modifying the copy the method was given is a good idea because it could be used in other places.
Also, there are several different uses for curly braces within Ruby such as declaring blocks.

Try this:
def thores_hammer(bling)
hammer_bling = bling
end
thores_hammer Hash[:rubys => 5, :emeralds => 5, :souls => 333]

Related

Ruby hash defaults: where do nested values go? [duplicate]

This question already has answers here:
Strange, unexpected behavior (disappearing/changing values) when using Hash default value, e.g. Hash.new([])
(4 answers)
Closed 6 years ago.
I wanted to use Ruby's default hash values to allow me to more easily nest hashes without having to manually initialize them. I thought it'd be nice to be able to dig a level down for each key safely without having pre-set the key as a hash. However, I find that when I do this, the data gets stored somewhere, but is not visible by accessing the top-level hash. Where does it go, and how does this work?
top = Hash.new({}) #=> {}
top[:first][:thing] = "hello" #=> "hello"
top[:second] = {thing: "world"} #=> {:thing => "world"}
top #=> {:second => {:thing => "world"}}
top[:first] #=> {:thing => "hello"}
You want to know where your inserted hash is? Maybe you have heard about Schroedingers cat:
h = Hash.new({})
h[:box][:cat] = "Miau"
=> "Miau"
h
=> {}
The cat seem to be dead....
h[:schroedingers][:cat]
=> "Miau"
The cat seem still to be alive, but in a different reality....
Ok, if nothing helps, "Read The Fine Manual". For Hash.new, we read:
If obj is specified, this single object will be used for all default values.
So when you write h[:box], a object is returned, and this object is another hash, and it happen to empty.
Into this empty hash, you write an key-value.
Now this other hash is no longer empty, it has a key-value pair. And it is returned every time you search for a key is not found in your original hash.
You can access the default value via a variety of #default methods
http://ruby-doc.org/core-2.2.3/Hash.html#method-i-default
top.default
=> {:thing=>"hello"}
You can also tell it how you want it to act, example:
irb(main):058:0> top = Hash.new {|h,k| h[k] = {}; h[k]}
=> {}
irb(main):059:0> top[:first][:thing] = "hello"
=> "hello"
irb(main):060:0> top[:second] = {thing: "world"}
=> {:thing=>"world"}
irb(main):061:0> top
=> {:first=>{:thing=>"hello"}, :second=>{:thing=>"world"}}

Ruby multiple named arguments

I'm very new to ruby and I'm trying to write a web application using the rails framework. Through reading I've seen methods being called like this:
some_method "first argument", :other_arg => "value1", :other_arg2 => "value2"
Where you can pass an unlimited number of arguments.
How do you create a method in ruby that can be used in this way?
Thanks for the help.
That works because Ruby assumes the values are a Hash if you call the method that way.
Here is how you would define one:
def my_method( value, hash = {})
# value is requred
# hash can really contain any number of key/value pairs
end
And you could call it like this:
my_method('nice', {:first => true, :second => false})
Or
my_method('nice', :first => true, :second => false )
This is actually just a method that has a hash as an argument, below is a code example.
def funcUsingHash(input)
input.each { |k,v|
puts "%s=%s" % [k, v]
}
end
funcUsingHash :a => 1, :b => 2, :c => 3
Find out more about hashes here http://www-users.math.umd.edu/~dcarrera/ruby/0.3/chp_03/hashes.html
Maybe that *args can help you?
def meh(a, *args)
puts a
args.each {|x| y x}
end
Result of this method is
irb(main):005:0> meh(1,2,3,4)
1
--- 2
--- 3
--- 4
=> [2, 3, 4]
But i prefer this method in my scripts.
You can make the last argument be an optional hash to achieve that:
def some_method(x, options = {})
# access options[:other_arg], etc.
end
However, in Ruby 2.0.0, it is generally better to use a new feature called keyword arguments:
def some_method(x, other_arg: "value1", other_arg2: "value2")
# access other_arg, etc.
end
The advantages of using the new syntax instead of using a hash are:
It is less typing to access the optional arguments (e.g. other_arg instead of options[:other_arg]).
It is easy to specify a default value for the optional arguments.
Ruby will automatically detect if an invalid argument name was used by the caller and throw an exception.
One disadvantage of the new syntax is that you cannot (as far as I know) easily send all of the keyword arguments to some other method, because you don't have a hash object that represents them.
Thankfully, the syntax for calling these two types of methods is the same, so you can change from one to the other without breaking good code.

hash['key'] to hash.key in Ruby

I have a a hash
foo = {'bar'=>'baz'}
I would like to call foo.bar #=> 'baz'
My motivation is rewriting an activerecord query into a raw sql query (using Model#find_by_sql). This returns a hash with the SELECT clause values as keys. However, my existing code relies on object.method dot notation. I'd like to do minimal code rewrite. Thanks.
Edit: it appears Lua has this feature:
point = { x = 10, y = 20 } -- Create new table
print(point["x"]) -- Prints 10
print(point.x) -- Has exactly the same meaning as line above
>> require 'ostruct'
=> []
>> foo = {'bar'=>'baz'}
=> {"bar"=>"baz"}
>> foo_obj = OpenStruct.new foo
=> #<OpenStruct bar="baz">
>> foo_obj.bar
=> "baz"
>>
What you're looking for is called OpenStruct. It's part of the standard library.
A good solution:
class Hash
def method_missing(method, *opts)
m = method.to_s
if self.has_key?(m)
return self[m]
elsif self.has_key?(m.to_sym)
return self[m.to_sym]
end
super
end
end
Note: this implementation has only one known bug:
x = { 'test' => 'aValue', :test => 'bar'}
x.test # => 'aValue'
If you prefer symbol lookups rather than string lookups, then swap the two 'if' condition
Rather than copy all the stuff out of the hash, you can just add some behaviour to Hash to do lookups.
If you add this defintion, you extend Hash to handle all unknown methods as hash lookups:
class Hash
def method_missing(n)
self[n.to_s]
end
end
Bear in mind that this means that you won't ever see errors if you call the wrong method on hash - you'll just get whatever the corresponding hash lookup would return.
You can vastly reduce the debugging problems this can cause by only putting the method onto a specific hash - or as many hashes as you need:
a={'foo'=>5, 'goo'=>6}
def a.method_missing(n)
self[n.to_s]
end
The other observation is that when method_missing gets called by the system, it gives you a Symbol argument. My code converted it into a String. If your hash keys aren't strings this code will never return those values - if you key by symbols instead of strings, simply substitute n for n.to_s above.
There are a few gems for this. There's my recent gem, hash_dot, and a few other gems with similar names I discovered as I released mine on RubyGems, including dot_hash.
HashDot allows dot notation syntax, while still addressing concerns about NoMethodErrors addressed by #avdi. It is faster, and more traversable than an object created with OpenStruct.
require 'hash_dot'
a = {b: {c: {d: 1}}}.to_dot
a.b.c.d => 1
require 'open_struct'
os = OpenStruct.new(a)
os.b => {c: {d: 1}}
os.b.c.d => NoMethodError
It also maintains expected behavior when non-methods are called.
a.non_method => NoMethodError
Please feel free to submit improvements or bugs to HashDot.

Ruby: How do I use symbols to represent things in an array?

I have an array of arrays that looks like this:
fruits_and_calories = [
["apple", 100],
["banana", 200],
["kumquat", 225],
["orange", 90]
]
I also have a method I want to invoke on each element of the array:
fruits_and_calories.each do |f| eat(f[0], f[1])
I'd really like to be able to say something like:
fruits_and_calories.each do |f| eat(f[:name], f[:calories])
Is there a way that I can pull this off without having to change each item in the array (for example, by iterating through it and somehow adding the symbols in)? Or, if that's too hard, is there a better alternative?
The best answer is not to use an Array at all, but to use a Hash:
fruits_and_calories = { :apple => 100,
:banana => 200,
:kumquat => 225,
:orange => 90}
fruits_and_calories.each do |name, calories|
eat(name, calories)
end
Without changing the data structure at all, you could change the block arguments to achieve the same thing:
fruits_and_calories.each do |name, calories| eat(name, calories); end
This works because Ruby will auto-expand the inner arrays (["apple", 100], etc) into the argument list for the block ('do |name, calories| ... end'). This is a trick that Ruby inherited from Lisp, known as 'destructuring arguments'.
Pesto's answer (use a hash) is a good one, but I think I'd prefer to use a Struct.
Fruit = Struct.new(:name, :calories)
fruits = [
Fruit.new("apple", 100),
Fruit.new("banana", 200),
Fruit.new("kumquat", 225),
Fruit.new("orange", 90)
]
fruits.each {|f| eat(f.name, f.calories)}
This also lends itself to changing eat from taking both the name and calories, to taking a fruit instance:
fruits.each {|f| eat(f)}
Is there some reason it must be an array, per se? That seems to cry out to be a hash, or a class for Fruit.
An array is always indexed by numbers, so as far as I know using the standard array it's not possible.
Personally I'd just opt for using a comment above the code to hint what f[0] and f[1] stands for.
But if you are hell bent on doing it I guess some duck-typing on the Array class works:
class Array
def name ; self[0] ; end
def calories ; self[1] ; end
end
# then call it with:
fruits_and_calories.each {|f| eat(f.name, f.calories) }

How can I use C# style enumerations in Ruby?

I just want to know the best way to emulate a C# style enumeration in Ruby.
Specifically, I would like to be able to perform logical tests against the set of values given some variable. Example would be the state of a window: "minimized, maximized, closed, open"
If you need the enumerations to map to values (eg, you need minimized to equal 0, maximised to equal 100, etc) I'd use a hash of symbols to values, like this:
WINDOW_STATES = { :minimized => 0, :maximized => 100 }.freeze
The freeze (like nate says) stops you from breaking things in future by accident.
You can check if something is valid by doing this
WINDOW_STATES.keys.include?(window_state)
Alternatively, if you don't need any values, and just need to check 'membership' then an array is fine
WINDOW_STATES = [:minimized, :maximized].freeze
Use it like this
WINDOW_STATES.include?(window_state)
If your keys are going to be strings (like for example a 'state' field in a RoR app), then you can use an array of strings. I do this ALL THE TIME in many of our rails apps.
WINDOW_STATES = %w(minimized maximized open closed).freeze
This is pretty much what rails validates_inclusion_of validator is purpose built for :-)
Personal Note:
I don't like typing include? all the time, so I have this (it's only complicated because of the .in?(1, 2, 3) case:
class Object
# Lets us write array.include?(x) the other way round
# Also accepts multiple args, so we can do 2.in?( 1,2,3 ) without bothering with arrays
def in?( *args )
# if we have 1 arg, and it is a collection, act as if it were passed as a single value, UNLESS we are an array ourselves.
# The mismatch between checking for respond_to on the args vs checking for self.kind_of?Array is deliberate, otherwise
# arrays of strings break and ranges don't work right
args.length == 1 && args.first.respond_to?(:include?) && !self.kind_of?(Array) ?
args.first.include?( self ) :
args.include?( self )
end
end
end
This lets you type
window_state.in? WINDOW_STATES
It's not quite the same, but I'll often build a hash for this kind of thing:
STATES = {:open => 1, :closed => 2, :max => 3, :min => 4}.freeze()
Freezing the hash keeps me from accidentally modifying its contents.
Moreover, if you want to raise an error when accessing something that doesn't exist, you can use a defualt Proc to do this:
STATES = Hash.new { |hash, key| raise NameError, "#{key} is not allowed" }
STATES.merge!({:open => 1, :closed => 2, :max => 3, :min => 4}).freeze()
STATES[:other] # raises NameError
I don't think Ruby supports true enums -- though, there are still solutions available.
Enumerations and Ruby
The easiest way to define an Enum in ruby to use a class with constant variables.
class WindowState
Open = 1
Closed = 2
Max = 3
Min = 4
end
Making a class or hash as others have said will work. However, the Ruby thing to do is to use symbols. Symbols in Ruby start with a colon and look like this:
greetingtype = :hello
They are kind of like objects that consist only of a name.

Resources