I have two hashes as so:
deploy = {}
config[:mysql] = {}
I also have a function as so:
def some_cool_function(mysql_config)
{
foo:bar
}
end
When I call the function and assign the results to a hash as so:
deploy.mysql = some_cool_function(config.mysql)
I get NoMethodError: undefined method mysql for #<Hash:0x000055a0f2929f58>
It's possible the hash mysql just doesn't exist in the config hash, but i haven't investigated that option yet.
It looks right to me though, am I doing something incorrectly? I'm fairly new to the ruby language.
Related
I am trying to get the value of a key and trying to store it in an array
Below is the sample code,
require 'rubygems'
require 'json'
opt=[]
response_assigned = {
"poll_id": 1194
}
opt << [JSON.parse(response_assigned)['poll_id']]
By using ruby, I have tried to convert poll_id variable into string,
opt << [JSON.parse(response_assigned)['poll_id'].to_s,channel_id]
but it is throwing same error.
'convert_encoding': {:poll_id=>1194} is not like a string (TypeError)
response_assigned is already a Hash. You can access the values via :[]; there's no need to use JSON.parse here. (This method is used for converting JSON strings into hashes, like the object you already have!)
Also, a more subtle note: There are two distinct types of object in ruby: String and Symbol.
By defining your object like this: {"poll_id": 1194}, you have made the hash key a symbol. It's equivalent to writing this: {poll_id: 1194}, or this: {:poll_id => 1194}.
Therefore, in order to access the value, you can use:
opt << response_assigned[:poll_id]
If you want to make the hash key a String instead of a Symbol, you could write:
response_assigned = {
"poll_id" => 1194
}
opt << response_assigned["poll_id"]
Given an array of hashes I want to check if each one contains a certain key and value. The following did NOT work:
it { expect(some_array).to all( have_attributes(:some_key => 'some_value') ) }
I could not tell from the match error why it didn't work but I think it's something to do with expectations have_attributes has about the input arguments or environment.
Make a custom matcher as follows:
RSpec::Matchers.define :have_member_with_value do |expected_key, expected_value|
match do |actual|
actual[expected_key] == expected_value
end
end
Usage:
it { expect(some_array).to all( have_member_with_value(:some_key, "some_value") ) }
Sadly I'm not sure why the approach in the question does not work.
I think the assertion does not work because have_attributes does not work with plain ruby hash keys. You can't access hash keys the same as attributes if you're using a vanilla Ruby hash.
Consider:
a = OpenStruct.new(hello: 'you')
b = { hello: 'you' }
a.hello # this is an attribute automatically defined via OpenStruct
=> "you"
b.hello # this is a regular ol' key
NoMethodError: undefined method `hello' for {:hello=>"you"}:Hash
from (pry):79:in `<main>'
I believe the matcher would work if the object you were working with had the attribute accessor for whatever key-value you were looking for. Ex. If you had an array of OpenStructs, using both match_array and have_attributes would work. These are usually available automatically via metaprogramming if you're using a fancy library like ActiveRecord or OpenStruct.
Otherwise, you have to define these attributes yourself, or assert on the hash key rather than the attribute.
I would probably do something like this:
it do
expect(subject.body.map { |elem| elem[:some_key] }).to all( eq "some_value" ) }
end
I would loop through subject.body and write the expectation within the loop
e.g
subject.body.each do |entry|
it { expect(entry[:some_key]).to eq "some_value"}
end
I have a context for the session of what I'm doing. Like so:
class Context
CONTAINS = {}
end
I've been using it successfully like so:
Context::CONTAINS[:alpha] = "exampleA"
Context::CONTAINS[:beta] = "exampleB"
However :alphamight not contain anything some of the times the code runs. I was trying to iterate through it all by doing:
Context::CONTAINS.each { |x| puts x }
But that isn't working I get:
-:8:in `[]=': can't convert Symbol into Integer (TypeError)
I can't figure out how to iterate through it to just retrieve the :keys that actually have something and use them.
Use each_keys. It's the ruby-way of doing it, though you can also use each
Context::CONTAINS.each_key { |k|
puts k.to_s
}
to_s converts symbol to string.
Context::CONTAINS.keys is just another alias for each_key
I know that in Ruby you can create hash maps like this:
hash = {"name"=>"John"}
But is it possible to have a hash map of methods:
hash = {"v"=> show_version}
and when calling hash["v"] either to execute the show_version function, or to return some kind on pointer that passed to some special method, to execute the function from the hash?
What I am trying to achieve, is to have a hash map of methods, instead of using a case/when construction, as it looks too verbose to me.
Not exactly like this, no. You need to get a hold of the Method proxy object for the method and store that in the Hash:
hash = { 'v' => method(:show_version) }
And you need to call the Method object:
hash['v'].()
Method duck-types Proc, so you could even store simple Procs alongside Methods in the Hash and there would be no need to distinguish between them, because both of them are called the same way:
hash['h'] = -> { puts 'Hello' }
hash['h'].()
# Hello
I mean, I don't declare
my_var = new variable
or something like that.
I just go with
my_var = 1;
Similarly, why can't I just
books["War and peace"] = :masterpiece
Why I need to define in advance?
books = {}
books["War and peace"] = :masterpiece calls the []= method on books with "War and peace" and :masterpiece as its arguments. If books doesn't exist, you can't call a method on it.
Or to approach the question a different way: If ruby did do some magic to automatically initialize variables, when you use []= on them, how should ruby know that you want books to be a hash in the above example? Any class can have [] and []= operators which accept strings as an index.
Doing:
my_var = 1
Is defining and assigning the local variable. With a hash it could be done like this:
books = { 'War and Peace' => :masterpiece }