Hash method get on ruby - ruby

I need to get some values for a hash but, I don't know how can I do it!
My data:
data = {
name: "Pedro Álvares",
age: 35,
sensitive_data: {
cpf_cnpj=>27046645678,
fantasy_name: "I have the power"
}
}
I search for ruby methods and find the method values_at, but this method gets only the first_data like name, age.
If I use:
name = data.values_at(:name)
the field returned is Pedro Álvares
but if I try use:
fantasy_name = data.values_at(:fantasy_name)
the data returned is nil.
How can I get the field without using data[:sensitive_data][:fantasy_name]?

Because you know the correct structure of the hash you should write:
data[:sensitive_data][:fantasy_name]
#=> "I have the power"
You should not use dig here. Why? Suppose you accidently wrote
data.dig(:sesnitive_data, :fantasy_name)
The would return nil (because data has no key :sesnitive). Depending on the context the error might not surface until sometime later, making debugging more difficult than is necessary.
By contrast, if you wrote
data[:sesnitive_data][:fantasy_name]
data[:sesnitive_data] would return nil (because data has no key :sesnitive_data) and then nil[:sesnitive_data] would raise an exception, informing you that nil has no method []. That is precisely what you want to happen: you want to be notified of the error immediately, and have the reason for it it pinpointed, so you can easily correct your code.
Hash#dig, Array#dig and Struct#dig (which call each other) have their uses (when you do not know the structures of objects in advance--a hash's keys, for example), but those methods should not be used when an object's structure is known.

You could get the nested value by dig method:
data.dig(:sensitive_data, :fantasy_name) # => "I have the power"

Related

Why can you change the value of a local variable in Ruby in a function using another method but not with an assignment operator?

