Rails: Number to currency, delete trailing zeros - ruby-on-rails

How can I use number_to_currency and make it delete the zeros in the decimal part?
So if I have a number 30.50, I want to keep the .50, but if I have 30.00, I want to delete those zeros. I see the precision, but I don't know if I can use it conditionally to just be applied if the trailing decimals are zeros...
Thanks

num = 30.00
number_to_currency(num, :precision => (num.round == num) ? 0 : 2)
=> $30
num = 30.05
number_to_currency(num, :precision => (num.round == num) ? 0 : 2)
=> $30.05

I use money strings , so I do it a different way :
def string_to_cents str
new_str = number_to_currency(str, :format => "%n")
if new_str && new_str[-3..-1] == ".00"
new_str[-3..-1] = ""
end
new_str
end

Related

Does there exist a gem to parse human numbers?

There is a helper #number_to_human to print large numbers, but is there an opposite helper to parse large numbers, similar to strtotime()?
No specific search results. Ruby Toolbox is dead.
A bonus would be to accept a locale, to handle , and ..
I would like to parse things like
$1m
$15 million
999 thousand
$999k
$111 M
1,234,567.89
€987.654,00
$1.1 billion
I found something and customized it.
def human_to_number(human)
return human unless human.is_a? String
return human if human.blank? # leave '' as is
human.downcase!
if human.index('k') || human.index('thousand')
multiplier = 1000
elsif human.index('m')
multiplier = 1_000_000
elsif human.index('b')
multiplier = 1_000_000_000
elsif human.index('t')
multiplier = 1_000_000_000_000
else
multiplier = 1
end
number = human.gsub(/[^0-9\.]/,'').to_f
number = number * multiplier
end
irb(main):003:0> d.human_to_number '$1.2 million'
=> 1200000.0
irb(main):004:0> d.human_to_number '$1.2 billion'
=> 1200000000.0
irb(main):005:0> d.human_to_number '$1.2k'
=> 1200.0
irb(main):006:0> d.human_to_number '1.2k'
=> 1200.0
irb(main):007:0> d.human_to_number '555.66k'
=> 555660.0

How remove an extra space in string and convert to int type?

When I enter a price more than three digits, such as 1000, the js script makes the 1 000, 10 000, etc. It puts a space for the user's convenience. Validation display is not a numeric type. How convert to int type in this situation?
validates :price, numericality: { only_integer: true, allow_nil: true }
here is a slightly better solution that would still allow you to have nil values
(please note that nil.to_i is 0 as well as any "text".to_i is also 0)
def my_method(str)
Integer(str.gsub(/\s/, ''))
rescue ArgumentError => e
nil
end
Example of use:
my_method('1000')
=> 1000
my_method('1 000')
=> 1000
my_method(' ')
=> nil
my_method('some_text')
=> nil
my_method('1.000')
=> nil
my_method('1,000')
=> nil
If you want to treat . and , you can adapt the regex in gsub.
I found a solution:
2.3.0 :004 > "1 000".delete(' ')
=> "1000"
2.3.0 :005 > "1 000".delete(' ').to_i
=> 1000

Converting base-10 to base2 in Ruby using recursion (Binary converter)

I would like to convert a base10 number to base2 in Ruby without using the built in to_s(2) method, using recursion.
I wrote this:
def to_binary(d)
if d<1
return ""
else
return to_binary(d/2).to_s + (d%2).to_s
end
end
This would return all correct results EXCEPT 0. Is there any way to return 0 for 0 without having leading zeroes for numbers greater than 0?
You can modify your checks a bit:
def to_binary(d)
return d.to_s if [0,1].include?(d) # same as "if d == 0 || d == 1"
to_binary(d/2) + (d%2).to_s
end
to_binary(10) == "1010"
#=> true
to_binary(0) == "0"
#=> true
You could also write above method as:
def to_binary(d)
return d.to_s if [0,1].include?(d)
div,mod = d.divmod(2)
to_binary(div) + mod.to_s
end

Understanding Ruby script for cassandra database

