I created a Class and created many instances and stored it into an array called messages
If I type,
print messages[0]
It gives
#<SMSMessage:0x00000001681d88 #id=29185, #account_id=1565, #upload_id=0, #txaction_type_id=9, #txid=0, #finanalytics_txid=1565,
#date_posted=2015-05-13 17:58:01 +0530, #sequence=1, #sic_code=0,
#amount=-1802.0, #raw_name="MERLINS", #filtered_name="MERLINS",
#cleaned_name="NULL", #merchant_id="NULL", #memo="NULL",
#check_num="NULL", #ref_num="NULL", #balance=0.0, #created_at=2015-05-13 18:03:30 +0530,
#updated_at=2015-05-13 18:08:17 +0530, #status="0", #tagged=0, #merged_with_txaction_id=0, #note="NULL", #usd_amount=0.0, #attachment_ids="NULL", #automatch=0, #merchant_name="MERLINS", #tag_names=nil, #transfer_txaction_id=0, #fi_date_posted=2015-05-13 17:58:01 +0530, #transaction_status_id=0, #mc_code="NULL", #provider_txn_type="NULL", #latitude=19.09686, #longitude=72.8537753, #sync_status=31, #sec_account_id=0, #associated_sms_id=130672, #account_key="YzI5ZDUyNWY5NmYwNWFiNjJiYmE1YTk4Y2VkYTBjYTZmOGM5ZTI0NzE2MzU2MzAwMmU2OWU2MzNiYmQ2YTZhMA==", #id_on_client=229, #sync_delete_status=0,
#matching_bill_id=0, #mapped_account_number=0, #additional_description="NULL", #category_id=45, #data_processing_flag=4,
#derived_description="NULL", #final_description="NULL", #derived_merchant="Merlins Bar", #final_merchant="NULL",
#tentative_location_flag=-1, #tentative_latitude="-90.00000000000", #tentative_longitude="-90.00000000000", #mongo_merchant_id="102", #parent_category_id=40, #raw_description="NULL", #formatted_description="NULL", #associated_sms_client_id=779, #account_client_id=4>
If i try to access the ID by typing,
print messages[0].id
It gives me an error
NoMethodError: undefined method `id' for #<SMSMessage:0x00000001681d88>
How do I resolve this ?
PS - The SMSMessage Class Code is
class SMSMessage
def initialize(id,account_id,upload_id,txaction_type_id,txid,finanalytics_txid,date_posted,sequence,sic_code,amount,raw_name,filtered_name,cleaned_name,merchant_id,memo,check_num,ref_num,balance,created_at,updated_at,status,tagged,merged_with_txaction_id,note,usd_amount,attachment_ids,automatch,merchant_name,tag_names,transfer_txaction_id,fi_date_posted,transaction_status_id,mc_code,provider_txn_type,latitude,longitude,sync_status,sec_account_id,associated_sms_id,account_key,id_on_client,sync_delete_status,matching_bill_id,mapped_account_number,additional_description,category_id,data_processing_flag,derived_description,final_description,derived_merchant,final_merchant,tentative_location_flag,tentative_latitude,tentative_longitude,mongo_merchant_id,parent_category_id,raw_description,formatted_description,associated_sms_client_id,account_client_id)
#id = id.to_i
#account_id = account_id.to_i
#upload_id = upload_id.to_i
#txaction_type_id = txaction_type_id.to_i
#txid = txid.to_i
#finanalytics_txid = finanalytics_txid.to_i
#date_posted = Time.parse(date_posted)
#sequence = sequence.to_i
#sic_code = sic_code.to_i
#amount = amount.to_f
#raw_name = raw_name
#filtered_name = filtered_name
#cleaned_name = cleaned_name
#merchant_id = merchant_id
#memo = memo
#check_num = check_num
#ref_num = ref_num
#balance = balance.to_f
#created_at = Time.parse(created_at)
#updated_at = Time.parse(updated_at)
#status = status
#tagged = tagged.to_i
#merged_with_txaction_id = merged_with_txaction_id.to_i
#note = note
#usd_amount = usd_amount.to_f
#attachment_ids = attachment_ids
#automatch = automatch.to_i
#merchant_name = merchant_name
#tag_names = tag_names
#transfer_txaction_id = transfer_txaction_id.to_i
#fi_date_posted = Time.parse(fi_date_posted)
#transaction_status_id = transaction_status_id.to_i
#mc_code = mc_code
#provider_txn_type = provider_txn_type
#latitude = latitude.to_f
#longitude = longitude.to_f
#sync_status = sync_status.to_i
#sec_account_id = sec_account_id.to_i
#associated_sms_id = associated_sms_id.to_i
#account_key = account_key
#id_on_client = id_on_client.to_i
#sync_delete_status = sync_delete_status.to_i
#matching_bill_id = matching_bill_id.to_i
#mapped_account_number = mapped_account_number.to_i
#additional_description = additional_description
#category_id = category_id.to_i
#data_processing_flag = data_processing_flag.to_i
#derived_description = derived_description
#final_description = final_description
#derived_merchant = derived_merchant
#final_merchant = final_merchant
#tentative_location_flag = tentative_location_flag.to_i
#tentative_latitude = tentative_latitude.to_f
#tentative_longitude = tentative_longitude.to_f
#mongo_merchant_id = mongo_merchant_id
#parent_category_id = parent_category_id.to_i
#raw_description = raw_description
#formatted_description = formatted_description
#associated_sms_client_id = associated_sms_client_id.to_i
#account_client_id = account_client_id.to_i
end
end
Since you do not define accessor methods for object attributes, you should use instance_variable_get:
messages[0].instance_variable_get(:#id)
To be able to read id attribute (that is messages[0].id) you would want to add
attr_reader :id
to your model. If you will need to write this attribute, you would define attr_writer :id.
For both (read and write) there is a attr_accessor :id.
Related
I write a multiplayer game(snake) with backend based on Ruby. This function must receive commands for frontend and send the current state of the game. But throw NoMethod error on the four line of my function for the changeside method and I don't know why because of that class method is present.
Class method example
def changeside(nump,newSide)
opp = {'R':'L','U':'D','D':'U','L':'R'}
cx = {'L':-1,'R':1,'U':0,'D':0}
cx = {'L':0,'R':0,'U':-1,'D':1}
if newSide!=opposite[players[nump]['side']] && ['R','L','U','D'].count( newSide)==1
players[nump]['side']['cx'] = cx[newSide]
players[nump]['side']['cy'] = cy[newSide]
end
end
Error example
2020-10-07 18:01:23 - NoMethodError - undefined method `[]' for nil:NilClass:
The function I'm run
def getStatus(game)
ans = {"opStatus"=>TRUE}
puts game
$games[game['gid'.to_i]]['game'].changeside(2,game['side'])
$games[game['gid'.to_i]]['game'].move(($games[game['gid']]['fid']==game['pid']?1:2))
ans["gameStatus"] = $games[game['id']]['game'].run
ans['timer'] = $games[game['id']]['game'].timer
ans['snake'] = $games[game['id']][($games[game['id']]['fid']==game['pid']?1:2)].snake
ans['enemy'] = $games[game['id']][($games[game['id']]['fid']==game['pid']?2:1)].snake
ans['food'] = $games[game['id']]['game'].food
end
Here is JSON sent to the function
{"gid"=>"1", "side"=>"R", "pid"=>"1"}
To fix that, I debugged that moment, but I couldn't go inside a class method.
Here is the full code of the class game.
It located in another file and called by
`require_relative 'game.rb'`
Full code of the class.
class Game
attr_accessor :players, :food, :walls, :timer, :run,:winner
def initialize()
#players = {}
#winner = -1
#players[1] = {'snake'=>[[9,2],[8,2],[7,2]]}
#players[1]['cx'] = 0
#players[1]['cy'] = -1
#players[1]['side'] = 'U'
#players[2] = {'snake'=>[[2,9],[2,8],[2,7]]}
#players[2]['cx'] = -1
#players[2]['cy'] = 0
#players[2]['side'] = 'L'
#timer = 0
#run = FALSE
genFood
end
def genFood()
#food = [rand(10)+1,rand(10)+1]
while players[1]['snake'].include?(food) || players[2]['snake'].include?(food)
#food = [rand(10)+1,rand(10)+1]
end
end
def move(nump)
if #run
#timer+=0.25
#players[nump]['snake'].shift
#players[nump]['snake'].push([#players[id]['snake'][0]+#players[id]['cx'],#players[id]['snake'][1]+#players[id]['cy']])
if #players[nump]['snake'][0] == food
#players[nump]['snake'][0].unshift(food)
#food = [rand(10)+1,rand(10)+1]
while players[nump]['snake'].include(food) or players[1]['snake'].include(food)
#food = [rand(10)+1,rand(10)+1]
end
end
if #player[nump]['snake'].count(#player[nump]['snake'][-1])==2 ||
#winner = ((nump==1)?2:1)
elsif #players[((nump==1)?2:1)]['snake'].count(#player[nump]['snake'][-1])==1
#winner = 0
else
if #timer==60
if #players[1]['snake'].length()>#players[2]['snake'].length()
#winner = 1
elsif #players[1]['snake'].length()<#players[2]['snake'].length()
winner = 2
else
winner = 0
end
end
end
end
end
def changeside(nump,newSide)
opp = {'R':'L','U':'D','D':'U','L':'R'}
cx = {'L':-1,'R':1,'U':0,'D':0}
cx = {'L':0,'R':0,'U':-1,'D':1}
if newSide!=opposite[players[nump]['side']] && ['R','L','U','D'].count( newSide)==1
players[nump]['side']['cx'] = cx[newSide]
players[nump]['side']['cy'] = cy[newSide]
end
end
end
The csv file gets created when I scrape but it doesn't display in the terminal. I want to display each row onto the screen
def get_aspley_data
url = "https://www.domain.com.au/rent/aspley-qld-4034/?price=0-900"
unparsed_page = HTTParty.get(url)
parsed_page = Nokogiri::HTML(unparsed_page)
house_listings = parsed_page.css('.listing-result__details')
house_listings.each do |hl|
prop_type = hl.css('.listing-result__property-type')[0]
price = hl.css('.listing-result__price')[0]
suburb_address = hl.css('span[itemprop=streetAddress]')[0]
house_array = [house_listings]
house_array.push("#{prop_type} #{price}")
aspley_dis = CSV.open($aspley_file, "ab", {:col_sep => "|"}) do |csv|
csv << [prop_type, price, suburb_address]
end
end
end
Try below one
def get_aspley_data
url = "https://www.domain.com.au/rent/aspley-qld-4034/?price=0-900"
unparsed_page = HTTParty.get(url)
parsed_page = Nokogiri::HTML(unparsed_page)
house_listings_data = []
house_listings = parsed_page.css('.listing-result__details')
house_listings.each do |hl|
prop_type = hl.css('.listing-result__property-type')[0]
price = hl.css('.listing-result__price')[0]
suburb_address = hl.css('span[itemprop=streetAddress]')[0]
house_array = [house_listings]
house_array.push("#{prop_type} #{price}")
house_listings_data << [prop_type, price, suburb_address]
puts [prop_type, price, suburb_address].to_csv(col_sep: "|")
end
File.open($aspley_file, "ab") do |f|
data = house_listings_data.map{ |d| d.to_csv(col_sep: "|") }.join
f.write(data)
end
end
This is the hash I'm trying to format
input = {"test_key"=>"test_value", "test_key2"=>"test_value2"}
And this is the expected result
"{\n\t\"test_key\" = \"test_value\";\n\t\"test_key2\" = \"test_value2\";\n}"
I have the following code so far
def format_hash(hash)
output = ""
hash.to_s.split(',').each do |k|
new_string = k + ';'
new_string.gsub!('=>', ' = ')
output += new_string
end
end
which gives me the this output
output = "{\"test_key\" = \"test_value\"; \"test_key2\" = \"test_value2\"};"
But I'm still struggling with adding the rest. Any ideas/suggestions?
input = {"test_key"=>"test_value", "test_key2"=>"test_value2"}
"{" << input.map { |k,v| "\n\t\"#{k}\" = \"#{v}\"" }.join(';') << ";\n}"
#=> "{\n\t\"test_key\" = \"test_value\";\n\t\"test_key2\" = \"test_value2\";\n}"
The steps are as follows.
a = input.map { |k,v| "\n\t\"#{k}\" = \"#{v}\"" }
#=> ["\n\t\"test_key\" = \"test_value\"", "\n\t\"test_key2\" = \"test_value2\""]
b = a.join(';')
#=> "\n\t\"test_key\" = \"test_value\";\n\t\"test_key2\" = \"test_value2\""
"{" << b << ";\n}"
#=> "{\n\t\"test_key\" = \"test_value\";\n\t\"test_key2\" = \"test_value2\";\n}"
input may contain any number of key-value pairs that adhere to the indicated pattern.
One starting point might be to use JSON formatter:
require 'json'
input = {"test_key"=>"test_value", "test_key2"=>"test_value2"}
JSON.pretty_generate(input)
=> "{\n \"test_key\": \"test_value\",\n \"test_key2\": \"test_value2\"\n}"
This has some subtle differences, since it looks like you use = as opposed to :. That said, perhaps it's easier to work from this than from what you have.
Working with JSON
JSON.pretty_generate(input).gsub(/:/,' =').gsub(/,(?=\n)/, ';').gsub(/(;\n|\n)\s+/, '\1'+"\t")
=> "{\n\t\"test_key\" = \"test_value\";\n\t\"test_key2\" = \"test_value2\"\n}"
Custom Formatter
Of course you could define your custom formatter:
def formatter(hash)
output = ""
output += "{\n\t"
output += hash.entries.map{|a| "\"#{a[0]}\" = \"#{a[1]}\"" }.join(";\n\t")
output += ";\n}"
end
formatter( input )
I am struggling to understand how I can access an array with a hash key. In my code, I create a hash with keys and values. Now, I want to set the values in a Car class. Whenever I try to instantiate the Car, the argument expects Integer and not a String.
I am getting the following error: TypeError (no implicit conversion of String into Integer)
Here is my code:
class Car_maker
attr_accessor :car_maker
def initialize(car_maker)
#car_maker = car_maker
end
end
class Car_model < Car_maker
attr_accessor :km, :type, :transmission, :stock, :drivetrain, :status,
:fuel, :car_maker, :model, :year, :trim, :features
#total number of instances & array with car objects
##totalCars = 0
##catalogue = []
def initialize(km, type, transmission, stock, drivetrain, status, fuel, car_maker, model, year, trim, features)
super(car_maker)
#km = km
#type = type
#transmission = transmission
#stock = stock
#drivetrain = drivetrain
#status = status
#fuel = fuel
#model = model
#year = year
#trim = trim
#features = features
##totalCars += 1
end
def self.convertListings2Catalogue(line)
#Initialise arrays and use them to compare
type = ["Sedan", "coupe", "hatchback", "station", "SUV"]
transmission = ["auto", "manual", "steptronic"]
drivetrain = ["FWD", "RWD", "AWD"]
status = ["new", "used"]
car_maker = ["honda", "toyota", "mercedes", "bmw", "lexus"]
hash = Hash.new
#In this part, we hash the set of features using regex
copyOfLine = line
regex = Regexp.new(/{(.*?)}/)
match_array = copyOfLine.scan(regex)
match_array.each do |line|
hash["features"] = line
end
#Now, we split every comma and start matching fields
newStr = line[0...line.index('{')] + line[line.index('}')+1...line.length]
arrayOfElements = newStr.split(',')
arrayOfElements.each do |value|
if value.include?("km") and !value.include?("/")
hash["km"] = value
elsif type.include?(value)
hash["type"] = value
elsif transmission.include?(value.downcase)
hash["transmission"] = value
elsif value.include?("/") and value.include?("km")
hash["fuel economy"] = value
elsif drivetrain.include?(value)
hash["drivetrain"] = value
elsif status.include?(value.downcase)
hash["status"] = value
elsif /(?=.*[a-zA-Z])(?=.*[0-9])/.match(value) and !value.include?("km")
hash["stock"] = value
elsif car_maker.include?(value.downcase)
hash["carmaker"] = value
elsif /^\d{4}$/.match(value)
hash["year"] = value
elsif value.length == 2
hash["trim"] = value
else
if value.length > 2
hash["model"] = value
end
end
end
end
end
textFile = File.open('cars.txt', 'r')
textFile.each_line{|line|
if line.length > 2
result = Car_model.convertListings2Catalogue(line)
puts "Hash: #{result}"
carObj = Car_model.new(result["km"], result["type"], result["transmission"], result["stock"], result["drivetrain"],
result["status"], result["fuel"], result["carmaker"], result["model"], result["year"], result["trim"], result["features"])
###catalogue.push (carObj)
end
}
This line
result = Car_model.convertListings2Catalogue(line)
Doesn't return the hash object. It returns arrayOfElements since that's what the each method actually returns and the each method is the last method executed in the method (although there are hash assignments within it, it's only the last value that's returned unless you use an explicit return statement.
Just use the variable hash in the last line of the convertListing2Catalog method
if value.length > 2
hash["model"] = value
end
end
end
hash # < this is the last line of the method so it's the value that will be returned
end
end
If you think about it, there were several variables created in the method. There's no reason to expect that the contents of any specific variable such as hash would be returned, and ruby methods by default return the last executed command.
So I'm very confused here. When I use the scrapy shell and input the xpath the correct data is returned, but when I set that same xpath equal to a variable within the script, it outputs a blank. I'm really not sure what is going on.
import scrapy
class FestivalSpider(scrapy.Spider):
name = 'basketball'
custom_settings = {
"DOWNLOAD_DELAY": 3,
"CONCURRENT_REQUESTS_PER_DOMAIN": 3,
"HTTPCACHE_ENABLED": True
}
start_urls = [
'http://www.basketball-reference.com/leagues/NBA_2017_per_game.html'
]
def parse(self, response):
start_urls = [
'http://www.basketball-reference.com/leagues/NBA_2017_per_game.html']
for href in start_urls:
yield scrapy.Request(
url=href,
callback=self.parse_festival,
meta={'url': href}
)
def parse_festival(self, response):
url = response.request.meta['url']
name = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "player"]/a/text()').extract()
pos = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "pos"]/text()').extract()
age = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "age"]/text()').extract()
#team = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "team_id"]/text()').extract()
games = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "g"]/text()').extract()
games_s = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "gs"]/text()').extract()
fg_per_mp = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "fg_per_mp"]/text()').extract()
#fga_per_mp = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "fga_per_mp"]/text()').extract()
#fg_pct = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "fg_pct"]/text()').extract()
#fg3_per_mp = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "fg3_per_mp"]/text()').extract()
#fg3a_per_mp = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "fg3a_per_mp"]/text()').extract()
#fg3_pct = response.xpath('//tr[#class = "full_table"]/td[#data-stat = "fg3_pct"]/text()').extract()
#location = (
# response.xpath('//div[#id="festival-basics"]/text()').extract()[3])
#dates = (
# response.xpath('//div[#id="festival-basics"]/text()').extract()[5])
#tickets = (
# response.xpath('//div[#id="festival-basics"]/text()').extract()[7])
#website = (
# response.xpath(
# '//div[#id="festival-basics"]/a/#href').extract()[0]
#)
#logo = (
# response.xpath(
# '//div[#id="festival-basics"]/img/#src').extract()[0]
#)
#lineup = (
# response.xpath(
# '//div[#class="lineupguide"]/ul/li/text()').extract() +
# response.xpath(
# '//div[#class="lineupguide"]/ul/li/a/text()').extract()
#)
print(response.xpath('//tr[#class = "full_table"]/td[#data-stat = "fg_per_mp"]/text()').extract())
yield {
'url': url,
'name': name,
'pos': pos,
'age' : age,
'games' : games,
'games_s': games_s,
'fg_per_mp': fg_per_mp
#'fga_per_mp': fga_per_mp,
#'fg_pct': fg_pct,
#'fg3_per_mp': fg3_per_mp,
#'fg3a_per_mp': fg3a_per_mp
#'team' : team
#'location': location,
#'dates': dates,
#'tickets': tickets,
#'website': website,
#'logo': logo,
#'lineup': lineup
}
The item in question is the fg_per_mp, when I use the response.xpath('//tr[#class = "full_table"]/td[#data-stat = "fg_per_mp"]/text()').extract() in the shell it works, but the same line in the script returns an empty list.
What am I doing wrong?