Ruby/Rails - Converting Google Apps Script to Rails - ruby-on-rails

I'm having a bit of trouble converting the following method in a Google App Script to work with Rails:
Tutorial: Parsing an XML Document
This is the method I'd like to convert:
function parse(txt) {
var doc = Xml.parse(txt, true);
var attr = doc.spellcheck;
if (attr) {
return "Cannot find actor: " + attr.name;
}
var actors = doc.html.head.getElements("actor");
var movies = doc.html.head.getElements("movie");
if (!actors || actors.length ==0) {
return "no match found";
}
var movieIndex = 0;
var r = '';
var firstPerson = true;
for (var i in actors) {
r = r + actors[i].getText();
if (movies[movieIndex]) {
r = r + (firstPerson ? "" : " who") + " was in " +
movies[movieIndex].getText() + " with ";
}
movieIndex++;
firstPerson = false;
}
return r;
}
This is what I have so far:
I'm using Nokogiri to parse the XML:
uri = "http://oracleofbacon.org/cgi-bin/xml?a=Kevin%20Bacon&b=#{to.strip.to_hash}&u=1&p=google-apps"
doc = Nokogiri::XML(open(uri))
My attempt at conversion:
def parse(doc)
attr = doc.xpath("//link//actor").first # => "<actor>Miley Cyrus</actor>"
if (!attr)
return "Cannot find actor: #{attr}"
end
actors = doc.xpath("//link//actor")
movies = doc.xpath("//link//movie")
if (!actors || actors.length == 0)
return "No match found."
end
movieIndex = 0
r = ""
firstPerson = true
actors.each do |actor|
r = r + actor
if (movies[movieIndex])
r = r + (firstPerson ? "" : " who") + " was in #{movies[movieIndex]} with "
end
movieIndex++
firstPerson = false;
end
return r
end
I get an error:
`block in parse': undefined method `+#' for false:FalseClass (NoMethodError)
This is happening on the firstPerson = false line.

actors.each yields each actor node to the block. So your i variable contains an actor element (Nokogiri::XML::Element). Thus actors[i] doesn't make sense, which is why you get the first error.
You're probably looking for
actors.each do |actor|
r = r + actor
[...]
end
although I am not sure what will happen when you attempt to concatenate a Nokogiri::XML::Element to a String.
Also, movieIndex++ doesn't do what you hope. You want movieIndex += 1.
Although, since you're just incrementing movieIndex on every loop, you could remove the line entirely and do actors.each do |actor, movieIndex| instead.

Related

lua open a file with a table and change certain values