I am a Ruby novice. But due to some problem I have to handle the code as our ruby developer is not available. We are using cassandra database to get values from a Ruby (Sinatra) web service and put it into the Cassandra keyspace. But due to some problem , the data is failing to insert.
In the following code partners_daily , partner_monthly etc are column family (tables) in the stats keyspace(database).
if params and !partner_id.nil? and !activity_type.nil?
{
:partners_daily => "#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
:partners_monthly => "#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}",
:partners_alltime => "#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}",
:channels_daily => "#{channel_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
:channels_monthly => "#{channel_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}",
:channels_alltime => "#{channel_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}",
:countries_daily => "#{country}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
:countries_monthly => "#{country}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}",
:countries_alltime => "#{country}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}"
}.each do |k,v|
stats.add(k, v, 1, 'count')
end
return "Activity stored in stats"
end
else
return "Error: client headers missing"
end
end
def count(table, key)
require 'cassandra-cql' # requiring this at the top was leading to error: unconfigured columnfamily
cqldb = CassandraCQL::Database.new('127.0.0.1:9160', {:keyspace => 'plystats'})
query = "update partners_daily set count = ? where key = ?"#"update #{table} set count = count+1 where key = ?;"
#return cqldb.execute(query, 0, 'sonia').inspect
return query
end
I want to know how the data inserting logic in it is being performed, and where ? Is it in stats.add(k, v, 1, 'count') ?
and is there any error in the inserting part because its failing.
I want to know how the data inserting logic in it is being performed, and where ? Is it in stats.add(k, v, 1, 'count') ?
Yes, that's where it should be happening. Between the {} are dictionary/hash values:
{
:partners_daily => # …
}.each do |k,v|
A loop is started with the each method, and each entry is decomposed and put into k and v, the key in k and the value in v. For example, the first record in the hash is:
:partners_daily => "#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
This would then decompose within the each loop to:
k = :partners_daily
v = # The result of
"#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
I don't now what the values are for partner_id etc, but making some up it'd look something like "123_sales_sucess_2013_6_01"
Notice there's a typo for the word success in there.
It's a bit confusing due to the multiple double quotes and braces, so I'd change this to:
[partner_id, activity_type, (success == 1 ? 'success' : "failure:#{failure_code}"), time.year, time.month, time.day].join("_")
But notice that there's a lot of repetition in there, so I'd change the whole hash to (at least):
success_string = success == 1 ?
'success' :
"failure:#{failure_code}"
data = {
:partners_daily => [partner_id, activity_type,success_string,time.year,time.month,time.day].join("_"),
:partners_monthly => [partner_id,activity_type,success_string,time.year,time.month].join("_"),
:partners_alltime => [partner_id,activity_type,success_string].join("_"),
:channels_daily => [channel_id,activity_type,success_string,time.year,time.month,time.day].join("_"),
:channels_monthly => [channel_id,activity_type,success_string,time.year,time.month].join("_"),
:channels_alltime => [channel_id,activity_type,success_string].join("_"),
:countries_daily => [country,activity_type,success_string,time.year,time.month,time.day].join("_"),
:countries_monthly => [country,activity_type,success_string,time.year,time.month].join("_"),
:countries_alltime => [country,activity_type,success_string].join("_")
}
data.each do |k,v|
# more code…
It starts to be easier to read and see the logic. Also, by putting the hash into the data variable instead of working on it immediately, it allows you to inspect it more easily, e.g.
warn "data = #{data.inspect}"
would output a representation of the data to the console, so at least you could get an idea of what the script is attempting to put in. At the top of this code, you could also add warn "script = #{script.inspect}" to check what the script object looks like.
If the script object is a Cassandra instance i.e. there's something like script = Cassandra.new "blah", "blahblah" that sets it up, then the add method is this one
The signature given is add(column_family, key, value, *columns_and_options) but that doesn't seem to match the call you have:
stats.add(k, v, 1, 'count')
should (probably) be:
stats.add('count', k, v, 1)
In fact, I'm not even sure that the concatenation in the data hash should happen and maybe all of that should just be passed to add, but it's your data so I can't be sure.
Feel free to comment below and I'll update this.
Trying it in IRB to check it for syntax errors:
success = 1
# => 1
partner_id = 123
# => 123
activity_type = "something"
# => "something"
time = Time.now
# => 2013-06-05 11:17:50 0100
channel_id = 456
# => 456
country = "UK"
# => "UK"
success_string = success == 1 ?
'success' :
"failure:#{failure_code}"
# => "success"
data = {
:partners_daily => [partner_id, activity_type,success_string,time.year,time.month,time.day].join("_"),
:partners_monthly => [partner_id,activity_type,success_string,time.year,time.month].join("_"),
:partners_alltime => [partner_id,activity_type,success_string].join("_"),
:channels_daily => [channel_id,activity_type,success_string,time.year,time.month,time.day].join("_"),
:channels_monthly => [channel_id,activity_type,success_string,time.year,time.month].join("_"),
:channels_alltime => [channel_id,activity_type,success_string].join("_"),
:countries_daily => [country,activity_type,success_string,time.year,time.month,time.day].join("_"),
:countries_monthly => [country,activity_type,success_string,time.year,time.month].join("_"),
:countries_alltime => [country,activity_type,success_string].join("_")
}
# => {:partners_daily=>"123_something_success_2013_6_5", :partners_monthly=>"123_something_success_2013_6", :partners_alltime=>"123_something_success", :channels_daily=>"456_something_success_2013_6_5", :channels_monthly=>"456_something_success_2013_6", :channels_alltime=>"456_something_success", :countries_daily=>"UK_something_success_2013_6_5", :countries_monthly=>"UK_something_success_2013_6", :countries_alltime=>"UK_something_success"}

How to determine if a string is a number?

What is the easiest way to find out in Rails 3 whether a string str contains a positive float number or not ? (str is not an attribute in an active-record model)
It should work like this:
str = "123" => true
str = "123.456" => true
str = "0" => true
str = "" => false
str = "abcd" => false
str = "-123" => false
Here's one idea:
class String
def nonnegative_float?
Float(self) >= 0
rescue ArgumentError
return false
end
end
However, since you already seem to have a pretty good idea of what a nonnegative float number looks like, you could also match it against a Regexp:
class String
def nonnegative_float?
!!match(/\A\+?\d+(?:\.\d+)?\Z/)
end
end
You can match it against a regular expression.
str === /^\d+(\.\d+)?$/

Resources