Building Data Structure out of JSON output - ruby

Hi Im working on writing a script that pulls data out of a ticketing system. Once it pulls the data it analyze the content of it and if it the content match a specific criteria then it needs to build a data structure file that will be dump in the same server.
I was able to parse the data in JSON format, listed below is the content:
[{"id"=>10423,
"type"=>"Ticket",
"lastUpdated"=>"2014-11-04T10:58:47Z",
"shortSubject"=>"FOO STATUS UPDATE",
"shortDetail"=>"Reply to this message if all systems are functional..",
"displayClient"=>"No Client",
"updateFlagType"=>0,
"prettyLastUpdated"=>"54 minutes ago",
"latestNote"=>
{"id"=>16850,
"type"=>"TechNote",
"mobileListText"=>"<b>t. trust: </b> All Systems are OK",
"noteColor"=>"clear",
"noteClass"=>"bubble right"}},
{"id"=>10422,
"type"=>"Ticket",
"lastUpdated"=>"2014-11-04T10:54:07Z",
"shortSubject"=>"FOO STATUS UPDATE",
"shortDetail"=>"Reply to this message if all systems are functional..",
"displayClient"=>"No Client",
"updateFlagType"=>0,
"prettyLastUpdated"=>"58 minutes ago",
"latestNote"=>nil},
{"id"=>10421,
"type"=>"Ticket",
"lastUpdated"=>"2014-11-04T10:53:17Z",
"shortSubject"=>"FOO STATUS UPDATE",
"shortDetail"=>"Reply to this message if all systems are functional..",
"displayClient"=>"No Client",
"updateFlagType"=>0,
"prettyLastUpdated"=>"59 minutes ago",
"latestNote"=>nil}]
In the data above you can see that each ticket has an id, lastupdate, short Subject, short Detail and lastest note the value of the latest note will be nill if no one reply to the ticket but if someone does reply then the value mobileListText will have something.
So what I need to do pretty much is once I get this data the script will look for the subject that complies with "FOO STATUS UPDATE" if that value matches then looks for the content of the shortDetail matches "Reply to this message if all systems are functional.." and if this complies then looks for its latestNote, if latestNote is nill then it will create a log file specifiying date and time when it run, the id of the ticket with this state and a message saying, ticket has not being reply, but if the latest note has the value "mobileListText"=>"t. trust: All Systems are OK", then creates the follwing data structure:
{"LastUpdate":1415130257,"Service":[{"time":"11-04-2014 10:58:47 GMT","region:":"","id":"","description":"All Systems are OK","service":""},{"time":"11-04-2014 10:54:07 GMT","region:":"","id":"","description":"All Systems are OK","service":""},{"time":"11-04-2014 10:53:17 GMT","region:":"","id":"","description":"All Systems are OK","service":""}]}
Im able to have part of this however, based on the data above, only one ticket has All Systems are OK, meaining that only one of the tickets has being reply, and it only should write something like this:
{"LastUpdate":1415130257,"Service":[{"time":"11-04-2014 10:58:47 GMT","region:":"","id":"","description":"All Systems are OK","service":""}]}
But Instead repeats this only ticket that has being replied serveral times.
this my code so far:
require 'rubygems'
require 'json'
require 'net/http'
require 'highline/import'
require 'pp'
require 'logger'
#usersol='foo'
#passol= 'foo123'
#urlsol= "http://dev-webhelpdesk.foo.corp:8081/helpdesk/WebObjects/Helpdesk.woa/ra/Tickets?list=group&page=1&limit=#{#limit}&username=#{#usersol}&password=#{#passol}"
#limit = '25'
#log = #log= Logger.new( 'message_solar.log')
def ticket_data #looks for ticket data in solarwinds
resp = Net::HTTP.get_response(URI.parse(#urlsol))
url_output = resp.body
JSON.parse(url_output)
end
#CRONJOB THAT START ALL
#echo "Reply to this message if all systems are functional.." | mail -r noc#foo.com -s "FOO STATUS UPDATE:" noc-team#FOO.com >> /dev/null
# Looking for all the tickets with the following content
# ticket id, ticket subject and content
def search_allok(allok)
description = []
allok.each do |systems|
output1 = systems.has_key?'id'
if output1
systems.values_at('shortSubject').each do | subject |
output2 = subject.match(%r(TRUST STATUS UPDATE))
if output2
latestnote = systems.values_at('latestNote')
latestnote.each do |content|
if content
final = content.values_at('mobileListText')
final_ok = final[0].sub!(/^\<b\>.*\<\/b\>\s/, "")
systems_ok = final_ok.match(%r(All Systems are OK))
if systems_ok
ids = systems['id']
notify = {"LastUpdate" => Time.now.to_i, "Service" => []}
allok.each do |lastup|
reference = lastup.has_key? 'id'
if reference
timeid = lastup.values_at('lastUpdated')
timeid.each do |lines|
final=lines.split(/[-, T, Z]/)
notify["Service"] << { "time" => "#{final[1]}-#{final[2]}-#{final[0]} #{final[3]} GMT", "region:" => "", "id" => "#{ids}", "description" => "#{systems_ok}" , "service" => ''}
end
end
end
File.open("notify.json", "w") do |fileformatted|
fileformatted.puts (JSON.dump(notify))
end
else
time = Time.now
#log.info("#{time} - Ticket ID #{systems['id']} has not being updated")
end
else
#log.info("#{time} - Ticket ID #{systems['id']} has not being reply")
end
end
end
end
end
end
end
# If the content is there then it need to create
# the data structure including the lastupdated
# (time when it run the script), and the lastupdate for the ticket
# and the description All Systems OK
#This method below I added to the one above, but I was thinking on doing it separate but I encouter issues passing the information needed from above to below
def datastructure(format_file) #creates JSON file lastupdated of each ticket in the queue
notify = {"LastUpdate" => Time.now.to_i, "Service" => []}
format_file.each do |lastup|
reference = lastup.has_key? 'id'
if reference
timeid = lastup.values_at('lastUpdated')
timeid.each do |lines|
final=lines.split(/[-, T, Z]/)
notify["Service"] << { "time" => "#{final[1]}-#{final[2]}-#{final[0]} #{final[3]} GMT", "region:" => "", "id" => "", "description" => region , "service" => ''}
end
end
end
File.open("notify.json", "w") do |fileformatted|
fileformatted.puts (JSON.dump(notify))
end
end
#ticket_data
#datastructure(ticket_data)
search_allok(ticket_data)

The code you've written is basically doing a roundabout version of what is achieved by using ruby's map and select methods. See this article: Ruby Explained: Map, Select, and Other Enumerable Methods

Related

RUBY - Currency Exchange Rate Calculator

I'm trying to create a currency converter in Ruby which will calculate the exchange rate between two currencies on a given date.
I have a data file containing test data (date, currency from, currency to). The test data is in EUR, so all rates are converted to EUR and then to the target currency.
So far I have 3 files (Exchange.rb, Test_Exchange.rb, rates.json):
Exchange.rb:
require 'json'
require 'date'
module Exchange
# Return the exchange rate between from_currency and to_currency on date as a float.
# Raises an exception if unable to calculate requested rate.
# Raises an exception if there is no rate for the date provided.
#rates = JSON.parse(File.read('rates.json'))
def self.rate(date, from_currency, to_currency)
# TODO: calculate and return rate
rates = u/rates[date] # get rates of given day
from_to_eur = 1.0 / rates[from_currency] # convert to EUR
from_to_eur * rates[to_currency] # convert to target currency
end
end
Test_Exchange.rb:
require_relative 'Exchange.rb'
require 'date'
target_date = Date.new(2018,12,10).to_s
puts "USD to GBP: #{Exchange.rate(target_date, 'USD', 'GBP')}"
puts "USD to JPY: #{Exchange.rate(target_date, 'PLN', 'CHF')}"
puts "DKK to CAD: #{Exchange.rate(target_date, 'PLN', 'CHF')}"
rates.json:
{
"2018-12-11": {
"USD": 1.1379,
"JPY": 128.75,
"BGN": 1.9558,
"CZK": 25.845,
"DKK": 7.4641,
"GBP": 0.90228,
"HUF": 323.4,
"CHF": 1.1248,
"PLN": 4.2983
},
"2018-12-10": {
"USD": 1.1425,
"JPY": 128.79,
"BGN": 1.9558,
"CZK": 25.866,
"DKK": 7.4639,
"CAD": 1.5218,
"GBP": 0.90245,
"HUF": 323.15,
"PLN": 4.2921,
"CHF": 1.1295,
"ISK": 140.0,
"HRK": 7.387,
"RUB": 75.8985
},
"2018-12-05": {
"USD": 1.1354,
"JPY": 128.31,
"BGN": 1.9558,
"CZK": 25.886,
"DKK": 7.463,
"GBP": 0.88885,
"HUF": 323.49,
"PLN": 4.2826,
"RON": 4.6528,
"SEK": 10.1753,
"CHF": 1.1328,
"HRK": 7.399,
"RUB": 75.8385,
"CAD": 1.5076
}
}
I'm not sure what to add in the Exchange.rb file to allow the user to input a date and the two currencies to compare exchange rates.
Running Exchange.rb does nothing. I'm guessing it wants a date and currency parameters input?
Running Test_Exchange.rb works because the date and currencies are bootstrapped in.
I found almost the same question posted here a couple years ago, but the thread is now closed, and the solution was incomplete. Hoping someone can help me!
RUNNING EDIT:
Exchange.rb:
require 'json'
require 'date'
module Exchange
# Return the exchange rate between from_currency and to_currency on date as a float.
# Raises an exception if unable to calculate requested rate.
# Raises an exception if there is no rate for the date provided.
#rates = JSON.parse(File.read('rates.json'))
#Grab Date and Currencies from User
puts "Please enter a Date (YYYY-MM-DD)"
input_date = gets.chomp
puts "The Date you entered is: #{input_date}"
puts "Please enter a 3-letter Currency Code (ABC):"
input_curr_1 = gets.chomp
puts "The 1st Currency you entered is: #{input_curr_1}"
puts "Please enter a 2nd 3-letter Currency Code (XYZ):"
input_curr_2 = gets.chomp
puts "The 2nd Currency you entered is: #{input_curr_2}"
def self.rate(input_date, input_curr_1, input_curr_2)
# TODO: calculate and return rate
rates = #rates[input_date] # get rates of given day
from_to_eur = 1.0 / rates[input_curr_1] # convert to EUR
from_to_eur * rates[input_curr_2] # convert to target currency
end
end
I think I have to use a put and a get to capture the user date input? Then the same for each of the two currencies? Of course, my syntax for the date stuff is all wrong..
So I managed to use the gets and put functions. Now all that's left is somehow calling the rates.json file and comparing the user inputs to the existing data..

how to amend a code to get query from external and save result to external

I have a code which looks like this
require 'net/http'
base = 'www.uniprot.org'
tool = 'mapping'
params = {
'from' => 'ACC+ID', 'to' => 'P_ENTREZGENEID', 'format' => 'tab',
'query' => 'A0A0K3AVS5 A0A0K3AVV4 A0A0K3AW32 A0A0K3AWP0'
}
http = Net::HTTP.new base
$stderr.puts "Submitting...\n";
response = http.request_post '/' + tool + '/',
params.keys.map {|key| key + '=' + params[key]}.join('&')
loc = nil
while response.code == '302'
loc = response['Location']
response = http.request_get loc
end
while loc
wait = response['Retry-After'] or break
$stderr.puts "Waiting (#{wait})...\n";
sleep wait.to_i
response = http.request_get loc
end
response.value # raises http error if not 2xx
puts response.body
which gives me what I need. however, I have two questions
1- How to load a query list instead I parse it into the code ? lets say I save a txt file with all the query i want to the desktop of a mac
2- How to export the output ?
If I have
B2D6P1
G5EC52
B2FDA8-2
B2MZB1
B3CJ34
B3CKG1
B3GWA1
what #tadman showed gives me the answer
however, I have the following
B2D6P1
G5EC52;B2D6P4
B2FDA8-2;B2FDA8
B2MZB1;P18834
B3CJ34
B3CKG1
B3GWA1;Q8I7K5
and the answer is like below
B2D6P1 rmd-2
G5EC52 tlf-1
B2D6P4 tlf-1
B2FDA8 smc-3
B2MZB1 col-14
P18834 col-14
B3CJ34 gcn-1
B3CKG1 urm-1
B3GWA1 nono-1
Q8I7K5 nono-1
what I want is that if I have two entries in each row (separated with ;) leading to the similar output , it gives me only one , otherwise give me as many as they have for example in above example , my desire output is
B2D6P1 rmd-2
G5EC52;B2D6P4 tlf-1
B2FDA8-2;B2FDA8 smc-3
B2MZB1;P18834 col-14
B3CJ34 gcn-1
B3CKG1 urm-1
B3GWA1;Q8I7K5 nono-1
is this possible ?
Reading query data:
query = File.readlines('ids.txt').map(&:chomp).join(' ')
That way you can have them on separate lines, easier to edit, and they're space separated when submitted.
That makes your params look like:
params = {
'query' => query,
...
}
Writing data:
File.open('output.txt', 'w') do |f|
f.write(response.body)
end
That's all there is to it. If it's a string, or can be converted to a string, you can write it to a file.

Ruby Dashing: Issues with Jobs (on a CentOS Server)

I'm having a weird event occur, where my dashing dashboard's list widget is showing erroneous data. Here's the screenshot from my live Dashing widget
Erroneous Widget
Expected Output
What follows is the code for the widget:
Code in .erb
<li data-row="1" data-col="1" data-sizex="2" data-sizey="6">
<div data-id="facebook_insights" data-view="List" data-unordered="true" data-title="Facebook Insights: Weekly Post Views" data-moreinfo="Updated every 10 seconds"</div>
</li>
Code in job .rb
require 'mysql2'
social_count = Hash.new({ value: 0 })
time = Time.new()
date_time1 = Time.new(time.year, time.month, time.day-1)
...
SCHEDULER.every '10s' do
begin
db = Mysql.new(<HOST>,<USER>,<PASS>,<DBNAME>)
mysql1 = "SELECT <VAR> FROM <TABLE> WHERE <VAR> = '#{date_time1}' ORDER BY <VAR> DESC LIMIT 1"
...
result1 = db.query(mysql1)
...
rescue
ensure
db.close
end
result1.each do |row|
strrow1 = row[0]
$value1 = strrow1.to_i
end
...
social_count[0] = {label: "1:", value: $value1}
...
send_event('facebook_insights', { items: social_count.values })
end
What is really baffling, is that this code works for a similar widget using different data in the SQL query. Can anyone help me understand why?
I checked and re-checked the data and in my other, working code, I had my $value variables defined as $valueX with X being the number. I thought to myself "Maybe the variable names are getting confused due to them having the same name", so I changed my code to
Working Code
result1.each do |row|
strrow1 = row[0]
$variable1 = strrow1.to_i
end
...
social_count[0] = {label: "1:", value: $variable1}
Et Voila! Eureka! It worked. Not sure why it still got confused with the names, but from now on, my names will be unique!

Ruby - URL to Markdown

TOTAL rookie here.
I'm working on customizing a script made by Brett Terpstra - http://brettterpstra.com/2013/11/01/save-pocket-favorites-to-nvalt-with-ifttt-and-hazel/
Mine is a different use: I'd like to save my pinboard bookmarks with a specific tag to a file in dropbox in Markdown.
I feed it a text file such as:
Title: Yesterday is over.
URL: http://www.jonacuff.com/blog/want-to-change-the-world-get-doing/
Tags: 2md, 2wcx, 2pdf
Date: June 20, 2013 at 06:20PM
Image: notused
Excerpt: You can't start the next chapter of your life if you keep re-reading the last one.
And it outputs the markdown file.
Everything works great except when the 'excerpt' (see above) is more than one line. Sometimes it's a couple of paragraphs. When that happens, it stops working. When I hit enter from the command line, it's still waiting for more input.
Here's an example of a file that it doesn't work on:
Title: Talking ’bout my Generation.
URL: http://blog.greglaurie.com/?p=8881
Tags: 2md, 2wcx, 2pdf
Date: June 28, 2013 at 09:46PM
Image: notused
Excerpt: Contrast two men from the 19th century: Max Jukes and Jonathan Edwards.
Max Jukes lived in New York. He did not believe in Christ or in raising his children in the way of the Lord. He refused to take his children to church, even when they asked to go. Of his 1,026 descendants:
•300 were sent to prison for an average term of 13 years
•190 were prostitutes
•680 were admitted alcoholics
His family, thus far, has cost the state in excess of $420,000 and has made no contribution to society.
Jonathan Edwards also lived in New York, at the same time as Jukes. He was known to have studied 13 hours a day and, in spite of his busy schedule of writing, teaching, and pastoring, he made it a habit to come home and spend an hour each day with his children. He also saw to it that his children were in church every Sunday. Of his 929 descendants:
•430 were ministers
•86 became university professors
•13 became university presidents
•75 authored good books
•7 were elected to the United States Congress
•1 was Vice President of the United States
Edwards’ family never cost the state one cent.
We tend to think that our decisions only affect ourselves, but they have ramifications for generations to come.
Here's a screenshot of what it looks like after I run the command: https://www.dropbox.com/s/i9zg483k7nkdp6f/Screenshot%202013-11-22%2016.39.17.png
I'm hoping it's something easy. Any ideas?
#!/usr/bin/env ruby
# Works with IFTTT recipe https://ifttt.com/recipes/125999
#
# Set Hazel to watch the folder you specify in the recipe.
# Make sure nvALT is set to store its notes as individual files.
# Edit the $target_folder variable below to point to your nvALT
# ntoes folder.
require 'date'
require 'open-uri'
require 'net/http'
require 'fileutils'
require 'cgi'
$target_folder = "~/Dropbox/messx/urls2md"
def url_to_markdown(url)
res = Net::HTTP.post_form(URI.parse("http://heckyesmarkdown.com/go/"),{'u'=>url,'read'=>'1'})
if res.code.to_i == 200
res.body
else
false
end
end
file = ARGV[0]
begin
input = IO.read(file).force_encoding('utf-8')
headers = {}
input.each_line {|line|
key, value = line.split(/: /)
headers[key] = value.strip || ""
}
outfile = File.join(File.expand_path($target_folder), headers['Title'].gsub(/["!*?'|]/,'') + ".txt")
date = Time.now.strftime("%Y-%m-%d %H:%M")
date_added = Date.parse(headers['Date']).strftime("%Y-%m-%d %H:%M")
content = "Title: #{headers['Title']}\nDate: #{date}\nDate Added: #{date_added}\nSource: #{headers['URL']}\n"
tags = false
if headers['Tags'].length > 0
tag_arr = header s['Tags'].split(", ")
tag_arr.map! {|tag|
%Q{"#{tag.strip}"}
}
tags = tag_arr.join(" ")
content += "Keywords: #{tags}\n"
end
markdown = url_to_markdown(headers['URL']).force_encoding('utf-8')
if markdown
content += headers['Image'].length > 0 ? "\n\n> #{headers['Excerpt']}\n\n---#{markdown}\n" : "\n\n"+markdown
else
content += headers['Image'].length > 0 ? "\n\n![](#{headers['Image']})\n\n#{headers['Excerpt']}\n" : "\n\n"+headers['Excerpt']
end
File.open(outfile,'w') {|f|
f.puts content
}
if tags && File.exists?("/usr/local/bin/openmeta")
%x{/usr/local/bin/openmeta -a #{tags} -p "#{outfile}"}
end
# FileUtils.rm(file)
rescue Exception => e
puts e
end
How about this? Modify your input.each_line area accordingly:
headers = {}
key = nil
input.each_line do |line|
match = /^(?<key>\w+)\s*:\s*(?<value>.*)/.match(line)
value = line
if match
key = match[:key].strip
headers[key] = match[:value].strip
else
headers[key] += line
end
end
First, splitting on just ":" is dangerous since that can be in content. Instead, a (simplified from code) regex of /^\w+:.*/ will match "Word: Content". Since the lines after the "Excerpt:" aren't prefixed, you need to hang on to the last seen key, and just append if there's no key for this line. You may need to add a newline in there, depending on what you're doing with that header information, but it seems to work.

Working with nested hashes in Rails 3

I'm working with the Koala gem and the Facebook Graph API, and I want to break down the results I get for a users feed into separate variables for inserting into a mySQL database, probably using Active Record. Here is the code I have so far:
#token = Service.where(:provider => 'facebook', :user_id => session[:user_id]).first.token
#graph = Koala::Facebook::GraphAPI.new(#token)
#feeds = params[:page] ? #graph.get_page(params[:page]) : #graph.get_connections("me", "home")
And here is what #feeds looks like:
[{"id"=>"1519989351_1799856285747", "from"=>{"name"=>"April Daggett Swayne", "id"=>"1519989351"},
"picture"=>"http://photos-d.ak.fbcdn.net/hphotos-ak-ash4/270060_1799856805760_1519989351_31482916_3866652_s.jpg",
"link"=>"http://www.facebook.com/photo.php?fbid=1799856805760&set=a.1493877356465.2064294.1519989351&type=1", "name"=>"Mobile Uploads",
"icon"=>"http://static.ak.fbcdn.net/rsrc.php/v1/yx/r/og8V99JVf8G.gif", "type"=>"photo", "object_id"=>"1799856805760", "application"=>{"name"=>"Facebook for Android",
"id"=>"350685531728"}, "created_time"=>"2011-07-03T03:14:04+0000", "updated_time"=>"2011-07-03T03:14:04+0000"}, {"id"=>"2733058_10100271380562998", "from"=>{"name"=>"Joshua Ramirez",
"id"=>"2733058"}, "message"=>"Just posted a photo",
"picture"=>"http://platform.ak.fbcdn.net/www/app_full_proxy.php?app=124024574287414&v=1&size=z&cksum=228788edbab39cb34861aecd197ff458&src=http%3A%2F%2Fimages.instagram.com%2Fmedia%2F2011%2F07%2F02%2F2ad9768378cf405fad404b63bf5e2053_7.jpg",
"link"=>"http://instagr.am/p/G1tp8/", "name"=>"jtrainexpress's photo", "caption"=>"instagr.am",
"icon"=>"http://photos-e.ak.fbcdn.net/photos-ak-snc1/v27562/10/124024574287414/app_2_124024574287414_6936.gif", "actions"=>[{"name"=>"Comment",
"link"=>"http://www.facebook.com/2733058/posts/10100271380562998"}, {"name"=>"Like", "link"=>"http://www.facebook.com/2733058/posts/10100271380562998"}], "type"=>"link",
"application"=>{"name"=>"Instagram", "id"=>"124024574287414"}, "created_time"=>"2011-07-03T02:07:37+0000", "updated_time"=>"2011-07-03T02:07:37+0000"},
{"id"=>"588368718_10150230423643719", "from"=>{"name"=>"Eric Bailey", "id"=>"588368718"}, "link"=>"http://www.facebook.com/pages/Martis-Camp/105474549513998", "name"=>"Martis Camp",
"caption"=>"Eric checked in at Martis Camp.", "description"=>"Rockin the pool", "icon"=>"http://www.facebook.com/images/icons/place.png", "actions"=>[{"name"=>"Comment",
"link"=>"http://www.facebook.com/588368718/posts/10150230423643719"}, {"name"=>"Like", "link"=>"http://www.facebook.com/588368718/posts/10150230423643719"}],
"place"=>{"id"=>"105474549513998", "name"=>"Martis Camp", "location"=>{"city"=>"Truckee", "state"=>"CA", "country"=>"United States", "latitude"=>39.282813917575,
"longitude"=>-120.16736760768}}, "type"=>"checkin", "application"=>{"name"=>"Facebook for iPhone", "id"=>"6628568379"}, "created_time"=>"2011-07-03T01:58:32+0000",
"updated_time"=>"2011-07-03T01:58:32+0000", "likes"=>{"data"=>[{"name"=>"Mike Janes", "id"=>"725535294"}], "count"=>1}}]
I have looked around for clues on this, and haven't found it yet (but I'm still working on my stackoverflow-foo). Any help would be greatly appreciated.
That isn't a Ruby Hash, that's a fragment of a JSON string. First you need to decode into a Ruby data structure:
# If your JSON string is in json...
h = ActiveSupport::JSON.decode(json) # Or your favorite JSON decoder.
Now you'll have a Hash in h so you can access it like any other Hash:
array = h['data']
puts array[0]['id']
# prints out 1111111111_0000000000000
puts array[0]['from']['name']
# prints Jane Done

Resources