I'm trying to understand the concept of Ruby as a pass-by-reference-value language. Using an example I found on this site...
def uppercase(value)
value.upcase!
end
name = 'William'
uppercase(name)
puts name
we get the output "WILLIAM". So value and name are both pointing at the same object, which is initially holding a value of "William" and then .upcase changes it to "WILLIAM". I would understand this as pass-by-reference.
But then if I change .upcase to =:
def uppercase2(value)
value = "WILLIAM"
end
name = 'William'
uppercase2(name)
puts name
The output becomes "William". Which is pass by value.
Why does an assignment operator make the difference in how a variable is treated in Ruby?
The key here is that you can never change a Ruby object's core self, once it has been created it will always be the same object until garbage collected and destroyed. It is only possible to alter properties of the object.
You can, however, change variables or object references such as instance variables, constants, attr_accessor properties among other things.
So in this case:
def uppercase2(value)
value = "WILLIAM"
end
This reassigns the value local variable. It does nothing to the original object.
If you want to replace that text you need to use methods on the object to effect it, if supported. In this case there is a method:
def uppercase2(value)
value.replace("WILLIAM")
end
These are generally termed in-place modifications as in the object itself is manipulated rather than swapped for another object.
I'm trying to understand the concept of Ruby as a pass-by-reference-value language.
Ruby is pass-by-value. Always. It is never pass-by-reference. The value that is being passed is an immutable unforgeable pointer, but that is very different from pass-by-reference.
C is pass-by-value. And C has pointers. That doesn't mean that if you pass a pointer in C, it magically becomes pass-by-reference. It is still pass-by-value.
C++ has pointers, and it supports both pass-by-value and pass-by-reference. In C++, you can pass pointers by value or by reference and you can pass non-pointers by value or by reference. The two concepts are completely orthogonal.
If we can agree that C is pass-by-value, and we can agree that C has pointers, and we can agree that when we pass a pointer in C, that is still pass-by-value, then we must also agree that Ruby is pass-by-value, because Ruby behaves like a hypothetical version of C, where the only allowed types are "pointer to something", the only way to access a value is dereferencing the pointer, and the only way to pass a value is taking the pointer.
That does not change parameter passing in C in any way, which means it is still pass-by-value, which means if we call that in C pass-by-value, it doesn't make sense to call it anything else in Ruby.
def uppercase(value)
value.upcase!
end
name = 'William'
uppercase(name)
puts name
we get the output "WILLIAM". So value and name are both pointing at the same object, which is initially holding a value of "William" and then .upcase changes it to "WILLIAM". I would understand this as pass-by-reference.
Again, this is not pass-by-reference. Pass-by-reference would mean that you can change the reference in the caller's scope, which Ruby does not allow you to do.
This is nothing but simple mutation. Ruby is not a purely functional language, it does allow you to mutate objects. And when you mutate an object, you can observe its changed state regardless of what name you call it.
My friends call me "Jörg" but my barber calls me "Mr. Mittag". When my barber cuts my hair, it doesn't magically grow back when I meet my friends, it will still be gone even though they don't refer to me by the same name as my barber does.
You have two names for the same object, and you mutate that object. You will observe the new state regardless of which name you use to refer to that object.
That is simply "mutable state", it has nothing to do with pass-by-reference.
But then if I change .upcase to =:
def uppercase2(value)
value = "WILLIAM"
end
name = 'William'
uppercase2(name)
puts name
The output becomes "William". Which is pass by value.
Why does an assignment operator make the difference in how a variable is treated in Ruby?
It doesn't. Both cases are pass-by-value. In the second case, you created a new object and assigned it to the local variable value inside the uppercase2 method. (Technically, it is not a local variable, it is a parameter binding, but it can be rebound inside the method body, precisely because Ruby is pass-by-value. If it were pass-by-reference, then this would have also reassigned the name local variable to the newly created object.)
Sometimes, this specific case of pass-by-value, where the value being passed is an immutable pointer to a potentially mutable object is called call-by-object-sharing, call-by-sharing, or call-by-object. But that is not something different from pass-by-value. It is still pass-by-value. It is a special case of pass-by-value, where the value cannot be "any value" but is always "an immutable unforgeable pointer".
Sometimes, you will hear the description "Ruby is pass-by-value where the value that is being passed is a reference" or "Ruby is pass-by-reference-value" or "Ruby is pass-by-value-reference" or "Ruby is pass-by-object-reference". I don't really like these terms, because they sound very close to "pass-by-reference", but actually the term "reference" in "pass-by-reference" and the term "reference" in "pass-by-object-reference" mean two different things.
In "pass-by-reference", the term "reference" is a technical term that can be thought of as a generalization of the concept of "variable", "storage location", etc. Wheres in "pass-by-value-reference", we are talking about "object references", which are more like pointers but cannot be manufactured or changed.
I also don't like the terms that I used above "pass-by-value where the value being passed is an immutable unforgeable pointer", because the term "pointer" has certain connotations, especially for people coming from C. In C, you can do pointer arithmetic, and you can cast a number to a pointer, i.e. you can "conjure up a pointer out of thin air". You can do none of that in Ruby. That's why I add the adjectives "immutable" (no arithmetic) and "unforgeable" (you cannot create a pointer, only be handed one by the system), but people overlook or ignore them or underestimate their importance.
In some languages, these immutable unforgeable pointers to objects are called "object references" (which is again dangerous because it invites confusion with "pass-by-reference") or OOPS (Object-Oriented PointerS) which has the unfortunate connotations of the mostly unrestricted free-for-all "C" pointers. (Go, for example, has much more restrictive pointers, but when you simply say the word "pointer", nobody thinks of Go.)
Note that none of this is really specific to Ruby. Python, ECMAScript, Java, and many others behave the same way. C# behaves the same way by default, but also supports pass-by-reference as an explicit opt-in. (You must explicitly request pass-by-reference both at the method definition and at the method call.) Scala behaves the same way by default, but optionally supports call-by-name.
C# is actually a very good way of demonstrating the distinctions, because C# supports both pass-by-value and pass-by-reference, both value types and reference types, and obviously, you can write types both as mutable and immutable types, so you actually get all 8 possible different combinations and you can study how they behave.
I came up with this simple test code, which you can easily translate into other languages as well:
def is_ruby_pass_by_value?(foo)
foo.replace('More precisely, it is call-by-object-sharing!')
foo = 'No, Ruby is pass-by-reference.'
end
bar = 'Yes, of course, Ruby *is* pass-by-value!'
is_ruby_pass_by_value?(bar)
p bar
# 'More precisely, it is call-by-object-sharing!'
Here is the slightly more involved example in C#:
struct MutableCell { public string value; }
static void ArgumentPassing(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
{
foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
foo = new string[] { "C# is not pass-by-reference." };
bar.value = "For value types, it is *not* call-by-sharing.";
bar = new MutableCell { value = "And also not pass-by-reference." };
baz = "It also supports pass-by-reference if explicitly requested.";
qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
}
var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };
var corge = new MutableCell { value = "For value types it is pure pass-by-value." };
var grault = "This string will vanish because of pass-by-reference.";
var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };
ArgumentPassing(quux, corge, ref grault, ref garply);
Console.WriteLine(quux[0]);
// More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.
Console.WriteLine(corge.value);
// For value types it is pure pass-by-value.
Console.WriteLine(grault);
// It also supports pass-by-reference if explicitly requested.
Console.WriteLine(garply.value);
// Pass-by-reference is supported for value types as well.
Let's start breaking this down in something more understandable.
You can compare a variable like name (or value) with a signpost.
Let's say I point it to the a beige house, which will be the value of the variable.
With the above in mind let's take a look at the first example:
# don't worry about this line for now
House = Struct.new(:color)
def color_red(value)
value.color = :red
end
house = House.new(:beige)
color_red(house)
puts house
# prints: #<struct House color=:red>
So what happens here? When we pass house as parameter to color_red Ruby will copy our signpost and assign it to value. Now both signposts point to the same house. We then follow the directions of signpost value and walk to the house and paint it red.
For this reason the color of house will end up being red.
Now let's have a look at the other example:
def color_red(value)
value = House.new(:red)
end
house = House.new(:beige)
color_red(house)
puts house
# prints: #<struct House color=:beige>
Here we start of the same, we copy our signpost house and assign the copy to value. However instead of walking up to the house and painting it, we are going to modify the signpost and point it to a red house somewhere further down the street. And because our signpost value is a copy of house, pointing it in a new direction will not effect house.
Your code is doing the same thing. When you call value.upcase! you are saying to she string. Hey you, upcase all your characters! (Similar to painting the house.)
When you reasign value (value = "WILLIAM") you are essentially just modifying the signpost and pointing it to a new direction. However the signpost is passed as a copy so it does not effect the original.
def uppercase(value)
value.upcase!
end
name = 'William'
uppercase(name)
puts name #WILLIAM
In this case, you are mutating the original object. name points to William
and so does value. When you pass in the argument, Ruby will assign
the parameter variable value to the same object that name is pointing to.
def uppercase2(value)
value = "WILLIAM"
end
name = 'William'
uppercase2(name)
puts name
In this case, you are reassigning value. That is, you are changing which
object value is pointing to. It was pointing to the same string object that
name was pointing to. But, now, you are asking value to reference a
different object.
So, in summary, upcase! mutates the object while = will re-assign.
You can think of 3 circles, value is in one, name in another and William
in the third.
value and name both point to the string object, William.
In the first situation, you mutate the string object that both value and name
are pointing to.
In the second situation, you are creating a 4th circle, which has WILLIAM in it. Then you are erasing the line from value to William and creating a line
from value to WILLIAM.
You get the idea if I do this:
def uppercase2(value)
value = "WILLIAM"
puts value
end
name = 'William'
uppercase2(name) # => “WILLIAM”
puts name # William

