Forecast.io Ruby Gem - Remove Decimal from Temperature - ruby-on-rails

I am using the forecast-ruby gem and everything is working fine. However, when you get the temperature from the API, it returns it with decimals, which I don't need. (e.g., 85.23). I would like to strip the last 2 digits and just display the temperature as 85 degrees.
Here is what I am working with:
#forecast = ForecastIO.forecast(lat, long)
Then, I can check the current temp with: #forecast.currently.temperature => 85.23
Does anyone know of a way to either request just the basic temperature from the API? If not, how would I go about removing the last three characters within the method above to achieve an end result of just 85?
Thanks!

It appears that you're not dealing with characters, it's a number, so just use .round:
x = 85.23
x.round # 85
If you want to actually truncate to 85 (even if the temperature were say 85.99) then use .to_i instead.

Related

Ruby Regex for repeated numbers in a string

If i have a string like "123123123" - Here 123 is repeated 3 times.
1. So how can i get only "123" in ruby?
2. So if the string is "12312312" - Here 123 is repeated 2 times and then just 12, so here still i need to get "123".
3. Even if string is 99123123123, still i need to get 123.
Is this possible in Ruby Regex?
EDIT: I want this to solve Project Euler Problem 26 . So here 123 can be anything. All i want is to extract 1 number of at-least 2 repeated numbers.
This regex will detect all repeating groups.
(\d+)(?=.*\1)
Demo
Works great with ruby too.
result = '9912341234123'.scan(/(\d+)(?=.*\1)/)
#gets group with largest length
longestRepeatingGroup = result.max_by{|arr| arr[0].length}
puts longestRepeatingGroup
puts longestRepeatingGroup[0].length
Try this
99123123123.scan(/123/).count
12312312.scan(/123/).count

Completely random identifier of a given length

I would like to generate a completely random "unique" (I will ensure that using my model) identifier of a given (the length may varies) length containing numbers, letter and special characters
For example:
161551960578281|2.AQAIPhEcKsDLOVJZ.3600.1310065200.0-514191032|
Can someone please suggest the most efficient way to do that in Ruby on Rails?
EDIT: IMPORTANT:
If it is possible please comment on how efficient your proposed solution is because this will be used every time a user enters a website!
Thanks
Using this for an access token is a different story than UUIDs. You need not only pseudo-randomness but additionally this needs to be a cryptographically secure PRNG. If you don't really care what characters you use (they don't add anything to the security) you could use something as the following, producing a URL-safe Base64-encoded access token. URL-safeness becomes important in case you append the token to URLs, similar to what some Java web apps do: "http://www.bla.com/jsessionid=". If you would use raw Base64 strings for that purpose you would produce potentially invalid URLs.
require 'securerandom'
def produce_token(length=32)
token = SecureRandom.urlsafe_base64(length)
end
The probability of getting a duplicate is equal to 2^(-length). Since the output will be Base64-encoded, the actual output will be 4/3 * length long. If installed, this is based on the native OpenSSL PRNG implementation, so it should be pretty efficient in terms of performance. Should the OpenSSL extension not be installed, /dev/urandom will be used if available and finally, if you are on a Windows machine, CryptGenRandom would be used as fallback. Each of these options should be sufficiently performant. E.g., on my laptop running produce_tokena million times finishes in ~6s.
The best solution is:
require 'active_support/secure_random'
ActiveSupport::SecureRandom.hex(16) # => "00c62d9820d16b52740ca6e15d142854"
This will generate a cryptographically secure random string (i.e. completely unpredictable)
Similarly, you could use a library to generate UUIDs as suggested by others. In that case, be sure to use the random version (version 4) and make sure the implementation uses a cryptosecure random generator.
As anything related to security, rolling your own is not the best idea (even though I succumbed to it too, see first versions! :-). If you really want an homemade random string, here's a rewrite of tybro0103's approach:
require 'digest/sha1'
ALPHABET = "|,.!-0123456789".split(//) + ('a'..'z').to_a + ('A'..'Z').to_a
def random_string
not_quite_secure = Array.new(32){ ALPHABET.sample }.join
secure = Digest::SHA1.hexdigest(not_quite_secure)
end
random_string # => "2555265b2ff3ecb0a13d65a3d177b326733bc143"
Note that it hashes the random string, otherwise it could be subject to attack.
Performance should be similar.
Universally Unique Identifieres - UUIDs are tricky to generate yourself ;-) If you want something really reliable, use the uuid4r gem and call it with UUID4R::uuid(1). This will spit out a uuid based on time and a hardware id (the computers mac address). So it's even unique across multiple machines if generated at the exact same time.
A requirement for uuid4r is the ossp-uuid c library which you can install with the packetmanager of your choice (apt-get install libossp-uuid libossp-uuid-dev on debian or brew install ossp-uuid on a mac with homebrew for example) or by manually downloading and compiling it of course.
The advantage of using uuid4r over a manual (simpler?) implementation is that it is a) truly unique and not just "some sort of pseudo random number generator kind of sometimes reliable" and b) it's fast (even with higher uuid versions) by using a native extension to the c library
require 'rubygems'
require 'uuid4r'
UUID4R::uuid(1) #=> "67074ea4-a8c3-11e0-8a8c-2b12e1ad57c3"
UUID4R::uuid(1) #=> "68ad5668-a8c3-11e0-b5b7-370d85fa740d"
update:
regarding speed, see my (totally not scientific!) little benchmark over 50k iterations
user system total real
version 1 0.600000 1.370000 1.970000 ( 1.980516)
version 4 0.500000 1.360000 1.860000 ( 1.855086)
so on my machine, generating a uuid takes ~0.4 milliseconds (keep in mind I used 50000 iterations for the whole benchmark). hope that's fast enough for you
(following the "benchmark")
require 'rubygems'
require 'uuid4r'
require 'benchmark'
n = 50000
Benchmark.bm do |bm|
bm.report("version 1") { n.times { UUID4R::uuid(1) } }
bm.report("version 4") { n.times { UUID4R::uuid(4) } }
end
Update on heroku: the gem is available on heroku as well
def random_string(length=32)
chars = (0..9).to_a.concat(('a'..'z').to_a).concat(('A'..'Z').to_a).concat(['|',',','.','!','-'])
str = ""; length.times {str += chars.sample.to_s}
str
end
The Result:
>> random_string(42)
=> "a!,FEv,g3HptLCImw0oHnHNNj1drzMFM,1tptMS|rO"
It is a bit trickier to generate random letters in Ruby 1.9 vs 1.8 due to the change in behavior of characters. The easiest way to do this in 1.9 is to generate an array of the characters you want to use, then randomly grab characters out of that array.
See http://snippets.dzone.com/posts/show/491
You can check implementations here I used this one
I used current time in miliseconds to generate random but uniqure itentifier.
Time.now.to_f # => 1656041985.488494
Time.now.to_f.to_s.gsub('.', '') # => "16560419854884948"
this will give 17 digits number
sometime it can give 16 digits number because if last digit after point (.) is 0 than it is ignore by to_f.
so, I used rleft(17, '0')
example:
Time.now.to_f.to_s.gsub('.', '').ljust(17, '0') # => "1656041985488490"
Than I used to_s(36) to convert it into short length alphanumeric string.
Time.now.to_f.to_s.gsub('.', '').ljust(17, '0').to_i.to_s(36) # => "4j26hz9640k"
to_s(36) is radix base (36)
https://apidock.com/ruby/v2_5_5/Integer/to_s
if you want to limit the length than you can select first few digits of time in miliseconds:
Time.now.to_f.to_s.gsub('.', '').ljust(17, '0').first(12).to_i.to_s(36) # => "242sii2l"
but if you want the uniqueness accuracy in miliseconds than I would suggest to have atleast first(15) digits of time

