Cannot convert Array into String (Ruby) - ruby

I'm having trouble with this code (again).
I'm trying to get Ruby to check if tree is equal to any of the items in $do_not_scan and all I'm getting is a "cannot convert Array into String" error. Any way to fix such a thing?
My code:
#filesniffer by Touka, ©2015
$filecount = 0
$trees = Dir.entries("C:\\")
$do_not_scan = ["bootmgr", "BOOTNXT", "USER", ".", "Documents and Settings", "PerfLogs", "System Recovery", "System Volume Information", "$RECYCLE.BIN"]
def scan
$trees.each do |tree|
unless tree.include?($do_not_scan[0...8])
puts "scanning #{tree}"
entries = Dir.entries("c:\\#{tree}")
entries.each do |filename|
if filename == "**\*.dll"
puts "Found #{filename} in #{tree}"
end
end
end
end
end
def scan_loop
$trees.each do |tree|
scan
unless tree.include?($do_not_scan[0...8])
subtrees = Dir.entries("#{tree}")
subtrees.each do |tree|
scan
scan_loop
end
end
end
end
scan_loop
sleep

It looks like the following have to change in the scan and scan_loop methods:
$do_not_scan[0...8].include?(tree)
In place off:
tree.include?($do_not_scan[0...8])

Related

dealing with a file path argument: no implicit conversion of nil into String