How to update single key/value from dictionary in morph?

In a previous question I asked how I could show the contents of a Dictionary in a GUI. I started from this idea to build a GUI with a slightly better look and feel. It mainly consists of RectangleMorphs glued together in columns and rows (cfr. the accepted answer in my previous question).
The problem now is that I would like my table to be updated when elements are added/removed/edited in my dictionary. I managed to write some Morph that consists of columns of CellMorphs, which inherit from RectangleMorph and have model and message as instance variables with the following update message:
update
" update the contents of this cell "
| value |
self removeAllMorphs.
(model = nil or: message = nil)
ifTrue: [ value := '' ]
ifFalse: [ value := model perform: message ].
self addMorph: value asMorph.
As can be seen, the CellMorph is a container for a Morph containing the actual content of the cell. This works great for displaying the size of the dictionary for instance:
d := Dictionary new.
d at: 'foo' put: 100.
d at: 'bar' put: 200.
cell := CellMorph new
model: d;
message: #size;
color: Color white.
cell openInWorld.
d at: 'boo' put: 300. " cell will be updated "
but I don't seem to get something similar working for the contents of the dictionary, because I can't find a way to access single keys or values with a message. The only solution I can think of is to create new columns with new cells every time, but this is so expensive and I can't imagine that this is a good idea...
Therefore my question:
Is there a way to update my Morph displaying the dictionary without creating billions of my CellMorphs or should I forget about my idea and rather work with rows of CellMorphs for instance in order to group the entries in the dictionary?
for completeness: the model: message in CellMorph looks like:
model: newModel
"change the model behind this cell"
model ifNotNil: [ model removeDependent: self ].
newModel ifNotNil: [newModel addDependent: self].
model := newModel.
self update.
update: aParameter does nothing more than call update. and I also added self changed. in all messages of Dictionary that I want the interface to be notified of (at: put:, removeKey:, etc.).
In the instance variable named 'message' you could have a Message object, instead of having only the selector.
An instance of Message has the receiver, selector and arguments. So, you could configure it with the dictionary keys sorted asArray in the receiver, the selector #at: and an index, to get a specific key. Accessing the value would be getting the value at: that key in the dictionary.
I think that a Message is not executed with object perform: message, you should check. message perform should work because it already has the receiver.
In any case, this complexity may show that having only (one) model and (one) message is not enough to get the model in th granularity you want, and you can possibly specialize a bit more, using the knowledge that the model is a dictionary. For instance, having an instance variable for key or for keyIndex.
Some side notes about the code:
(model = nil or: message = nil)
has comparisons with nil, that can be replaced by #isNil message or, if you want to stick with equality, use the faster == to compare identity, since nil is unique.
#or: is used to get the benefits of partial evaluation (the argument is evaluated only if the receiver is false). But that only works if you have a block as argument, otherwise the expression is evaluated before, to get the argument for the message in the stack.

