Easiest Way to Print Non-Strings in Ruby - ruby

I'm constantly doing this
puts “The temperature is “ + String(temperature) + “.”
in my debugging code, and another option is to use interpolation
puts “The temperature is #{temperature}.”
is there any less cumbersome way to do this?
Edit: This is just for debugging, if that matters.

None that are all that worthwhile for small cases like that.
Though, you should prefer interpolation as it's less expensive than concatenation.

The best way to insert dynamic variables into strings is
#interpolation
"foo #{my_var} bar"
It will call the to_s method on whatever object the expression returns and insert that string. It really the same as
#concatenation
"foo " + my_var.to_s + " bar"
But, as wfarr metioned, its faster to do interpolation. Easier to read too.

A slightly different approach is to use assertions in automated tests.
For example using Test::Unit :-
assert_equal 25, temperature
I find that using automated tests dramatically cuts down on the amount of debugging code I have to write.

Use Kernel#p
p temperature #=> 10.25
When I'm debugging, I often label such statements just by copying the line, and using inserting a colon, making the variable into a symbol.
p :attributes #=> :attributes
p attributes #=> { :mood => "happy", 5 => [] }
Or
p [:location, location] #=> [ :location, "# work" ]
Note that Kernel#p calls #inspect on its arguments, instead of #to_s, but this normally provides more useful debugging info anyway.

I highly recommend to use irbtools gem which includes awesome_print or just awesome_print.
I personally find it faster and less cumbersome to use in dev, then using interpolated strings, thou sometimes that's the only way to go.
You can do this on any object and it will give you a nicely formatted otput be that array, string or hash or even any other complex object that you may have - like 3-dimentional array printted as a tree structure. In order to have it awailable in your rails env - just include it in the Gemfile in the development group, or add it to .irbrc - to always have it in your irb console. Then just do
require "awesome_print"
ap MyGreatObject
here is a sample output from one of my projects
ap Address
class Address < ActiveRecord::Base {
:id => :integer,
:address_line_1 => :string,
:address_line_2 => :string,
:address_line_3 => :string,
:city => :string,
:state => :string,
:zip => :string,
:country => :string,
:attn => :string,
:category_id => :integer,
:addressable_id => :integer,
:addressable_type => :string,
:created_at => :datetime,
:updated_at => :datetime
}
ap Address.first
Address Load (1.0ms) SELECT `addresses`.* FROM `addresses` LIMIT 1
#<Address:0x7bc5a00> {
:id => 1,
:address_line_1 => "1 Sample Drive",
:address_line_2 => nil,
:address_line_3 => nil,
:city => "Chicago",
:state => "IL",
:zip => "60625",
:country => "USA",
:attn => nil,
:category_id => 1,
:addressable_id => 1,
:addressable_type => "Warehouse",
:created_at => Tue, 10 Jan 2012 14:42:20 CST -06:00,
:updated_at => Tue, 17 Jan 2012 15:03:20 CST -06:00
}

There's always the possibility to use printf style formatting:
"The temperature is %s" % temperature
This would allow for finer formatting of numbers, etc. as well. But honestly, how much less "cumbersome" than using #{} interpolation can you expect to get?

Another way is to do something stupid like this:
"The temperature is %s." % temperature.to_s
Personally I'd use interpolation

Related

Isolating and displaying a specific element within a hash

I am currently having trouble writing a test that addresses the eligibility_settings of a record I have. I am having trouble pulling out one of the specific elements from this hash.
Specifically I want to test that by making a change elsewhere in a different function that changes the min age of a specific player, and so what I am really trying to test is the eligibility_settings.min_age. But i'm having trouble within my test isolating that out.
My hash looks like this
{
:name => "player1",
:label => "redTeam_1_1",
:group => "adult",
:teamId => 7,
:eligibility_settings => {
"min_age" => 18,
"player_gender" => "female",
"union_players_only" => true
}
}
However when I try looping through this hash, I am having trouble isolating that one element.
i've tried something like
team.get_players.first.map do |settings, value|
value.tap do |x, y|
y[3]
end
end
However It seems like what i've been trying, and my approach has not been working quite right.
Would anyone have any idea what I could do with this?
Although #SergioTulentsev gave the proper response, in the future if you are going to be looping through hashes, below is one way to iterate through the keys and grab the value you want.
hash = {
:name => "player1",
:label => "redTeam_1_1",
:group => "adult",
:teamId => 7,
:eligibility_settings => {
"min_age" => 18,
"player_gender" => "female",
"union_players_only" => true
}
}
hash.map do |settings, value|
p hash[:eligibility_settings]['min_age'] if settings == :eligibility_settings
end # output 18

An efficient way of custom tag parsing in ruby