Regex - Cost of an Item

What is the regular expression to check a cost has been provided correctly:
Number must be greater than or equal to 0.01
Number must be less than or equal to 99.99
Possible matches are:
9 | 23.3 | 25.69
Not allowed:
| 2.
Of course, the correct way would be to take the provided string, convert it to a number (catching errors if it's not a parseable number) and then compare that with the valid values.
If it has to be a regex, it's of course possible but ugly:
^(?:[1-9][0-9]?(?:\.[0-9]{1,2})?|0?.0[1-9]|0?.[1-9][0-9]?)$
Explanation:
^ # start of string
(?: # either match
[1-9][0-9]? # a number between 1 and 99
(?:\.[0-9]{1,2})? # optionally followed by a decimal point and up to two digits
| # or
0?.0[1-9] # a number between 0.01 and 0.09 (optionally without leading 0)
| # or
0?.[1-9][0-9]? # a number between 0.1 and 0.99
) # end of alternation
$ # end of string
Of course, in most regex dialects, you can use \d in place of [0-9] without a change in meaning, but I think in this case sticking to the longer version helps readability.
In Ruby, assuming your input string never contains a newline:
if subject =~ /^(?:[1-9][0-9]?(?:\.[0-9]{1,2})?|0?.0[1-9]|0?.[1-9][0-9]?)$/
# Successful match
else
# Match attempt failed
end
Since you care about the number of significant digits, another solution would be to first check if the input looks like a number, and if it passes that test, convert it to a float and check if it's in range.
^(\d{1,2}|\d{0,2}\.\d{1,2})$
would match any number (integer or decimal up to two digits after the decimal point) between 0 and 99.99. Then you just need to check whether the number is >= 0.01. The advantage of this approach is that you can easily extend the range of digits allowed before/after the decimal point if the requirements for valid numbers change, and then adjust the value check accordingly.
I am not sure you need to do this using regular expression why dont you just split the string on '|' into an array and check each element in array is greater than 0.01 and less than 99.99
A solution using a regexp would be hard to maintain since it is a very strange and unintuitive way to solve the problem. It would be hard for anyone reading your code (including yourself in a couple of weeks) to understand what the purpose of the check is.
That said, assuming values 0.00 - 99.99 are valid, the regexp could be
^\d{0,2}(\.\d\d?)?$
Assuming 0.01 - 99.99, it's a bit more complicated:
^0{0,2}(\.(0[1-9]|[1-9]\d?))?|\d{0,2}(\.\d\d)?$
And don't get me started on 0.02 - 99.98... :-)
So basically, don't do this. Convert the string to a numerical value and then do a regular interval check.
try
^\d{1,2}(\.\d{1,2})?$
it checks whether there are 1 or 2 digits and optionally if there is a dot it checks if there are 1 or 2 digits after the dot.
as answer to the comments of your question: nothing speaks against checking for the format before sending the request to a server or something else. range checks could be done somewhere else.
It's not the best but works
(0\.01|0\.02|0\.03| ... |99\.98|99\.99)
Since you're in Rails, you might be better served using validates_numericality_of in your model:
validates_numericality_of :cost, :greater_than_or_equal_to => 0.01,
:less_than_or_equal_to => 0.99
To prevent fractional pennies, use this in conjunction with validates_format_of:
validates_format_of :cost, :with => /\A\d*(\.\d{1,2})?\Z/
This leverages the strength of each validation.

Compressing a hex string in Ruby/Rails

I'm using MongoDB as a backend for a Rails app I'm building. Mongo, by default, generates 24-character hexadecimal ids for its records to make sharding easier, so my URLs wind up looking like:
example.com/companies/4b3fc1400de0690bf2000001/employees/4b3ea6e30de0691552000001
Which is not very pretty. I'd like to stick to the Rails url conventions, but also leave these ids as they are in the database. I think a happy compromise would be to compress these hex ids to shorter collections using more characters, so they'd look something like:
example.com/companies/3ewqkvr5nj/employees/9srbsjlb2r
Then in my controller I'd reverse the compression, get the original hex id and use that to look up the record.
My question is, what's the best way to convert these ids back and forth? I'd of course want them to be as short as possible, but also url-safe and simple to convert.
Thanks!
You could represent a hexadecimal id in a base higher than 16 to make its string representation shorter. Ruby has built-in support for working with bases from 2 up to 36.
b36 = '4b3fc1400de0690bf2000001'.hex.to_s(36)
# => "29a6dblglcujcoeboqp"
To convert it back to a 24-character string you could do something like this:
'%024x' % b36.to_i(36)
# => "4b3fc1400de0690bf2000001"
To achieve better "compression" you could represent the id in base higher than 36. There are Ruby libraries that will help you with that. all-your-base gem is one such library.
I recommend base 62 representation as it only uses 0-9, a-z and A-Z characters which means it is URL safe by default.
Even with base 62 representation you end up with still unwieldy 16-character ids:
'4b3fc1400de0690bf2000001'.hex.to_base_62
# => "UHpdfMzq7jKLcvyr"
Sidestepping Rails convention a bit, another compromise is to use as the "URL id" the base 32 representation of the created_at date of the object.
aCompany.created_at
# => Sat Aug 13 20:05:35 -0500 2011
aCompany.created_at.to_i.to_s(32)
# => "174e7qv"
This way you get super short ids (7 characters) without having to keep track of a special purpose attribute (in MongoMapper, it's a simple matter of adding timestamps! in the model to get automatic created_at and updated_at attributes).
You can use base64 to make it shorter. Make sure that you are using '-' and '_' instead of '+' and '/'. You can also chop of the padding =.
Code to convert from a hex value to base 64
def MD5hex2base64(str)
h1=[].clear
# split the 32 byte hex into a 16 byte array
16.times{ h1.push(str.slice!(0,2).hex) }
# pack (C* = unsigned char), (m = base64 encoded output)
[h1.pack("C*")].pack("m")
end

check value starting with decimal ruby on rails

How do I check a value starting with a decimal
is_a_number(value) .... works for 12, 12.0, 12.2, 0.23 but not .23
Basically I'm doing a validation in a form, and I want to allow values starting with . i.e .23
but obviously pop up a flag (false) when its not a number
".23" isn't really a number, in my book.
If you want to treat it like one, check if the first character is a decimal point, if it is, prepend a "0" and try again.
Actually, you could probably prepend a zero regardless. It shouldn't affect the value of any "legitimate" number. (EDIT: As long as you can explicitly specify base 10 when actually converting to a number)
Read your input into a string and dynamically add the zero if needed. For example:
if (inputvar[0] == '.')
inputvar = "0#{inputvar}"
end
The resulting value can be converted into a number by .to_i, .to_f, etc.

Resources