UDP HTTP Header parsing in Ruby - ruby-on-rails

I get the following response from a a UDP Socket:
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
DATE: Thu, 08 Nov 2012 12:32:33 GMT
EXT:
LOCATION: http://192.168.0.100:49153/nmrDescription.xml
SERVER: Windows2000/0.0 UPnP/1.0 PhilipsIntelSDK/1.4 DLNADOC/1.50
X-User-Agent: redsonic
ST: upnp:rootdevice
USN: uuid:F00DBABE-SA5E-BABA-DADA188ED55ED539::upnp:rootdevice
Is there a library, or simple way to parse all this ?
I'd like to get something like the following:
{
:cache_control => "max-age=1800"
:date => "Thu, 08 Nov 2012 12:32:33 GMT"
:ext => nil
:location => "http://192.168.0.100:49153/nmrDescription.xml"
# Etc.
}

response.split($/).drop(1).inject({}) do |h, l|
k, v = l.split(": ", 2)
h[k.downcase.gsub("-", "_").to_sym] = (v unless v.empty?)
h
end
# => {
# :cache_control=>"max-age=1800",
# :date=>"Thu, 08 Nov 2012 12:32:33 GMT",
# :ext=>nil,
# :location=>"http://192.168.0.100:49153/nmrDescription.xml",
# :server=>"Windows2000/0.0 UPnP/1.0 PhilipsIntelSDK/1.4 DLNADOC/1.50",
# :x_user_agent=>"redsonic",
# :st=>"upnp:rootdevice",
# :usn=>"uuid:F00DBABE-SA5E-BABA-DADA188ED55ED539::upnp:rootdevice"
#}

Related

Sum the next value of hash in an array of hashes

I have an array of hashes like this:
[{Mon, 09 May 2016 14:49:17 UTC +00:00=>12},
{Sun, 17 Apr 2016 14:08:40 UTC +00:00=>30},
{Sun, 16 Apr 2016 14:08:40 UTC +00:00=>18},
{Sun, 15 Apr 2016 14:03:33 UTC +00:00=>21}]
How can I sum the previous value from the oldest date to the current date, my expected output will be:
[{Mon, 09 May 2016 14:49:17 UTC +00:00=>81},
{Sun, 17 Apr 2016 14:08:40 UTC +00:00=>69},
{Sun, 16 Apr 2016 14:08:40 UTC +00:00=>39},
{Sun, 15 Apr 2016 14:03:33 UTC +00:00=>21}]
Thanks!
Assuming that the key of every hash in your array is a DateTime object, you can get what your want with this:
balance = [
{DateTime.parse('Mon, 09 May 2016 14:49:17 UTC +00:00')=>12},
{DateTime.parse('Sun, 17 Apr 2016 14:08:40 UTC +00:00')=>30},
{DateTime.parse('Sun, 16 Apr 2016 14:08:40 UTC +00:00')=>18},
{DateTime.parse('Sun, 15 Apr 2016 14:03:33 UTC +00:00')=>21}
] # => your original array
# Get expected array.
balance.map{ |h|
{
h.keys.first => balance.select{ |e|
e.keys.first <= h.keys.first }.map{ |s|
s[s.keys.first] }.reduce(:+)
}
}
I split the code in lines in order to improve readability.
Another approach would be to sort the array first and then use the map function to keep a running total to collect the required data.
# sort the balances by date
balance = balance.sort {|a, b| a.keys.first <=> b.keys.first }
# get running total and collect for each date
total = 0
balance.map do |entry|
date, value = entry.first
total += value
{date => total}
end
I assume your array is in lastest-to-earliest date order and looks something like arr below:
a = [{ "Mon, 09 May 2016 14:49:17 UTC +00:00"=>12 },
{ "Sun, 17 Apr 2016 14:08:40 UTC +00:00"=>30 },
{ "Sun, 16 Apr 2016 14:08:40 UTC +00:00"=>18 },
{ "Sun, 15 Apr 2016 14:03:33 UTC +00:00"=>21 }]
require 'date'
arr = a.map do |h|
(d, v) = h.to_a.first
{ DateTime.parse(d) => v }
end
#=> [{#<DateTime: 2016-05-09T14:49:17+00:00 ((2457518j,53357s,0n),+0s,2299161j)>=>12},
# {#<DateTime: 2016-04-17T14:08:40+00:00 ((2457496j,50920s,0n),+0s,2299161j)>=>30},
# {#<DateTime: 2016-04-16T14:08:40+00:00 ((2457495j,50920s,0n),+0s,2299161j)>=>18},
# {#<DateTime: 2016-04-15T14:03:33+00:00 ((2457494j,50613s,0n),+0s,2299161j)>=>21}]
We can then compute the required array as follows.
cumv = 0
arr.reverse.
map { |h| h.to_a.first }.
each_with_object([]) do |(d,v),a|
cumv += v
a << { d => cumv }
end.
reverse
#=> [{#<DateTime: 2016-05-09T14:49:17+00:00 ((2457518j,53357s,0n),+0s,2299161j)>=>81},
# {#<DateTime: 2016-04-17T14:08:40+00:00 ((2457496j,50920s,0n),+0s,2299161j)>=>69},
# {#<DateTime: 2016-04-16T14:08:40+00:00 ((2457495j,50920s,0n),+0s,2299161j)>=>39},
# {#<DateTime: 2016-04-15T14:03:33+00:00 ((2457494j,50613s,0n),+0s,2299161j)>=>21}]

