How to extract the values from a string from slack ruby bot - ruby

I am trying to create a slackbot which can save incoming data to a database.
I have used the gem slack-ruby-bot and I'm able to receive my text, but I want to extract specific parts of the text, to save in a database.
Given the following received text:
I worked on 'stackoverflow' for 10 hours.
I must be able to extract the project name, stackoverflow, and the hour, which is 10. Is there someway to do it?
command 'activity', '/^Activity/' do |client, data, match|
client.say(text: "#{data.text}", channel: data.channel)
end
This is just a sample code which gets the command activity.

Wherever you receive the string, you might use the regular expression and String#scan to get the data.
"I worked on 'stackoverflow' for 10 hours.".scan /'[^']+'|\d+/
#⇒ ["'stackoverflow'", "10"]

Related

Ignore formatting in Slack App when reading messages

I'm building a Slack App which is only interested in actual user input in message, regardless if it's bold, italic, or a web link.
What would be the best way to remove all the formatting characters, such as _, *, etc, and leave actual text only?
The best solution is actually to ignore the text param entirely, as it is inherently lossy, and to instead parse what you want from the blocks param, which gives an exact representation of what the user saw in their slack client message field when they posted their message.
To demonstrate this, here's a simple example
what you type
WYS
text
blocks[0]["elements"]["elements"]
parsing text from blocks
[a][space][*][b][*]
​a b
a *b*
[{"type":"text","text":"a "},{"type":"text","text":"b","style":{"bold":true}}]
a b
[a][*][b][*][←][←][←][space]
a *b*
a *b*
[{"type":"text","text":"a *b*"}]
a *b*
Unfortunately for now, the Slack API does not give you the blocks param in command events, only message events. Hopefully they will fix this, but until then you may wish to use regular messages instead of slash commands.
If you are using node.js there is a module for this:
https://openbase.io/js/remove-markdown/documentation
Note that this is for markdown and not Slack's variant mrkdwn so it might not work.
Managed to get the unformatted message in python by looping through the array.
def semakitutu(message, say):
user = message['user']
# print(message)
hasira = message['blocks']
hasira2 = hasira[0]['elements'][0]['elements']
urefu = len(hasira2)
swali = ''
for x in range(urefu):
swali=swali+hasira2[x]['text']
print(swali)
say(f"Hello <#{user}>! I am running your request \n {swali}")```

Parse email subject office 365 flows

I am trying to get some data parsed out of a subject line in Office 365 Flows. I have an email that has a consistent format:
Help Desk [Ticket #12345]
I want to get the number '12345' for use in later steps in the flow. So far, I've attempted to use the substring expression in a compose connector:
substring(triggerBody()?['Subject'], 20, 5)
But I get an error about the string being null.
Besides the index being incorrect (to retrieve '12345' from Help Desk [Ticket #12345] you need to use substring(value, 0, 5) as the index is 0-based), the expression looks correct. But you can take a step-by-step approach to see what is wrong.
To start, take a look at the flow run to see exactly what the trigger outputs are:
If you see the Subject field (as I do in my case), create a variable containing that value only to make sure that you don't have any typo:
If it works correctly, then you should see in the flow run the subject:
If everything is still good at that point, create a new variable with the substring that you want:
And again, check the value.
If you got to this point, then you should be able to retrieve the ticket id.

Bizarre field switch between cli and file output in Ruby

I'm having such an strange issue with an ruby script which i'm working with... in this script i parse an iTunes Library xml file and form objects for Artists, Albums and Tracks. In my Album class, i have two numeric field, YEAR and TRACK_COUNT.
My script parses correctly the two fields, let's say, for example, the output of it:
#<Album:0x007f59b1472a18 #compilation=false, #title="Straight Out Of Hell", #year=2013, #track_count=13, #trackList=[], #coverList=[]>
when i output this same object to file, it get crippled, transforming to this, here in json format:
{"compilation":false,"title":"Straight Out Of Hell","year":13,"track_count":13,"trackList":[],"coverList":[]}]
as you can see, the field YEAR get overwritten with the value in TRACK_COUNT field... i'm getting crazy with this, as i don't do any change to this field between these outputs!
UPDATE
As asked by #Amadan...
http://pastebin.com/1FUuvaCr Biblioteca.xml (EXCERPT)
http://pastebin.com/F8wgu6bz Track.rb
http://pastebin.com/3qhd4TRU Song.rb
http://pastebin.com/RNf5S7AZ dependencies.rb
http://pastebin.com/haXPpJgN Cover.rb
http://pastebin.com/1JYtT1nn Artist.rb
http://pastebin.com/qsgLsAJa Album.rb
http://pastebin.com/eiUAMfwR app.rb (MAIN SCRIPT)
This is happening because your source file is not as clean as you believe it to be. In some albums in the source XML, "Track Count" and "Year" are appearing on the same line, without a recognized line break between them. So you might have a line like this:
<key>Track Count</key><integer>12</integer><key>Year</key><integer>2006</integer>
When your if-else-if ladder asks if "track count" appears in the line, it does, so you're grabbing the first <integer>something</integer> match on the line. This works fine. But when you try to extract the year out of this line, you're again asking for the first <integer> on the line, which is the Track Count.
The bigger problem is that you're attempting to parse an XML file line-by-line, and that's not how they're meant to be read. Install the nokogiri gem and call this:
data = Nokogiri::XML('Biblioteca.xml')
Now you can get to any information contained in the document. The official tutorials on user Nokogiri are here: http://www.nokogiri.org/tutorials/
Use this method to parse your file:
def parse filename
xml = Nokogiri::XML(filename)
songs = xml.css('dict key').select{|key| key.text =~ /^[0-9]{4}$/}
songs.map do |song|
info = {}
song.next_element.css('key').each do |attribute|
info[attribute.text] = attribute.next_element.text
end
info
end
end
This will create a list of song hashes. Here are some examples for how to use it:
# load the two songs in your example file
songs = parse('Biblioteca.xml')
# Get the year of the first song
songs[0]['Year'] #=> 2006
# Get the Track Count of the second song's album
songs[1]['Track Count'] #=> 12
# Get the Name of the second song
songs[1]['Name'] #=> 'Baby Come On'
# Get the Album name of the second song
songs[1]['Album'] #=> 'When Your Heart Stops Beating'
From here, you can easily put info into your song objects. Let me know if you have any more questions.
I've found a library for iTunes dodgy plist xml standart... Nokogiri-plist... working fine now :D

Extract JSON values from remote api with Ruby

I'm trying to grab some data from last.fm and use it in a simple sinatra app. I've worked out how to open the document but having issues extracting the data in ruby here is the first list of the API data I'd like to grab the name:
{"similarartists":{"artist":[{"name":"Sonny & Cher"}]}
This is just an extract of the return, I'm using this in my rb file:
require 'json'
require 'open-uri'
data = JSON.parse(open("http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&artist=editors&api_key=xxx&format=json").read)
puts data["similarartists"]["artist"]["name"]
It doesn't seem to be working I get can't convert String into Integer (TypeError) on ruby 1.9.3 but the name in the JSON isn't an integer? If I just put the following:
puts data["similarartists"]["artist"]
It returns the whole thing, but I want to grab inside of that and get the name.
"name"=>"Interpol"
I don't understand why it would complain about integers when the name is a string? Hope someone can help me!
Based on the comments thread, the issue is a misunderstanding of the structure of the data returned from the API call.
The exact issue was the structure had an array of artists under the artist key so to get at the name you need to do:
data['similarartists']['artist'][0]['name']
Note though that you should only do that if you are sure there will only be one artist. The nature of the return data suggests that won't always be the case so you might be better off pulling all names depending on your use doing something like:
data['similarartists']['artist'].map {|a| a['name']}.join(',')
That will join all of the artist names together comma separated.
In the future, you can track this issue down by looking at the full structure of the return data and making sure you see the correct structure. The docs on the API may indicate some help here too.
You also might check if someone has made a gem for accessing the API. Often a gem will up-level some of this raw output and give you a nice object to work with. I suggest searching GitHub for a last.fm gem.
The problem is that you are trying to access an Array with the index "name", Ruby tries to convert this to an Integer and fails which results in the Error message you are seeing.
If you test the class of data["similarartists"]["artist"].class you will see that it returns Array. So basically what is happening is that the JSON.parse() called created as the value of data["similarartists"]["artist"] an Array of Hashes. To access all of the artist names you can simply iterate through this array:
require 'json'
require 'open-uri'
data = JSON.parse(open("http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&artist=editors&api_key=29da5a0e01ca2d1524cac596d5462d67&format=jso\
n").read)
# iterate through the Array of returned artists and print their names
data["similarartists"]["artist"].each do |artist|
puts artist["name"]
end
# output
# Interpol
# White Lies
# The Cinematics
# Smith & Burrows
# The National
# Julian Plenti
# She Wants Revenge
# etc ...
If you only want the first entry for Interpol you can just use index [0]:
puts data["similarartists"]["artist"][0]["name"]

How can I QUICKLY get a string from one of the first couple lines of a long CSV at a remote URL?

I'm working on an assignment where I retrieve several stock prices from online, using Yahoo's stock price system. Unfortunately, the Yahoo API I'm required to use returns a .csv file that apparently contains a line for every single day that stock has been traded, which is at least 5 thousand lines for the stocks I'm working with, and over 10 thousand lines for some of them (example).
I only care about the current price, though, which is in the second line.
I'm currently doing this:
require 'open-uri'
def get_ticker_price(stock)
open("http://ichart.finance.yahoo.com/table.csv?s=#{stock}") do |io|
io.read.split(',')[10].to_f
end
end
…but it's really slow.
Is all the delay coming from getting the file, or is there some from the way I'm handling it? Is io.read reading the entire file?
Is there a way to download only the first couple lines from the Yahoo CSV file?
If the answers to questions 1 & 2 don't render this one irrelevant, is there a better way to process it that doesn't require looking at the entire file (assuming that's what io.read is doing)?
You can use query string parameters to reduce the data to the current date, by using date range parameters.
example for MO on 7/13/2012: (start/end month starts w/ a zero-index, { 00 - 11 } ).
http://ichart.finance.yahoo.com/table.csv?s=MO&a=06&b=13&c=2012&d=6&e=13&f=2012&g=d
api description here:
http://etraderzone.com/free-scripts/47-historical-quotes-yahoo.html

Resources