I have a file with a large table. Need to open it, get certain values and replace other values with the new ones. With this example, Females and Males Classroom a and b must equal Teachers Classroom a and b.
Read as much as I can on IO, but I cannot seem to get this to work correctly. Any help will be greatly appreciated.
--file with sample data to test, original file has 7000+lines
theData =
{
["theSchool"] =
{
["theTeachers"] =
{
["theClassroom"] =
{
["a"] = 001,
["b"] = 002,
},
},
["theFemales"] =
{
["theClassroom"] =
{
["a"] = 005,
["b"] = 010,
},
},
["theMales"] =
{
["theClassroom"] =
{
["a"] = 012,
["b"] = 014,
},
},
},
}
Then the function file looks like this
local file = io.open(filepath,'r')
local newCa = '["a"] = '..theData.theSchool.theTeachers.theClassroom.a
local newCb = '["b"] = '..theData.theSchool.theTeachers.theClassroom.b
local replaceFa = '["a"] = '..tostring(theData.theSchool.theFemales.theClassroom.a)
local replaceFb = '["b"] = '..tostring(theData.theSchool.theFemales.theClassroom.b)
local replaceMa = '["a"] = '..tostring(theData.theSchool.theMales.theClassroom.a)
local replaceMb = '["b"] = '..tostring(theData.theSchool.theMales.theClassroom.b)
file:close()
--Will it work?
print("Original Values:")
print(newCa)
print(newCb)
print(replaceFa)
print(replaceFb)
print(replaceMa)
print(replaceMb)
file = io.open(filepath,'r+')
function lines_from(filepath)
lines = {}
for line in io.lines(filepath) do
lines[#lines + 1] = line
end
return lines
end
local lines = lines_from(filepath)
for k,v in ipairs(lines) do
if v == replaceFa then
file:write(newCa..'\n')
elseif v == replaceFb then
file:write(newCb..'\n')
elseif v == replaceMa then
file:write(newCa..'\n')
elseif v == replaceMb then
file:write(newCb..'\n')
else
file:write(v..'\n')
end
--('[' .. k .. ']', v)
end
--replaceF = {[a] = newCa, [b] = newCb}
--replaceM = {[a] = newCa, [b] = newCb}
--file:write(replaceF)
--file:write(replaceM)
--print(tostring(theData.theSchool.theFemales.theClassroom.a))
file:close()
file = io.open(filepath,'r')
--Did it work?
print("New Values:")
print(theData.theSchool.theTeachers.theClassroom.a)
print(theData.theSchool.theTeachers.theClassroom.b)
print(theData.theSchool.theFemales.theClassroom.a)
print(theData.theSchool.theFemales.theClassroom.b)
print(theData.theSchool.theMales.theClassroom.a)
print(theData.theSchool.theMales.theClassroom.b)```
> I'll remove all the print things after it works.
try this solution, loading the table in one read of the file will be faster, and writing is also better with one command write
--- read
local handle = io.open("data.lua",'rb')
local data = handle:read("*a")
handle:close()
data = data .. "\n return theData"
local t = loadstring(data)()
-- edit
theData.theSchool.theTeachers.theClassroom.a = theData.theSchool.theTeachers.theClassroom.a + 1
-- write
local function concat(t, r)
r = r or {}
for k,v in pairs(t) do
if type(v)=="table" then
r[#r+1] = string.format('\t["%s"]={\n',k )
concat(v, r)
r[#r+1] = "\t},\n"
else
r[#r+1] = string.format('\t\t["%s"]=%03s,\n',k ,v )
end
end
return r
end
local r = concat(t)
local text = "theData = { \n " .. table.concat(r) .. "}"
print(text) -- just control
local handle = io.open("data.lua",'wb')
local data = handle:write(text)
handle:close()

Returning values in lua

function SearchDatabase(ply, value)
local id = ply:SteamID()
if id == nil then return end
local query = ECLIPSEUSERDATA:query("SELECT " .. value .. " FROM main WHERE usersteamid = '" .. id .. "';")
if not query then return end
query.onData = function(q, d)
if(#query:getData() >= 1)then
print("[SQL]" .. value .. " = " .. tostring(d[value]))
print(tostring(d[value]))
return tostring(d[value])
end
end
query.onError = function(db, err)
print("[SQL] Failed to search database - Error: ", err)
end
query:start()
query:wait()
end
function UpdatePlaytime(ply)
if ply == nil then
return
end
local PlayersPlaytime = SearchDatabase(ply, "playtime")
print(PlayersPlaytime)
local PlaytimeUpdate = PlayersPlaytime + 1
end
The problem i'm currently having is when the value: d[value], is returned to my function UpdatePlaytime() function it is returning a nil value and I have no idea how to fix it.
Console logs:
[SQL]playtime = 0
0
nil
Any help will appreciated thanks!
-D12

How to push key and value to an empty hash with a loop in Ruby on rails

I want to use Bing search results for my webpage. To use their json data I found this solution:
new_bing_results = bing_results[0][:Web]
result = { }
result[:title] = new_bing_results[0][:Title]
result[:description] = new_bing_results[0][:Description]
result[:url] = new_bing_results[0][:Url]
result[:display_url] = new_bing_results[0][:DisplayUrl]
result[:title1] = new_bing_results [1][:Title]
result[:description1] = new_bing_results [1][:Description]
result[:url1] = new_bing_results [1][:Url]
result[:display_url1] = new_bing_results [1][:DisplayUrl]
result[:title2] = new_bing_results [2][:Title]
result[:description2] = new_bing_results [2][:Description]
result[:url2] = new_bing_results [2][:Url]
result[:display_url2] = new_bing_results [2][:DisplayUrl]
....
result
How can I create a loop that is doing the same thing 50 times without having to repeat the same code.
I tried this but only get errors:
new_bing_results = bing_results[0][:Web]
$i = 0
$num = 50
result2 = {}
while $i < $num do
result[:title$i] = new_bing_results[$i][:Title]
......
end
result
The problem is that I do not find a solution for adding my $i number to the key result[:title] as in the value new_bing_results[$i][:Title]
This should do the trick
result = {}
50.times do |i|
result["title#{i}".to_sym] = new_bing_results[i][:Title]
result["description#{i}".to_sym] = new_bing_results[i][:Description]
result["url#{i}".to_sym] = new_bing_results[i][:Url]
result["display_url#{i}".to_sym] = new_bing_results[i][:DisplayUrl]
end
50.times will run from 0 to 49 and you can use interpolation to avoid the repetition.
You can use .to_sym method. For example:
new_bing_results = [{Title: "Title"}]
result = {}
result["title#{i}".to_sym] = new_bing_results[i][:Title]
result
=> {:title0=>"Title"}
You can use string interpolation and then the to_sym method.
result = {}
50.times do |n|
result["title#{n}".to_sym] = new_bing_results[n][:Title]
end

Split Function showing error in Ruby 1.8.7

I have a piece of code I have written in Ruby 1.8.7
Variable emotes has a list of emoticons separated by a space. However, when I apply the split function, I get an error
lines=[]
keywords=""
emotes=""
Dir["/home/pnpninja/Downloads/aclImdb/train/formatted neg/*"].each do |reviewfile|
sum_emote = 0
sum_keyword = 0
lines = File.foreach(reviewfile.to_s).first(2)
lines[0].gsub!("\n",'')
keywords = lines[0].split(" ")
emotes = lines[1].split(" ")
keywords.each { |keyword| sum_keyword = sum_keyword + keywordhash[keyword] }
emotes.each { |emote| sum_emote = sum_emote + emotehash[emote] }
senti=""
if sum_emote+sum_keyword >= 0
senti = "Positive"
else
senti = "Negative"
end
vv = reviewfile.gsub('formatted neg','analysed neg')
fin = File.open(vv.to_s, 'a')
fin << "Emote Weight = #{sum_emote}\n"
fin << "Keyword Weight = #{sum_keyword}\n"
fin << "Sentiment : #{senti}"
fin.close
end
The error I get is
NoMethodError: private method `split' called for nil:NilClass
at line
emotes = lines[1].split(" ")
THe second line in each file could be empty or not.
The error is telling you that you can't call split on a nil object.
Rewrite your code to ensure there are no nil objects or ensure nothing is done if the object in question is nil
unless lines[1].nil?
emotes = lines[1].split(" ")
emotes.each { |emote| sum_emote = sum_emote + emotehash[emote] }
end

"Error: attempt to index local 'self' (a nil value)" in string.split function

Quick facts, I got this function from http://lua-users.org/wiki/SplitJoin at the very bottom, and am attempting to use it in the Corona SDK, though I doubt that's important.
function string:split(sSeparator, nMax, bRegexp)
assert(sSeparator ~= '')
assert(nMax == nil or nMax >= 1)
local aRecord = {}
if self:len() > 0 then
local bPlain = not bRegexp
nMax = nMax or -1
local nField=1 nStart=1
local nFirst,nLast = self:find(sSeparator, nStart, bPlain)
while nFirst and nMax ~= 0 do
aRecord[nField] = self:sub(nStart, nFirst-1)
nField = nField+1
nStart = nLast+1
nFirst,nLast = self:find(sSeparator, nStart, bPlain)
nMax = nMax-1
end
aRecord[nField] = self:sub(nStart)
end
return aRecord
end
The input: "1316982303 Searching server"
msglist = string.split(msg, ' ')
Gives me the error in the title. Any ideas? I'm fairly certain it's just the function is out of date.
Edit: lots more code
Here's some more from the main.lua file:
multiplayer = pubnub.new({
publish_key = "demo",
subscribe_key = "demo",
secret_key = nil,
ssl = nil, -- ENABLE SSL?
origin = "pubsub.pubnub.com" -- PUBNUB CLOUD ORIGIN
})
multiplayer:subscribe({
channel = "MBPocketChange",
callback = function(msg)
-- MESSAGE RECEIVED!!!
print (msg)
msglist = string.split(msg, ' ')
local recipient = msglist[0] --Get the value
table.remove(msglist, 0) --Remove the value from the table.
local cmdarg = msglist[0]
table.remove(msglist, 0)
arglist = string.split(cmdarg, ',')
local command = arglist[0]
table.remove(arglist, 0)
argCount = 1
while #arglist > 0 do
argname = "arg" .. argCount
_G[argname] = arglist[0]
table.remove(arglist, 0)
argCount = argCount + 1
end
Server.py:
This is the multiplayer server that sends the necessary info to clients.
import sys
import tornado
import os
from Pubnub import Pubnub
## Initiat Class
pubnub = Pubnub( 'demo', 'demo', None, False )
## Subscribe Example
def receive(message) :
test = str(message)
msglist = test.split()
recipient = msglist.pop(0)
msg = msglist.pop(0)
id = msglist.pop(0)
if id != "server":
print id
print msg
commandHandler(msg,id)
return True
def commandHandler(cmd,id):
global needOp
needOp = False
global matchListing
if server is True:
cmdArgList = cmd.split(',')
cmd = cmdArgList.pop(0)
while len(cmdArgList) > 0:
argument = 1
locals()["arg" + str(argument)] = cmdArgList.pop(0)
argument += 1
if cmd == "Seeking":
if needOp != False and needOp != id:
needOp = str(needOp)
id = str(id)
pubnub.publish({
'channel' : 'MBPocketChange',
#Message order is, and should remain:
#----------Recipient, Command,Arguments, Sender
'message' : needOp + " FoundOp," + id + " server"
})
print ("Attempting to match " + id + " with " + needOp + ".")
needOp = False
matchListing[needOp] = id
else:
needOp = id
pubnub.publish({
'channel' : 'MBPocketChange',
#Message order is, and should remain:
#----------Recipient, Command,Arguments, Sender
'message' : id + ' Searching server'
})
print "Finding a match for: " + id
elif cmd == "Confirm":
if matchListing[id] == arg1:
pubnub.publish({
'channel' : 'MBPocketChange',
#Message order is, and should remain:
#----------Recipient, Command,Arguments, Sender
'message' : arg1 + ' FoundCOp,' + id + ' server'
})
matchListing[arg1] = id
else:
pass #Cheater.
elif cmd == "SConfirm":
if matchListing[id] == arg1 and matchListing[arg1] == id:
os.system('python server.py MBPocketChange' + arg1)
#Here, the argument tells both players what room to join.
#The room is created from the first player's ID.
pubnub.publish({
'channel' : 'MBPocketChange',
#Message order is, and should remain:
#----------Recipient, Command,Arguments, Sender
'message' : id + ' GameStart,' + arg1 + ' server'
})
pubnub.publish({
'channel' : 'MBPocketChange',
#Message order is, and should remain:
#----------Recipient, Command,Arguments, Sender
'message' : arg1 + ' GameStart,' + arg1 + ' server'
})
else:
pass #hax
else:
pass
def connected():
pass
try:
channel = sys.argv[1]
server = False
print("Listening for messages on '%s' channel..." % channel)
pubnub.subscribe({
'channel' : channel,
'connect' : connected,
'callback' : receive
})
except:
channel = "MBPocketChange"
server = True
print("Listening for messages on '%s' channel..." % channel)
pubnub.subscribe({
'channel' : channel,
'connect' : connected,
'callback' : receive
})
tornado.ioloop.IOLoop.instance().start()
This error message happens if you run:
string.split(nil, ' ')
Double check your inputs to be sure you are really passing in a string.
Edit: in particular, msglist[0] is not the first position in the array in Lua, Lua arrays start at 1.
As an aside, this function was written when the intention that you'd use the colon syntactic sugar, e.g.
msglist=msg:split(' ')

Resources