How to print my hash value if it contains time stamp values?

I have a hash in ruby i want to print it in proper manner using hash objects like hash.each_pair(). But its not working as it has some time stamp values.
file1={:file_modify_date=>2015-01-08 12:34:34 +0530, :file_modify_date_civil=>Thu, 08 Jan 2015, :file_access_date=>2015-01-08 13:23:09 +0530, :file_access_date_civil=>Thu, 08 Jan 2015, :file_inode_change_date=>2015-01-08 12:34:34 +0530, :file_inode_change_date_civil=>Thu, 08 Jan 2015, :file_permissions=>"rw-r--r--", :file_type=>"JPEG", :mime_type=>"image/jpeg"}
file1.each_pair { |k, v| puts "Key: #{k}, Value: #{v}" }
How about you format your time_stamp value to string
file1={:file_modify_date=> time1.strftime("%Y-%d-%m %H:%M:%S +%z"), ....}
using strftime to format your time stamp
file1.each_pair { |k, v| puts "Key: #{k}, Value: #{v}" }
see also Rails strftime
Try following
file1={:file_modify_date=>'2015-01-08 12:34:34 +0530', :file_modify_date_civil=>'Thu, 08 Jan 2015', :file_access_date=>'2015-01-08 13:23:09 +0530', :file_access_date_civil=>'Thu, 08 Jan 2015', :file_inode_change_date=>'2015-01-08 12:34:34 +0530', :file_inode_change_date_civil=>'Thu, 08 Jan 2015', :file_permissions=>"rw-r--r--", :file_type=>"JPEG", :mime_type=>"image/jpeg"}
file1.each_pair { |k, v| puts "Key: #{k}, Value: #{v}" }

How do I get the first Thursday of the month in Ruby/Rails?

The following Ruby code gets me the first day of each month :
require 'active_support/all'
# get the date at the beginning of this month
date = Date.today.beginning_of_month
# get the first day of the next 5 months
5.times do |num|
date = date.next_month
p date
end
Which gives :
=> Fri, 01 Aug 2014
=> Mon, 01 Sep 2014
=> Wed, 01 Oct 2014
=> Sat, 01 Nov 2014
=> Mon, 01 Dec 2014
But how do I get the first Thursday of each month? i.e.
=> Thu, 07 Aug 2014
=> Thu, 04 Sep 2014
=> Thu, 02 Oct 2014
=> Thu, 06 Nov 2014
=> Thu, 04 Dec 2014
There's no need for iterations or conditions just get the so called delta of days till next thursday:
#4 is thursday because wday starts at 0 (sunday)
date = Date.today.beginning_of_month
date += (4 - date.wday) % 7
p date
=> Thu, 03 Jul 2014
That my opinion:
date_begin = Date.today.beginning_of_month
date_end = date_begin + 5.month
[*date_begin..date_end].select(&:thursday?).uniq(&:month)
=> [Thu, 03 Jul 2014, Thu, 07 Aug 2014, Thu, 04 Sep 2014, Thu, 02 Oct 2014, Thu, 06 Nov 2014]
Just for fun
class Date
def skip_to_thursday
# given current weekday, how many days we need to add for it to become thursday
# for example, for monday (weekday 1) it's 3 days
offset = lambda {|x| (4-x) % 7 }
self + offset[wday]
end
end
# get the date at the beginning of this month
date = Date.today.beginning_of_month
date.skip_to_thursday # => Thu, 03 Jul 2014
Here is my way :
def first_thursday
date = Date.today.beginning_of_month
date += 1 until date.wday == 4
date
end
first_thursday # => Thu, 03 Jul 2014
you can use something like this:
def first_thursday(months_ahead)
start_of_month = months_ahead.months.from_now.beginning_of_month.to_date
start_of_month += (4 - start_of_month.cwday) % 7
end
first_thursday 1
=> Thu, 07 Aug 2014
first_thursday 2
=> Thu, 04 Sep 2014
I ran into this problem for a recurring_events feature that I needed to build. I changed some of the variables to find the first Thursday but it also shows how you could evolve the answer to find the 2nd or 3rd Thursday (or any day of the week for that matter) if you had a week and day of the week count.
def find_thursday
start_of_month = DateTime.now.beginning_of_month
month_day = nil
loop do
month_day = start_of_month += 1.day
break if month_day.wday == find_weekday("Thu")
end
return month_day
end
def find_weekday
d = default_weekdays.find { |d| d[:day] == start_date.strftime("%a") }
d[:count]
end
def default_weekdays
return [
{ day: 'Sun', count: 0 },
{ day: 'Mon', count: 1 },
{ day: 'Tue', count: 2 },
{ day: 'Wed', count: 3 },
{ day: 'Thu', count: 4 },
{ day: 'Fri', count: 5 },
{ day: 'Sat', count: 6 },
]
end

