Change deep_merge to Utils.deep_merge_hashes - ruby

I am using Octopress to generate static html pages. I tried to change the language of the dates using this instruction (it is in German but we need only the code). When I copy date.rb from this German website to my octopress/plugins, I have the following error: Liquid Exception: undefined method `deep_merge' for # in blog/path/to/post/index.html.
I can generate site if I comment out this part in date.rb:
def to_liquid
date_format = self.site.config['date_format']
self.data.deep_merge({
"title" => self.data['title'] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
"url" => self.url,
"date" => self.date,
# Monkey patch
"date_formatted" => format_date(self.date, date_format),
"updated_formatted" => self.data.has_key?('updated') ? format_date(self.data['updated'], date_format) : nil,
"id" => self.id,
"categories" => self.categories,
"next" => self.next,
"previous" => self.previous,
"tags" => self.tags,
"content" => self.content })
end
Then the language is changed for the dates in blog/archives, but not for the dates in posts. I found a similar problem which has been solved by changing deep_merge → Utils.deep_merge_hashes. So I understand that I need to do exactly the same in the piece of the code I presented above. I think it should be quite easy, but since I don't know Ruby, I didn't succeed yet. Could you please tell me how should I use Utils.deep_merge_hashes instead of deep_merge in this case?

This works (ruby 2.1.1 - Jekyll 2.5.3)
def to_liquid(attrs = nil)
date_format = self.site.config['date_format']
new_datas = {
"title" => self.data['title'] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
"url" => self.url,
"date" => self.date,
# Monkey patch
"date_formatted" => format_date(self.date, date_format),
"updated_formatted" => self.data.has_key?('updated') ? format_date(self.data['updated'], date_format) : nil,
"id" => self.id,
"categories" => self.categories,
"next" => self.next,
"previous" => self.previous,
"tags" => self.tags,
"content" => self.content }
Utils.deep_merge_hashes(self.data, new_datas)
end

Related

I for some reason can't get this iteration thing right in my head

Once again I am a new student to this whole computer coding thing and I am doing a boot camp to try to get the basics and my foot in the door but for some reason I can't make this whole iteration thing stick in my brain we just started doing hashes in ruby and I have literally been staring at the checkpoint problem for a day and a half and I just can't make my brain know what the next logical step is to get the answer provided. It is in a pre work section before my actual live classes start here in a few weeks and it's only my second full week doing any coding at all so the most bare bones basic hints/answers would be greatly appreciated.
This is the problem:
Write a loop to give each person an email address that consists of their first name + last name # gmail.com. For example, Robert Garcia will have an email of robertgarcia#gmail.com. The program should end with: p people
people = [
{
"first_name" => "Robert",
"last_name" => "Garcia",
"hobbies" => ["basketball", "chess", "phone tag"]
},
{
"first_name" => "Molly",
"last_name" => "Barker",
"hobbies" => ["programming", "reading", "jogging"]
},
{
"first_name" => "Kelly",
"last_name" => "Miller",
"hobbies" => ["cricket", "baking", "stamp collecting"]
}
]
outer_index = 0
names = []
last_names = []
while outer_index < people.length
names << people[outer_index]["first_name"].downcase
last_names << people[outer_index]["last_name"].downcase
outer_index += 1
end
email = email = [names[0] + last_names[0] + "#gmail.com"]
this is all the farther I have gotten because everything I've tried to get it to go back trough and pick up the second and third names hasn't worked.
According to them this is what it is supposed to look like in the end:
so that you can see if the correct modifications were made to each hash. The result should be:
people =[
{
"first_name" => "Robert",
"last_name" => "Garcia",
"hobbies" => ["basketball", "chess", "phone tag"],
"email" => "robertgarcia#gmail.com"
},
{
"first_name" => "Molly",
"last_name" => "Barker",
"hobbies" => ["programming", "reading", "jogging"],
"email" => "mollybarker#gmail.com"
},
{
"first_name" => "Kelly",
"last_name" => "Miller",
"hobbies" => ["cricket", "baking", "stamp collecting"],
"email" => "kellymiller#gmail.com"
}
]
(Note that your output won't be indented nicely).
I am completely at a loss and I cannot see where I am going wrong so any help would be insanely helpful so I can get through this checkpoint and finish up week two and move on to week three asap.
It's pretty straightforward to loop over each element of the people array. We also can use string interpolation to easily compose the email address.
people.each do |h|
h["email"] = "#{h["first_name"]}#{h["last_name"]}#gmail.com".downcase
end
If we want to break this up a bit, we can.
people.each do |h|
fn = h["first_name"]
ln = h["last_name"]
h["email"] = "#{fn}#{ln}#gmail.com"
h["email"].downcase!
end
You're really overcomplicating it, there is no need to use while to simply loop across an array. Instead use #each from the Enumerable module:
people.each do |hash|
hash.merge!(
"email" => "#{hash['first_name']}#{hash['last_name']}#gmail.com".downcase
)
end
Or if you want a non-destructive version that doesn't alter the original data:
people.map do |hash|
hash.merge(
"email" => "#{hash['first_name']}#{hash['last_name']}#gmail.com".downcase
)
end

Elegantly return value(s) matching criteria from an array of nested hashes - in one line

I have been searching for a solution to this issue for a couple of days now, and I'm hoping someone can help out. Given this data structure:
'foo' => {
'bar' => [
{
'baz' => {'faz' => '1.2.3'},
'name' => 'name1'
},
{
'baz' => {'faz' => '4.5.6'},
'name' => 'name2'
},
{
'baz' => {'faz' => '7.8.9'},
'name' => 'name3'
}
]
}
I need to find the value of 'faz' that begins with a '4.', without using each. I have to use the '4.' value as a key for a hash I will create while looping over 'bar' (which obviously I can't do if I don't yet know the value of '4.'), and I don't want to loop twice.
Ideally, there would be an elegant one-line solution to return the value '4.5.6' to me.
I found this article, but it doesn't address the full complexity of this data structure, and the only answer given for it is too verbose; the looping-twice solution is more readable. I'm using Ruby 2.3 on Rails 4 and don't have the ability to upgrade. Are there any Ruby gurus out there who can guide me?
You can use select to filter results.
data = {'foo' => {'bar' => [{'baz' => {'faz' => '1.2.3'}, 'name' => 'name1'}, {'baz' => {'faz' => '4.5.6'}, 'name' => 'name2'}, {'baz' => {'faz' => '7.8.9'}, 'name' => 'name3'}]}}
data.dig('foo', 'bar').select { |obj| obj.dig('baz', 'faz').slice(0) == '4' }
#=> [{"baz"=>{"faz"=>"4.5.6"}, "name"=>"name2"}]
# or if you prefer the square bracket style
data['foo']['bar'].select { |obj| obj['baz']['faz'][0] == '4' }
The answer assumes that every element inside the bar array has the nested attributes baz -> faz.
If you only expect one result you can use find instead.

How to transform a user input in rails 4?

I am creating an app where users could enter their name that will be returned as chemical symbols (when matching).
So I managed to do in the console like:
symbols = {
"ac" => "Ac",
"al" => "Al",
"am" => "Al",
"br" => "Br",
"ba" => "Ba",
"cr" => "Cr"
}
puts "Get your chemical name!"
name = gets.chomp
name.gsub!(/#{symbols.keys.join('|')}/, symbols)
puts name
Now I'd like to make it works in the app but I don't know how to create the method ?
I want it to be displayed only in the views/show
= #convertor.name
= link_to 'Edit', edit_convertor_path(#convertor)
= link_to 'Back', convertors_path
shall I create the method in my model or else where?
class Convertor < ActiveRecord::Base
def get_chemical_name(name)
symbols = {
"ac" => "Ac",
"al" => "Al",
"am" => "Al",
"br" => "Br",
"ba" => "Ba",
"cr" => "Cr"
}
name.gsub!(/#{symbols.keys.join('|')}/, symbols)
puts name
end
end
so in my view showI tried something like =#convertor.get_chemical(name) but unsuccessful..
I need your help please
Yes, the method can stay in the model.
Short one:
#convertor.get_chemical(#convertor.name)
would work but this is not a right way to do that.
Correct way would be to change the method in Convertor class to not accept any arguments, since it is an instance method and it already has access to name attribute. So, after changing the method signature
def get_chemical_name
symbols = {
"ac" => "Ac",
"al" => "Al",
"am" => "Al",
"br" => "Br",
"ba" => "Ba",
"cr" => "Cr"
}
name.gsub!(/#{symbols.keys.join('|')}/, symbols)
end
you will be able to use
=#convertor.get_chemical_name
Also, I removed useless puts name from the method definition - in Ruby the last evaluated line is already a return value of the method (unless returned before the end of the method).
Also, if by any chance you are using the symbols hash anywhere else, you can move it to constant.

rails + activerecord: how create a hash from table with particular field's value as key

Given a table ZipCodeInfos with fields zipcode, state, city (all strings), where zipcode is unique:
zipcode,city,state
"10000", "Fooville", "AA"
"10001", "Smallville", "AA"
"10002", "Whoville", "BB"
What is the fastest way to generate a hash object of the entire table where the zipcode is a key like this:
{ "10000" => {:city => "Fooville", :state => "AA" },
"10001" => {:city => "Smallville", :state => "AA" },
"10002" => {:city => "Whoville", :state => "BB" } }
I know for a given record I can use .attributes to generate a hash with key,value pairs of field-names, field-values, for example Zipcode.first.attributes gives me
{"id" => 1, "zipcode" => "10000", "city" => "Fooville", "state => "AA" }
But, short of brute force iterating over each record (via .map), I cannot quite figure out how to create the desired hash with the zipcode as the key for each node of the hash.
This is the best I could come up with, and I suspect there is some nifty Ruby goodness that is faster?
zip_info_hash = {}
ZipCodeInfo.all.map{|x| zip_info_hash[x.zip] =
{'state' => x.state, 'city' => x.city }}
You could also try:
ZipCodeInfos.all.group_by &:zipcode
will get you a hash of zip code to array of ZipCodeInfos activerecords.
You can use inject method.
Here is what I generally use.
def visitors_name_email
visitors.inject({}) do |result, visitor|
result.merge(visitor.name => visitor.email)
end
end
I can't think of a way to avoid map here. I'd make only some minor changes to your code:
zip_info=Hash[*ZipCodeInfo.all
.map{|x| [x.zip, {:city => x.city, :state => x.state}]}
.flatten]

How do I extract the hash from an array of one hash?

I'm writing an API parser at the moment, and I'm working on formatting the data nicely.
So far, I have the following code:
data.each {|season| episodes[season["no"].to_i] = season["episode"].group_by{|i| i["seasonnum"].to_i}}
However, the only issue with this is that the output comes out like this:
8 => {
1 => [
[0] {
"epnum" => "150",
"seasonnum" => "01",
"prodnum" => "3X7802",
"airdate" => "2012-10-03",
"link" => "http://www.tvrage.com/Supernatural/episodes/1065195189",
"title" => "We Need to Talk About Kevin"
}
],
2 => [
[0] {
"epnum" => "151",
"seasonnum" => "02",
"prodnum" => "3X7803",
"airdate" => "2012-10-10",
"link" => "http://www.tvrage.com/Supernatural/episodes/1065217045",
"title" => "What's Up, Tiger Mommy?"
}
]
}
So there's a redundant array in each value of the secondary hash. How would I remove this array and just have the inside hash? So, for example I want:
8 => {
1 => {
"epnum" => "150",
"seasonnum" => "01",
"prodnum" => "3X7802",
"airdate" => "2012-10-03",
"link" => "http://www.tvrage.com/Supernatural/episodes/1065195189",
"title" => "We Need to Talk About Kevin"
}
,
etc.
EDIT: Here's the full file:
require 'httparty'
require 'awesome_print'
require 'debugger'
require 'active_support'
episodes = Hash.new{ [] }
response = HTTParty.get('http://services.tvrage.com/feeds/episode_list.php?sid=5410')
data = response.parsed_response['Show']['Episodelist']["Season"]
data.each { |season|
episodes[season["no"].to_i] = season["episode"].group_by{ |i|
i["seasonnum"].to_i
}
}
ap episodes
Input data: http://services.tvrage.com/feeds/episode_list.php?sid=5410
Wild guess:
data.each { |season|
episodes[season["no"].to_i] = season["episode"].group_by{ |i|
i["seasonnum"].to_i
}.first
}
It looks like you're using group_by (array of entries with same key) when you really want index_by (one entry per key).
data.each {|season| episodes[season["no"].to_i] = season["episode"].index_by {|i| i["seasonnum"].to_i}}
NOTE: If you can have MORE than one episode with the same seasonnum, you SHOULD use group by and have an array of values here. If you're just building a hash of episodes with a convenient lookup (one to one mapping), then index_by is what you want.

Resources