Using Ruby to solve a quiz

So I found this quiz on a website that I was excited to solve with my newly acquired Ruby skills (CodeAcademy, not quite finished yet).
What I want to do is make an array with 100 entries, all set to "open". Then, I planned to create a method containing a for loop that iterates through every nth entry of the array and changes it to either "open" or "closed", based on what it was before. In the for loop, n should be increased from 1 to 100.
What I have so far is this:
change_state = Proc.new { |element| element == "open" ? element = "closed" : element = "open" }
def janitor(array,n)
for i in 1..n
array.each { |element| if array.index(element) % i == 0 then element.change_state end }
end
end
lockers = [*1..100]
lockers = lockers.map{ |element| element = "closed" }
result = janitor(lockers,100)
When trying to execute I receive an error saying:
undefined method `change_state' for "closed":String (NoMethodError)
Anybody an idea what is wrong here? I kinda think I'm calling the "change_state" proc incorrectly on the current array element.
If you know the quiz, no spoilers please!
As you have implemented change_state, it is not a method of any class, and definitely not one attached to any of the individual elements of the array, despite you using the same variable name element. So you cannot call it as element.change_state.
Instead, it is a variable pointing to a Proc object.
To call the code in a Proc object, you would use the call method, and syntax like proc_obj.call( params ) - in your case change_state.call( element )
If you just drop in that change, your error message will change to:
NameError: undefined local variable or method `change_state' for main:Object
That's because the change_state variable is not in scope inside the method, in order to be called. There are lots of ways to make it available. One option would be to pass it in as a parameter, so your definition for janitor becomes
def janitor(array,n,state_proc)
(use the variable name state_proc inside your routine instead of change_state - I am suggesting you change the name to avoid confusing yourself)
You could then call it like this:
result = janitor(lockers,100,change_state)
Although your example does not really need this structure, this is one way in which Ruby code can provide a generic "outer" function - working through the elements of an array, say - and have the user of that code provide a small internal custom part of it. A more common way to achieve the same result as your example is to use a Ruby block and the yield method, but Procs also have their uses, because you can treat them like data as well as code - so you can pass them around, put them into hashes or arrays to decide which one to call etc.
There may be other issues to address in your code, but this is the cause of the error message in the question.