Is the Time object suitable to create a calendar?

I want to make a database-backed calendar. Will the Time object make my life easier? It hasn't so far...
The .end_of_year method gives me some strange information. If it's contemporary time it works flawlessly:
date = '2012-3-2'.to_time(:utc) #=> 2012-03-02 00:00:00 UTC
date.end_of_year #=> 2012-12-31 23:59:59 UTC
However, if you go back in time things get strange.
date = '1399-3-2'.to_time(:utc) #=> 1399-03-02 00:00:00 UTC
date.end_of_year #=> 1399-12-23 23:59:59 UTC
23rd of December? Shouldn't that be 31st?
It's not even consistent:
date = '0000-3-2'.to_time(:utc) #=> 0000-03-02 00:00:00 UTC
date.end_of_year #=> 0001-01-02 23:59:59 UTC
Um, the 2nd of January? OF THE NEXT YEAR? What is going on?
Also, are leap years taken into account by the object?
You could use DateTime instead:
date = '2012-3-2'.to_datetime #=> Fri, 02 Mar 2012 00:00:00 +0000
date.end_of_year #=> Mon, 31 Dec 2012 23:59:59 +0000
date = '1399-3-2'.to_datetime #=> Sun, 02 Mar 1399 00:00:00 +0000
date.end_of_year #=> Wed, 31 Dec 1399 23:59:59 +0000
date = '0000-3-2'.to_datetime #=> Tue, 02 Mar 0000 00:00:00 +0000
date.end_of_year #=> Fri, 31 Dec 0000 23:59:59 +0000
It's mora accurate, and you can format the output
I've did some digging. Here's what I found.
Let's begin with end_of_year:
def end_of_year
change(:month => 12).end_of_month
end
Which relies on change and end_of_month:
def end_of_month
last_day = ::Time.days_in_month(month, year)
last_hour{ days_since(last_day - day) }
end
The most interesting part is happening inside of days_since:
def days_since(days)
advance(:days => days)
end
The advance method is a bit more complex:
def advance(options)
unless options[:weeks].nil?
options[:weeks], partial_weeks = options[:weeks].divmod(1)
options[:days] = options.fetch(:days, 0) + 7 * partial_weeks
end
unless options[:days].nil?
options[:days], partial_days = options[:days].divmod(1)
options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
end
d = to_date.advance(options)
time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
seconds_to_advance = options.fetch(:seconds, 0) +
options.fetch(:minutes, 0) * 60 +
options.fetch(:hours, 0) * 3600
if seconds_to_advance.zero?
time_advanced_by_date
else
time_advanced_by_date.since(seconds_to_advance)
end
end
And he is the guy we're looking for :
# in rails console
time = '0000-01-01'.to_time(:utc) #=> 0000-01-01 00:00:00 UTC
time.advance(days: 1) #=> 0000-01-04 00:00:00 UTC
time.advance(days: 2) #=> 0000-01-05 00:00:00 UTC
time.advance(days: 3) #=> 0000-01-06 00:00:00 UTC
That's all for now. I will continue to dig.

Sum date object and time object on RoR

sorry for my english...
I have two object, one Date object and one Time object, I want sum them to get a DateTime object, this is I am trying...
[35] pry(main)> dateobj = Date.today
=> Sun, 06 Oct 2013
[36] pry(main)> timeobj = Time.parse("02:00:00")
=> 2013-10-06 02:00:00 -0600
[37] pry(main)> datetimeobj = dateobj + timeobj
TypeError: expected numeric
from /home/elquick/www/rails/vivsan/http/vendor/bundle/ruby/2.0.0/gems/activesupport-3.2.14/lib/active_support/core_ext/date/calculations.rb:90:in `+'
[38] pry(main)>
Some help?
Thanks!
Try to use
Date.today.to_datetime + Time.parse('02:00:00').seconds_since_midnight.seconds
Here is my result:
.0.0-p195 :019 > Date.today.to_datetime
=> Mon, 07 Oct 2013 00:00:00 +0000
2.0.0-p195 :020 > Time.parse('02:00:00').seconds_since_midnight.seconds
=> 7200.0 seconds
2.0.0-p195 :021 > Date.today.to_datetime + Time.parse('02:00:00').seconds_since_midnight.seconds
=> Mon, 07 Oct 2013 02:00:00 +0000
I found this...
dateobj = Date.new(2013, 10, 6)
timeobj = Time.parse("02:00:00")
datetime = DateTime.new(dateobj.year, dateobj.month, dateobj.day, timeobj.hour, timeobj.min, timeobj.sec)

Resources