I have a hash like:
{:name => 'foo', :country => 'bar', :age => 22}
I also have a string like
Hello ##name##, you are from ##country## and your age is ##age##. I like ##country##
Using above hash, I want to parse this string and substitute the tags with corresponding values. So after parsing, the string will look like:
Hello foo, you are from bar and your age is 22. I like bar
Do you recommend taking help of regex to parse it? In that case if I have 5 values in the hash, then I would have to traverse through string 5 times and each time parsing one tag. I don't think that is a good solution. Is there any better solution?
Here is my solution to the problem:
h = {:name => 'foo', :country => 'bar', :age => 22}
s = "Hello ##name##, you are from ##country## and your age is ##age##. I like ##country##}"
s.gsub!(/##([a-zA-Z]*)##/) {|not_needed| h[$1.to_sym]}
It generally makes a single pass using regex and does the replacement I think you need.
It looks like there is a solution depending on what version of ruby you are using. For 1.9.2 you can use a hash, shown here: https://stackoverflow.com/a/8132638/1572626
The question is generally similar, though, so read the other comments as well: Ruby multiple string replacement
You can use String#gsub with a block:
h = {:name => 'foo', :country => 'bar', :age => 22}
s = 'Hello ##name##, you are from ##country## and your age is ##age##. I like ##country##'
s.gsub(/##(.+?)##/) { |match| h[$1.to_sym] }

Is there a way to tell Psych in ruby to using inline mode?

environment: ruby1.9.3 , psych(any version)
ex:
o = { 'hash' => { 'name' => 'Steve', 'foo' => 'bar' } }
=> {"hash"=>{"name"=>"Steve", "foo"=>"bar"}}
#is there a inline option?
puts Psych.dump(o,{:inline =>true})
real result:
---
hash:
name: Steve
foo: bar
expect output:
---
hash: { name: Steve, foo: bar }
Psych supports this, although it isn't at all straightforward.
I've started researching this in my own question on how to dump strings using literal style.
I ended up devising a complete solution for setting various styles for specific objects, including inlining hashes and arrays.
With my script, a solution to your problem would be:
o = { 'hash' => StyledYAML.inline('name' => 'Steve', 'foo' => 'bar') }
StyledYAML.dump o, $stdout
The representable gem provides this in a convenient OOP style.
Considering you have a model User:
user.name => "Andrew"
user.age => "over 18"
You'd now define a representer module to render/parse User instances.
require 'representable/yaml'
module UserRepresenter
include Representable::YAML
collection :hash, :style => :flow
def hash
[name, age]
end
end
After defining the YAML document you simply extend the user instance and render it.
user.extend(UserRepresenter).to_yaml
#=> ---
hash: [Andrew, over 18]
Hope that helps, Andrew!

Question on Ruby collect method

I have an array of hashes
Eg:
cars = [{:company => "Ford", :type => "SUV"},
{:company => "Honda", :type => "Sedan"},
{:company => "Toyota", :type => "Sedan"}]
# i want to fetch all the companies of the cars
cars.collect{|c| c[:company]}
# => ["Ford", "Honda", "Toyota"]
# i'm lazy and i want to do something like this
cars.collect(&:company)
# => undefined method `company'
I was wondering if there is a similar shortcut to perform the above.
I believe your current code cars.collect{|c| c[:company]} is the best way if you're enumerating over an arbitrary array. The method you would pass in via the & shortcut would have to be a method defined on Hash since each object in the array is of type Hash. Since there is no company method defined for Hash you get the "undefined method 'company'" error.
You could use cars.collect(&:company) if you were operating on an Array of Cars though, because each object passed into the collect block would be of type Car (which has the company method available). So maybe you could modify your code so that you use an array of Cars instead.
You could convert the hashes to OpenStructs.
require 'ostruct'
cars = [{:company => "Ford", :type => "SUV"},
{:company => "Honda", :type => "Sedan"},
{:company => "Toyota", :type => "Sedan"}]
cars = cars.map{|car| OpenStruct.new(car)}
p cars.map( &:company )
#=> ["Ford", "Honda", "Toyota"]
It's impossible to use in your case, because in collect you use method [] and argument :company. The construction &:company takes labels :company and converts to Proc, so it's only one argument - the name of method.
Unfortunately Ruby hashes can't do that. Clojure maps on the other hand have functions for each key which return the corresponding value, which would be easy enough to do if you are so inclined (you should also add the corresponding respond_to? method):
>> class Hash
.. def method_missing(m)
.. self.has_key?(m) ? self[m] : super
.. end
.. end #=> nil
>> cars.collect(&:company) #=> ["Ford", "Honda", "Toyota"]
>> cars.collect(&:compay)
NoMethodError: undefined method `compay' for {:type=>"SUV", :company=>"Ford"}:Hash
Note: I'm not advising this, I'm just saying it's possible.
Another horrible monkeypatch you shouldn't really use:
class Symbol
def to_proc
if self.to_s =~ /bracket_(.*)/
Proc.new {|x| x[$1.to_sym]}
else
Proc.new {|x| x.send(self)}
end
end
end
cars = [{:company => "Ford", :type => "SUV"},
{:company => "Honda", :type => "Sedan"},
{:company => "Toyota", :type => "Sedan"}]
cars.collect(&:bracket_company)

Deleting EmbeddedDocuments with Mongo Mapper

I have mongo_mapper set up like so:
class Person
include MongoMapper::Document
many :pets
end
class Pet
include MongoMapper::EmbeddedDocument
key :animal, String
key :name, String
key :colour, String
end
# Create a person
me = Person.new
# Add pets to the person
me.pets << Pet.new(:animal => 'dog',:name => 'Mr. Woofs', :colour => 'golden')
me.pets << Pet.new(:animal => 'cat', :name => 'Kitty', :colour => 'black')
me.pets << Pet.new(:animal => 'cat', :name => 'Freckles', :colour => 'black')
me.pets << Pet.new(:animal => 'cat', :name => 'Fluffy', :colour => 'tabby')
I know I can delete all pets very simply (me.pets works as an array but also calls back)
# Delete all pets
me.pets.clear
I also know that I could delete all black cats by doing this:
# Delete black cats
me.pets.delete_if {|pet| pet.animal == 'cat' and pet.colour = 'black'}
But that seems like it'll take a very long time if there are a large number of pets to iterate through.
I feel like there should be a way to select only the black cats and then clear that array instead. Is there such a way?
try something like this, no idea if this'll work but worth a shot.
me.pets.all(:animal => "cat", :colour => "black").clear
To be honest though I think you are worrying about this for nothing. Usually array manipulation are plenty fast.

Resources