Bang methods in Groovy

Does Groovy have something similar to bang methods on Ruby?
From this blog post:
In Ruby, you can write methods whose names end in ! (exclamation point or “bang”). There’s a lot of confusion surrounding the matter of when, and why, you would want to do so.
The ! in method names that end with ! means, “This method is dangerous”—or, more precisely, this method is the “dangerous” version of an otherwise equivalent method, with the same name minus the !. “Danger” is relative; the ! doesn’t mean anything at all unless the method name it’s in corresponds to a similar but bang-less method name.*
And this site:
You'll find a number of pairs of methods, one with the bang and one without. Those without the bang perform an action and return a freshly minted object, reflecting the results of the action (capitalizing a string, sorting an array, and so on). The bang versions of the same methods perform the action, but they do so in place: Instead of creating a new object, they transform the original object.
This is not a convention in Groovy like it is in Ruby. However you can write methods with names that contain characters like ! with the limitation that it must always be quoted like a string:
// define method with quoted name
def 'dangerous!'() {
// do something dangerous
}
// invoke method with quoted name
'dangerous!'()
No, groovy (currently as of v2.1.4) doesn't have anything like this
To add to your options, another solution that would be more Groovy-like or Java-like would be to include an optional parameter that enabled in-place (a.k.a. dangerous) modification, like so:
def processFoo(Foo item, mutate = false) {
if(!mutate) {
Foo temp = new Foo()
// copy item properties
item = temp
}
item.bar = 'blah blah'
// process item here
return item
}
processFoo(myFoo) // makes a copy
processFoo(myFoo, true) // modifies original
This pattern is used — albeit in the opposite manner — with the sort method on collections. Calling sort(false) on Lists prevents changing the original array. Calling sort() or sort(true) will modify it directly.

ruby method with for loop, unexpected return

I have a model MyModel with a method to return a specific record (see logic below).
def self.find_future_rec #note2
rec = find(rand(MyModel.count)+1) #note1
while rec.nil? | (rec.expdate<Date.today)
rec = find(rand(MyModel.count)+1)
end
return rec
end
Every record of MyModel class has a variable expdate of Date class. (I know this is a horrible way to find a record, this is more for my own edification and also some test code.)
This method will iterate through several undesirable records before finding an appropriate record, but the record returned is always the one found at note 1, the first record queried. Is there some lazy assignment thing going on here?
I had to add self at note2 to be able to call the method in a static context. Is this the correct interpretation?
The find method never returns nil when you give it a single ID to find: if it can't find the record you're asking for, it raises an ActiveRecord::RecordNotFound exception. So, rec is always non-nil and rec.nil? is always false. That means that your loop is really like this:
while rec.expdate < Date.today
If your loop is always returning the rec from #note1 then you're never entering the while loop at all and you're always getting a desirable MyModel on the first try.
Other points to consider:
Sometimes things get deleted so Model.count + 1 is not necessarily the maximum ID.
find raises an exception to indicate failure so you need to rescue ActiveRecord::RecordNotFound rather than check for nil.
You are using | which is a boolean OR. Try using or or ||.
Adding self to make a method a class method ("static" is a decent approximation) is indeed one of the correct ways to approach this.

Resources