I am writing a short ruby script that takes a file as an argument and then parses that file.
I have put together a few conditions in the initialize method to ensure that a file path exists and it is readable and if it nots it prints an error message to the user.
However when I run the file with out a file attached along side the message "please add log file path". I also receive the following error messages.
please add log file path
Traceback (most recent call last):
3: from webserver_log_parser.rb:41:in `<main>'
2: from webserver_log_parser.rb:41:in `new'
1: from webserver_log_parser.rb:6:in `initialize'
webserver_log_parser.rb:6:in `exist?': no implicit conversion of nil into String (TypeError)
I would be really grateful if someone could explain why this happens and a way to fix this issue.
def initialize(log_file_path = nil)
puts 'please add log file path' unless log_file_path
puts 'Could not find the file path' unless File.exist?(log_file_path)
puts '${log_file_path} is unreadable' unless File.readable?(log_file_path)
extract_log_file(log_file_path)
end
def extract_log_file(log_file_path)
webpages = Hash.new { |url, ip_address| url[ip_address] = [] }
File.readlines(log_file_path).each do |line|
url, ip_address = line.split
webpages[url] << ip_address
end
sort_results(webpages)
end
def sort_results(results)
total_views = {}
unique_views = {}
results.each do |url, ip_address|
total_views[url] = ip_address.length
unique_views[url] = ip_address.uniq.length
end
display_results(total_views, unique_views)
end
def display_results(views, unique_views)
puts 'The most viewed pages are as follows:'
total_views_sorted = views.sort_by { |_k, count| -count }
total_views_sorted.each { |key, count| puts "#{key} #{count}" }
puts 'The pages with the most unique views are as follows:'
unique_sort = unique_views.sort_by { |_k, count| -count }
unique_sort.each { |key, count| puts "#{key} #{count}" }
end
end
if $PROGRAM_NAME == __FILE__
LogParser.new(ARGV[0])
end```
If you want to directly terminate the script with a message, you can use abort.
def initialize(log_file_path = nil)
abort("please add log file path") unless log_file_path
abort("Could not find the file path") unless File.exist?(log_file_path)
abort("${log_file_path} is unreadable") unless File.readable?(log_file_path)
extract_log_file(log_file_path)
end
When your guard conditions are triggered, you need to stop further processing (no need to check for readability of a file at file_path if you already established that file_path is nil). It could look like this, for example:
def initialize(log_file_path = nil)
unless log_file_path
puts 'please add log file path'
return
end
unless File.exist?(log_file_path)
puts 'Could not find the file path'
return
end
unless File.readable?(log_file_path)
puts '${log_file_path} is unreadable'
return
end
extract_log_file(log_file_path)
end

Running through multiple command line parameters

This is a school assignment I've been working on this for a while now and it only works with 1 parameter given. I've tried a lot of different scenarios using ARGV and think I'm just missing something.
This program is supposed to run through as many directories as given in the command line. It should default to the current working directory if no parameters are given.
I'll provide the code that works for one parameter. Again, I just need to be able to have this take in multiple parameters.
directory = ARGV[0] || Dir.pwd
searchstring = Regexp.new "(\\.[^.]+)$"
extensions = Hash.new {|hash, key| hash[key] = {size: 0, count: 0}}
if File.exists? File.expand_path(directory)
Dir["#{File.expand_path(directory)}/*/**"].each.map do |f|
if File.basename(f) =~ searchstring
extensions[File.extname(f)][:size] += File.stat(f).size
extensions[File.extname(f)][:count] += 1
end
end
else
puts "This directory does not exist"
end
puts (extensions.map{ |k,v| "Extension: #{k} => #{v}"}.sort)
EDIT: I also just noticed that it's only going through subdirectories. I know I can make it go through just the given directory by getting rid of the extra /** earlier when I'm looping through my filenames. How do I make it look at both the directory given and all of its subdirectories?
I also think I've pretty much answered my own question with what I originally answered with cycling through mulitple arguments. However, I still don't know how to go through all subdirectories. I'll post my latest code so everyone can see the difference.
ARGV[0]=Dir.pwd if ARGV.length < 1
for i in 0 ... ARGV.length
directory=ARGV[i]
searchstring = Regexp.new "(\\.[^.]+)$"
extensions = Hash.new {|hash, key| hash[key] = {size: 0, count: 0}}
if File.exists? File.expand_path(directory)
Dir["#{File.expand_path(directory)}/*"].each.map do |f|
if File.basename(f) =~ searchstring
extensions[File.extname(f)][:size] += File.stat(f).size
extensions[File.extname(f)][:count] += 1
end
end
else
puts "This directory does not exist"
end
puts "#{directory}"
puts (extensions.map{ |k,v| "Extension: #{k} => #{v}"}.sort)
end

loop through json array and retrieve one attribute, gives errors also

i am new to programming in ruby, and i am trying to get the value of json['earning_rate_hr'] but i get an error, in '[]': no implicit conversion of String into Integer (TypeError)
i know and i understand the error, however this is not my main question here is my file :
checkingchecker.rb :
#require_relative '../lib/hackex/net/typhoeus'
require_relative '../lib/hackex'
require 'rubygems'
require 'json'
file = 'accounts1.txt'
f = File.open file, 'r'
puts "MADE BY THE PEOPLE, FOR THE PEOPLE #madebylorax"
puts ""
puts "--------------------------------------------------------"
puts ""
while line = f.gets
line = line.chomp.split(';')
email, password = line
puts "logging in as " + email
HackEx.LoginDo(email, password) do |http, auth_token, user|
puts "getting info..."
user = HackEx::Request.Do(http, HackEx::Request.UserInfo(auth_token))['user']
puts "receieved user info!"
bank = HackEx::Request.Do(http, HackEx::Request.UserBank(auth_token))['user_bank']
puts "recieved bank info!"
json = HackEx::Request.Do(http, HackEx::Request.UserSpam(auth_token))['spam']
puts "recieved spam info!"
puts json['earning_rate_hr'] #error line, the error is because this is an array, and it cant be turned into integer, i was wondering if there is a way to use puts on it without trying to make it an integer
userchecking = bank["checking"]
checking = userchecking.scan(/.{1,3}/).join(',')
puts email + " has in Checking: BTC #{checking}"
puts ""
puts "--------------------------------------------------------"
puts ""
end
end
i tried to do puts json, it puts items like this one :
{"id"=>"9867351", "user_id"=>"289108", "victim_user_id"=>"1512021",
"victim_ip"=
"86.60.226.175", "spam_level"=>"50", "earning_rate_hr"=>"24300", "total_earning s"=>"13267800", "started_at"=>"2015-11-01 07:46:59",
"last_collected_at"=>"2015- 11-24 01:46:59"}
what i want to do is select the earning_rate_hr for each one of them and add them together, however i do not have a clue on how to do that, since the error is not fixed and i cant get the value of it
ps : i tried turning it into a Hash, and i also tried using .first, but .first only shows the firs one, i want to show all of them, thank you
I know you from line messenger, I haven't used ruby codes in a long time and this one keeps giving me cloudflare errors, I'm not sure if its because of server downtime/maintainance or whatever but yeah anyway heres your script, enjoy farming ;) -LineOne
PS, I changed a few strings to make it look a lil cleaner so you can see the spam income easier, and added the sleep (1) because sleeping for one second before reconnecting helps to prevent cloudflare errors
also you don't need to require json or rubygems in your hackex scripts because its required in the library so its all covered pre-user-input/script
require_relative 'libv5/lib/hackex'
while 1<2
begin
print'Filename: '
fn=gets.chomp
file = fn+'.txt'
f = File.open file, 'r'
puts "MADE BY THE PEOPLE, FOR THE PEOPLE #madebylorax" #helped by lineone
puts ""
puts "--------------------------------------------------------"
puts ""
while line = f.gets
line = line.chomp.split(';')
email, password = line
HackEx.LoginDo(email, password) do |http, auth_token, user|
puts "Retrieving Info..."
puts''
user = HackEx::Request.Do(http, HackEx::Request.UserInfo(auth_token))['user']
bank = HackEx::Request.Do(http, HackEx::Request.UserBank(auth_token))['user_bank']
json = HackEx::Request.Do(http, HackEx::Request.UserSpam(auth_token))['spam']
cash_count=0
tot_count=0
json.each do |j|
earn_rate = j['earning_rate_hr']
total= j['total_earnings']
cash_count+=earn_rate.to_i
tot_count+=total.to_i
end
print "#{email}: current earnings: #{cash_count} per hour, Total earnings #{tot_count},"
userchecking = bank["checking"]
checking = userchecking.scan(/.{1,3}/).join(',')
puts " #{checking} BTC in Checking"
puts ""
puts "--------------------------------------------------------"
puts ""
sleep 1
end
end
rescue
puts"#{$!}"
end
end
Thats fine you can also calculate the total income of your farms by adding new variables at the top example a=0 then adding the number at the end a+=tot_count
This should help:
earning_rates = json.map{|e| e["earning_rate_hr"]}
puts "Earning rates per hour: #{earning_rates.join(" ")}"
puts "Sum of earning rates: #{earning_rates.map{|e| e.to_i}.inject{|sum, x| sum + x}}"

Ruby method variable declaration

I'm trying to define methods to parse through an apache log file and pull ip addresses, URLs, requests per hour, and error codes. I've got everything working outside of methods, but when attempting to put that code into the methods I keep getting the error message "Stack level too deep." Here is the code in question.
class CommonLog
def initialize(logfile)
#logfile = logfile
end
def readfile
#readfile = File.readlines(#logfile).map { |line|
line.split()
}
#readfile = #readfile.to_s.split(" ")
end
def ip_histogram
#ip_count = 0
#readfile.each_index { |index|
if (#readfile[index] =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ )
puts #readfile[index]
puts #ip_count += 1
end
}
end
def url_histogram
url_count = 0
cleaned_file.each_index { |index|
if (cleaned_file[index] =~ /\/{1}(([a-z]{4,})|(\~{1}))\:{0}\S+/ )
puts cleaned_file[index]
puts url_count += 1
end
}
end
def requests_per_hour
end
def sorted_list
end
end
my_file = CommonLog.new("test_log")
cleaned_file = my_file.readfile
puts cleaned_file.ip_histogram
It looks like the problem lies on you CommonLog#readfile method:
def readfile
#readfile = File.readlines(#logfile).map { |line|
line.split()
}
#readfile = readfile.to_s.split(" ")
end
Notice that inside the implementation of readfile your calling readfile recursively? When it executes it reads the lines from the file, maps them and assign the result the #readfile; then it calls readfile and the method starts to execute again; this goes on forever, until you stack blows up because of too many recursive method calls.
I assume what you actually meant is:
#readfile = #readfile.to_s.split(" ")

Calling multiple methods on a CSV object

I have constructed an Event Manager class that performs parsing actions on a CSV file, and produces html letters using erb. It is part of a jumpstart labs tutorial
The program works fine, but I am unable to call multiple methods on an object without the earlier methods interfering with the later methods. As a result, I have opted to create multiple objects to call instance methods on, which seems like a clunky inelegant solution. Is there a better way to do this, where I can create a single new object and call methods on it?
Like so:
eventmg = EventManager.new("event_attendees.csv")
eventmg.print_valid_phone_numbers
eventmg_2 = EventManager.new("event_attendees.csv")
eventmg_2.print_zipcodes
eventmg_3 = EventManager.new("event_attendees.csv")
eventmg_3.time_targeter
eventmg_4 = EventManager.new("event_attendees.csv")
eventmg_4.day_of_week
eventmg_5 = EventManager.new("event_attendees.csv")
eventmg_5.create_thank_you_letters
The complete code is as follows
require 'csv'
require 'sunlight/congress'
require 'erb'
class EventManager
INVALID_PHONE_NUMBER = "0000000000"
Sunlight::Congress.api_key = "e179a6973728c4dd3fb1204283aaccb5"
def initialize(file_name, list_selections = [])
puts "EventManager Initialized."
#file = CSV.open(file_name, {:headers => true,
:header_converters => :symbol} )
#list_selections = list_selections
end
def clean_zipcode(zipcode)
zipcode.to_s.rjust(5,"0")[0..4]
end
def print_zipcodes
puts "Valid Participant Zipcodes"
#file.each do |line|
zipcode = clean_zipcode(line[:zipcode])
puts zipcode
end
end
def clean_phone(phone_number)
converted = phone_number.scan(/\d/).join('').split('')
if converted.count == 10
phone_number
elsif phone_number.to_s.length < 10
INVALID_PHONE_NUMBER
elsif phone_number.to_s.length == 11 && converted[0] == 1
phone_number.shift
phone_number.join('')
elsif phone_number.to_s.length == 11 && converted[0] != 1
INVALID_PHONE_NUMBER
else
phone_number.to_s.length > 11
INVALID_PHONE_NUMBER
end
end
def print_valid_phone_numbers
puts "Valid Participant Phone Numbers"
#file.each do |line|
clean_number = clean_phone(line[:homephone])
puts clean_number
end
end
def time_targeter
busy_times = Array.new(24) {0}
#file.each do |line|
registration = line[:regdate]
prepped_time = DateTime.strptime(registration, "%m/%d/%Y %H:%M")
prepped_time = prepped_time.hour.to_i
# inserts filtered hour into the array 'list_selections'
#list_selections << prepped_time
end
# tallies number of registrations for each hour
i = 0
while i < #list_selections.count
busy_times[#list_selections[i]] += 1
i+=1
end
# delivers a result showing the hour and the number of registrations
puts "Number of Registered Participants by Hour:"
busy_times.each_with_index {|counter, hours| puts "#{hours}\t#{counter}"}
end
def day_of_week
busy_day = Array.new(7) {0}
d_of_w = ["Monday:", "Tuesday:", "Wednesday:", "Thursday:", "Friday:", "Saturday:", "Sunday:"]
#file.each do |line|
registration = line[:regdate]
# you have to reformat date because of parser format
prepped_date = Date.strptime(registration, "%m/%d/%y")
prepped_date = prepped_date.wday
# adds filtered day of week into array 'list selections'
#list_selections << prepped_date
end
i = 0
while i < #list_selections.count
# i is minus one since days of week begin at '1' and arrays begin at '0'
busy_day[#list_selections[i-1]] += 1
i+=1
end
#busy_day.each_with_index {|counter, day| puts "#{day}\t#{counter}"}
prepared = d_of_w.zip(busy_day)
puts "Number of Registered Participants by Day of Week"
prepared.each{|date| puts date.join(" ")}
end
def legislators_by_zipcode(zipcode)
Sunlight::Congress::Legislator.by_zipcode(zipcode)
end
def save_thank_you_letters(id,form_letter)
Dir.mkdir("output") unless Dir.exists?("output")
filename = "output/thanks_#{id}.html"
File.open(filename,'w') do |file|
file.puts form_letter
end
end
def create_thank_you_letters
puts "Thank You Letters Available in Output Folder"
template_letter = File.read "form_letter.erb"
erb_template = ERB.new template_letter
#file.each do |line|
id = line[0]
name = line[:first_name]
zipcode = clean_zipcode(line[:zipcode])
legislators = legislators_by_zipcode(zipcode)
form_letter = erb_template.result(binding)
save_thank_you_letters(id,form_letter)
end
end
end
The reason you're experiencing this problem is because when you apply each to the result of CSV.open you're moving the file pointer each time. When you get to the end of the file with one of your methods, there is nothing for anyone else to read.
An alternative is to read the contents of the file into an instance variable at initialization with readlines. You'll get an array of arrays which you can operate on with each just as easily.
"Is there a better way to do this, where I can create a single new object and call methods on it?"
Probably. If your methods are interfering with one another, it means you're changing state within the manager, instead of working on local variables.
Sometimes, it's the right thing to do (e.g. Array#<<); sometimes not (e.g. Fixnum#+)... Seeing your method names, it probably isn't.
Nail the offenders down and adjust the code accordingly. (I only scanned your code, but those Array#<< calls on an instance variable, in particular, look fishy.)

Resources