I am trying to learn ruby(1.8.7). I have programmed in php for some time and I consider myself proficient in that language. I have a book which I reference, and I have looked at many introductory ruby tutorials, but I cannot figure this out.
myFiles = ['/Users/', '/bin/bash', 'Phantom.file']
myFiles.each do |cFile|
puts "File Name: #{cFile}"
if File.exists?(cFile)
puts "#{cFile} is a file"
cFileStats = File.stat(cFile)
puts cFileStats.inspect
cFileMode = cFileStats.mode.to_s()
puts "cFileMode Class: " + cFileMode.class.to_s()
puts "length of string: " + cFileMode.length.to_s()
printf("Mode: %o\n", cFileMode)
puts "User: " + cFileMode[3,1]
puts "Group: " + cFileMode[4,1]
puts "World: " + cFileMode[5,1]
else
puts "Could not find file: #{cFile}"
end
puts
puts
end
produces the following output:
File Name: /Users/
/Users/ is a file
#<File::Stat dev=0xe000004, ino=48876, mode=040755, nlink=6, uid=0, gid=80, rdev=0x0, size=204, blksize=4096, blocks=0, atime=Sun Sep 04 12:20:09 -0400 2011, mtime=Thu Sep 01 21:29:08 -0400 2011, ctime=Thu Sep 01 21:29:08 -0400 2011>
cFileMode Class: String
length of string: 5
Mode: 40755
User: 7
Group: 7
World:
File Name: /bin/bash
/bin/bash is a file
#<File::Stat dev=0xe000004, ino=8672, mode=0100555, nlink=1, uid=0, gid=0, rdev=0x0, size=1371648, blksize=4096, blocks=1272, atime=Sun Sep 04 16:24:09 -0400 2011, mtime=Mon Jul 11 14:05:45 -0400 2011, ctime=Mon Jul 11 14:05:45 -0400 2011>
cFileMode Class: String
length of string: 5
Mode: 100555
User: 3
Group: 3
World:
File Name: Phantom.file
Could not find file: Phantom.file
Wh is the string length different than expected? (Should be 5 for users, 6 for /bin/bash)? Why are the substrings not puling the correct characters. I understand World not being populated when referencing a 5 character string, but the offsets seem off, and in the case of /bin/bash 3 does not even appear in the string.
Thanks
Scott
This is a nice one.
When a number is preceeded by a 0, it is represented as octal. What you are actually getting for bin/bash:
0100755 to decimal = 33261
"33261".length = 5
And for /Users:
040755 to decimal = 16877
"16877".length = 5
Add the following line:
puts cFileMode
And you will see the error.
to_s takes an argument which is the base. If you call to_s(8) then it should work.
cFileMode = cFileStats.mode.to_s(8)
EDIT
files = ['/home/', '/bin/bash', 'filetest.rb']
files.each do |file|
puts "File Name: #{file}"
if File.exists?(file)
puts "#{file} is a file"
file_stats = File.stat(file)
puts file_stats.inspect
file_mode = file_stats.mode.to_s(8)
puts "cFileMode Class: #{file_mode.class}"
p file_mode
puts "length of string: #{file_mode.length}"
printf("Mode: #{file_mode}")
puts "User: #{file_mode[-3,1]}"
puts "Group: #{file_mode[-2,1]}"
puts "World: #{file_mode[-1,1]}"
else
puts "Could not find file: #{file}"
end
puts
puts
end
Instead of this:
puts "length of string: " + cFileMode.length.to_s()
What you want is this:
puts "length of string: #{cFile.length}"
Please do not use camel case for variables in Ruby, camel case is used on class names only, method and variable names should be written with underscores to separate multiple words.
It's also a good practice to avoid adding parameters to method calls that do not have parameters, so, instead of calling to_s() you should use to_s only.
Related
I have 2 methods that I want to call multiple times. The number of times that I want to call them is based on the count of a hash I'm using. I'm trying to create a new method that calls the other 2 and repeats for the length of the hash count. My issue is that I'm getting an error
"findfiles2.rb:61:in` `chdir': no implicit conversion of Enumerator into String (TypeError)
from findfiles2.rb:61:in `store_directories'
from findfiles2.rb:138:in `block in repeat'
from findfiles2.rb:134:in `loop'
from findfiles2.rb:134:in `repeat'
from findfiles2.rb:153:in `<main>'"
Here's my code:
require 'date'
require "mail"
options = { :address => "smtp.gmail.com",
:port => 587,
:domain => 'gmail.com',
:user_name => 'username',
:password => 'password/',
:authentication => 'plain',
:enable_starttls_auto => true }
mail_sender = "somename#gmail.com"
mail_recipient = "somename#yahoo.com"
directories = {
"directory1" => "/path/to/folder1/",
"directory2" => "/path/to/folder2/",
"directory3" => "/path/to/folder3/",
"directory4" => "/path/to/folder4/",
"directory5" => "/path/to/folder5/"
}
directory_count = directories.count.to_i
file_output = "/path/to/output/"
exclude_folder = 'sample'
output_file_name = "directory_list"
output_file_extension = ".csv"
date_today = Date.today.to_s
log_file_path = "/path/to/output/"
log_name = "script_log_" + date_today + ".txt"
log_file_name = log_file_path + log_name
# starts log file
def start_log(file_output, log_name)
Dir.chdir(file_output)
log_output = File.open(log_name, 'a+')
$stdout = log_output
puts Time.now.to_s + " > " + "Starting Script..."
puts "_______________________________________________"
end
# stores subdirectory contents into an array
def store_directories(directory, folder_to_exclude)
# changes working directory to the directory variable
puts Time.now.to_s + " > " + "Updating search directory..."
Dir.chdir(directory)
# outputs only subdirectories with a creation date of older than 24 hours, except for folders names 'test'
Dir.glob("*.*").map(&File.method(:realpath))
puts Time.now.to_s + " > " + "Gathering subdirectories..."
subdir_list=Dir.glob("*").map(&File.method(:realpath)).reject{|files| (not File.directory?(files) && (File.mtime(files) < (Time.now - (60*1440))) && (not files == directory + folder_to_exclude)) }
return subdir_list
end
# checks to see if there are any directories in the array
def directory_check(directory_list, save_to_file, today_date, output_file, output_extension)
if directory_list.empty? == false
# changes the working directory to the file output directory for the file
Dir.chdir(save_to_file)
# writes the array contents into a new file
file_name = output_file + "_" + today_date + output_extension
puts Time.now.to_s + " > " + "Saving contents to: " + file_name
File.open(file_name, "a+") do |f|
directory_list.each { |element| f.puts(element) }
end
else
puts Time.now.to_s + " > " + "This directory does not contain any subdirectories that are older than 24 hours"
exit
end
end
# sends an email containing today's report if a file was created today
def send_email(today_date, output_file_path, output_file_name, output_file_extension, mail_options, email_sender, email_recipient)
backlog_file = output_file_path + output_file_name + "_" + today_date + output_file_extension
if File.exist?(backlog_file) == true
puts Time.now.to_s + " > " + "Sending email report to: " + email_recipient + "..."
Mail.defaults do
delivery_method :smtp, mail_options
end
Mail.deliver do
to email_recipient
from email_sender
subject 'Backlog for ' + today_date
body 'Attached is a report showing any batches that have not been processed within the last 24 hours.'
add_file backlog_file
end
else
puts Time.now.to_s + " > " + "No batches older than 24 hours to report"
exit
end
end
This is the method that is giving me trouble
def repeat(directory, times, exclude_folder)
# fail "times must be 1 or more" if times < 1
counter = 1
# counter_string = counter.to_s
# puts counter_string
# directory_counter = directory + counter_string
loop do
if counter != times
subdir_list_contents = store_directories(directory, exclude_folder)
directory_check(subdir_list_contents, file_output, date_today, output_file_name, output_file_extension)
counter = counter + 1
else
break
end
end
end
This is where I'm starting to run everything.
# Starting log file...
start_log(file_output, log_name)
repeat(directories.each, directory_count, exclude_folder)
# # outputs contents of directory 1 to the file (I want to perform this for the amount of times equal to the hash length, which is what I'm creating the repeat method for)
subdir_list_contents = store_directories(directory1, exclude_folder)
directory_check(subdir_list_contents, file_output, date_today, output_file_name, output_file_extension)
# # # If there is a new file from today, sends an email with file as attachment
send_email(date_today, file_output, output_file_name, output_file_extension, options, mail_sender, mail_recipient)
Your code is much too long. As you can see, nobody helps you.
$ ruby -w t.rb
t.rb:125: warning: mismatched indentations at 'end' with 'def' at 104
t.rb:37: warning: assigned but unused variable - log_file_name
/Users/b/.rvm/rubies/ruby-2.4.0-rc1/lib/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:
in `require': cannot load such file -- mail (LoadError)
Post code that we can run. I'm not going to install a whole mail server. So I comment out
#require "mail"
then
t.rb:44:in `chdir': No such file or directory # dir_chdir - /path/to/output/ (Errno::ENOENT)
etc, etc.
Follow the error message :
t.rb:62:in `chdir': no implicit conversion of Enumerator into String (TypeError)
from t.rb:62:in `store_directories'
from t.rb:139:in `block in repeat'
from t.rb:136:in `loop'
from t.rb:136:in `repeat'
from t.rb:149:in `<main>'
All what you need to trace is repeat and store_directories, so you could have reduced the posted code to this strict minimum to reproduce the error :
directories = {
"directory1" => "/path/to/folder1/",
"directory2" => "/path/to/folder2/",
}
directory_count = directories.count.to_i
exclude_folder = 'sample'
# stores subdirectory contents into an array
def store_directories(directory, folder_to_exclude)
puts "directory=#{directory.inspect} folder_to_exclude=#{folder_to_exclude}"
Dir.chdir(directory)
end
def repeat(directory, times, exclude_folder)
store_directories(directory, exclude_folder)
end
repeat(directories.each, directory_count, exclude_folder)
Execution :
$ ruby -w t.rb
directory=#<Enumerator: {"directory1"=>"/path/to/folder1/", "directory2"=>"/path/to/folder2/"}:each> folder_to_exclude=sample
t.rb:12:in `chdir': no implicit conversion of Enumerator into String (TypeError)
from t.rb:12:in `store_directories'
from t.rb:16:in `repeat'
from t.rb:19:in `<main>'
Had you done this, you don't even had to post a question, because the cause of the error is obvious. In
repeat(directories.each, directory_count, exclude_folder)
directories.each returns an Enumerator. Remove each :
$ ruby -w t.rb
directory={"directory1"=>"/path/to/folder1/", "directory2"=>"/path/to/folder2/"} folder_to_exclude=sample
t.rb:12:in `chdir': no implicit conversion of Hash into String (TypeError)
from t.rb:12:in `store_directories'
from t.rb:16:in `repeat'
from t.rb:20:in `<main>'
I suppose that what you wanted to do is call repeat once for each directory :
def repeat(directory, exclude_folder)
puts "in repeat directory=#{directory} exclude_folder=#{exclude_folder}"
store_directories(directory, exclude_folder)
end
directories.each { | _key, directory | repeat(directory, exclude_folder) }
Execution :
$ ruby -w t.rb
in repeat directory=dir1 exclude_folder=sample
in store_directories directory="dir1" folder_to_exclude=sample
in repeat directory=dir2 exclude_folder=sample
in store_directories directory="dir2" folder_to_exclude=sample
t.rb:18:in `chdir': No such file or directory # dir_chdir - dir2 (Errno::ENOENT)
from t.rb:18:in `store_directories'
from t.rb:53:in `repeat'
chdir has a side effect : it changes the current directory, and the next time, it will start searching in the new current directory. To avoid this, you need to restore the previous state :
def store_directories(directory, folder_to_exclude)
puts "in store_directories directory=#{directory.inspect} folder_to_exclude=#{folder_to_exclude}"
current_directory = Dir.getwd
Dir.chdir(directory)
# ...
# Restore the directory that was current when entering the method.
# Without it, the next chdir will start from the directory left by the previous chdir.
Dir.chdir(current_directory)
end
Now it works :
$ ruby -w t.rb
in repeat directory=dir1 exclude_folder=sample
in store_directories directory="dir1" folder_to_exclude=sample
in repeat directory=dir2 exclude_folder=sample
in store_directories directory="dir2" folder_to_exclude=sample
After a few more changes, I end up with this :
require 'date'
directories = {
"directory1" => 'dir1',
"directory2" => 'dir2'
}
exclude_folder = 'sample'
#file_output = '.'
#date_today = Date.today.to_s
#output_file_name = 'directory_list'
#output_file_extension = '.csv'
# stores subdirectory contents into an array
def store_directories(directory, folder_to_exclude)
puts "in store_directories directory=#{directory.inspect} folder_to_exclude=#{folder_to_exclude}"
current_directory = Dir.getwd
puts Time.now.to_s + " > " + "Updating search directory..."
# changes working directory to the directory variable
Dir.chdir(directory)
# outputs only subdirectories with a creation date of older than 24 hours, except for folders names 'test'
puts Time.now.to_s + " > " + "Gathering subdirectories..."
subdir_list = Dir.glob("*").map { | file | File.realpath(file) }
puts "all files : subdir_list=#{subdir_list}"
puts "directory + folder_to_exclude=#{directory + folder_to_exclude}" # nonsense
subdir_list = subdir_list.reject do | file |
not File.directory?(file) \
&& File.mtime(file) < Time.now - 86400 \
&& (not file == folder_to_exclude)
end
puts "after reject : subdir_list=#{subdir_list}"
# Restore the directory that was current when entering the method.
# Without it, the next chdir will start from the directory left by the previous chdir.
Dir.chdir(current_directory)
puts "subdir_list=#{subdir_list.inspect}"
subdir_list
end
# checks to see if there are any directories in the array
def directory_check(directory_list, save_to_file, today_date, output_file, output_extension)
if directory_list.empty? == false
# changes the working directory to the file output directory for the file
Dir.chdir(save_to_file) # <----------------- problem !!!!
# writes the array contents into a new file
file_name = output_file + "_" + today_date + output_extension
puts Time.now.to_s + " > " + "Saving contents to: " + file_name
File.open(file_name, "a+") do |f|
directory_list.each { |element| f.puts(element) }
end
else
puts Time.now.to_s + " > " + "This directory does not contain any subdirectories that are older than 24 hours"
end
end
def repeat(directory, exclude_folder)
puts "in repeat directory=#{directory} exclude_folder=#{exclude_folder}"
subdir_list_contents = store_directories(directory, exclude_folder)
directory_check(subdir_list_contents, #file_output, #date_today, #output_file_name, #output_file_extension)
end
directories.each { | _key, directory | repeat(directory, exclude_folder) }
Execution :
$ ruby -w t.rb
in repeat directory=dir1 exclude_folder=sample
in store_directories directory="dir1" folder_to_exclude=sample
2017-10-27 08:05:24 +0200 > Updating search directory...
2017-10-27 08:05:24 +0200 > Gathering subdirectories...
all files : subdir_list=["/userdata/devl/ruby/zintlist/directories/dir1/x1.txt", "/userdata/devl/ruby/zintlist/directories/dir1/x2.txt"]
directory + folder_to_exclude=dir1sample
after reject : subdir_list=[]
subdir_list=[]
2017-10-27 08:05:24 +0200 > This directory does not contain any subdirectories that are older than 24 hours
in repeat directory=dir2 exclude_folder=sample
in store_directories directory="dir2" folder_to_exclude=sample
2017-10-27 08:05:24 +0200 > Updating search directory...
2017-10-27 08:05:24 +0200 > Gathering subdirectories...
all files : subdir_list=["/userdata/devl/ruby/zintlist/directories/dir2/x3.txt"]
directory + folder_to_exclude=dir2sample
after reject : subdir_list=[]
subdir_list=[]
2017-10-27 08:05:24 +0200 > This directory does not contain any subdirectories that are older than 24 hours
I need to replace placeholders NOUN, VERB, ADJ, and ADV in a file solution09.txt with user input.
Madlib solution09.txt:
One day I was watching my son [ADV] play with his [NOUN]. He was pretending the [NOUN] were [ADJ]. After a few minutes he was pretending to [VERB], because one of the [NOUN] drove away. When i asked him about it he [ADV] said, umm it's funny when [NOUN] [VERB] because [NOUN] can't really [VERB].
I think I successfully put the file into a string, but I have to read the string, and replace the placeholders with user input. Once I replace, I need to output the new madlib. I'm getting the user input into variables, but I'm not sure how to correctly replace the placeholder with the users input.
Current code:
file = File.open("solution09.txt", "r")
contents = file.read
puts "Enter a noun: "
noun = gets.chomp
puts "Enter a verb: "
verb = gets.chomp
puts "Enter an adjective: "
adj = gets.chomp
puts "Enter an adverb: "
adv = gets.chomp
if file.include?('NOUN')
file1= file.gsub("[NOUN]", noun, "[VERB]", verb, "ADJ", adj, "ADV", adv)
end
You can also build a replacement hash:
filename = "solution09.txt"
contents = File.read(filename)
replacements = {}
puts "Enter a noun: "
replacements['[NOUN]'] = gets.chomp
puts "Enter a verb: "
replacements['[VERB]'] = gets.chomp
puts "Enter an adjective: "
replacements['[ADJ]'] = gets.chomp
puts "Enter an adverb: "
replacements['[ADV]'] = gets.chomp
And pass it to gsub:
contents.gsub(Regexp.union(replacements.keys), replacements)
Regexp.union creates a pattern that matches any of the given keys.
Your code should look like
filename = "solution09.txt"
contents=File.read(filename)
puts "Enter a noun: "
noun=gets.chomp
puts "Enter a verb: "
verb=gets.chomp
puts "Enter an adjective: "
adj=gets.chomp
puts "Enter an adverb: "
adv=gets.chomp
if contents.include?('NOUN')
{ "\[NOUN\]" => noun,
"\[VERB\]" => verb,
"\[ADJ\]" => adj,
"\[ADV\]" => adv
}.each do |key, value|
contents.gsub!(key, value)
end
File.open(filename, "w") { |f| f << contents }
end
You need separate operation for read and write. There are other ways to do this
You can see how to do with single file pointer https://stackoverflow.com/a/10173112/1380263
You can also use ruby methods which interact with shell and use sed command (system, backticks, peopen)
Really depends on what suits your situation the best
file = File.read("solution09.txt")
.gsub(/\[(NOUN|VERB|ADJ|ADV)\]/) do
part = case $1
when "NOUN" then "a noun"
when "VERB" then "a verb"
when "ADJ" then "an adjective"
when "ADV" then "an adverb"
end
puts "Enter #{part}: "
gets.chomp
end
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}}"
Sorry, this may be a bit of a noob question. This (economic.rb) is a script that parses some world economic data. I'm unsure how to pass the xml file to it. Normally, to run this I would do
ruby economic.rb
However, File.open is taking the ARGV[0] as a parameter. How do I pass the xml file (data.xml) into that when running the script.
economic.rb
require 'rubygems'
require 'nokogiri'
File.open(ARGV[0]) do |f|
xml_doc = Nokogiri::XML::Document.parse(f)
countries = xml_doc.css('country')
most_populous = countries.max_by {|node| node['population'].to_i}
puts "The most populous country in 1996 was #{most_populous['name']} with a population of #{most_populous['population']}"
puts
puts "The five countries with the highest inflation rate in 1996 were:"
countries.sort_by {|country| -(country['inflation'] || 0).to_f} [0..4].each do |country|
puts " #{country['name']} - #{country['inflation']}%"
end
continent_info = countries.group_by {|country| country['continent']}
puts
puts "The continents and their countries in 1996 were:"
continent_info.keys.sort.each do |continent|
continent_info[continent].sort_by {|country|
country['name']}.each do |country|
puts " #{country['name']}"
end
end
You can just run:
ruby economic.rb data.xml
I am trying to write a CSV "fixer".
Unfortunately It seems that the csv.foreach instruction is not calling the lambda I have created. The CPU is used at 100%. Just wondering what ruby is doing in the meantime...
Any ideas why my code is wrong?
1 require "csv"
2
3 ARGV.empty? do
4 print "usage: fixcsv.rb <filename>"
5 exit
6 end
7
8 filename_orig = Dir.pwd + "/" + ARGV[0]
9 filename_dest = filename_orig.sub(/csv$/,"tmp.csv")
10 topic = filename_orig.sub(/_entries.csv$/,"").sub(/.*\//,"")
11
12 puts "topic:" + topic
13
14 writer = CSV.open(filename_dest,"w",:col_sep=>";")
15 #i=0
16 cycler = lambda do |row|
17 #i = i + 1
18 #puts "row number:" + i.to_str
19 #row[17] = topic
20 puts "foo"
21 writer << row
22 end
23
24 begin
25 CSV.foreach(filename_orig,:col_sep=>",",&cycler)
26 rescue
27 puts "exception:" + $!.message
28 exit
29 else
30 writer.close
31 end
Here is the stack trace produced when I Ctrl-C it:
stab#ubuntu:~/wok$ ruby addtopic.rb civilpoliticalrights_entries.csv
topic:civilpoliticalrights
^C/usr/lib/ruby/1.8/csv.rb:914:in `buf_size': Interrupt
from /usr/lib/ruby/1.8/csv.rb:825:in `[]'
from /usr/lib/ruby/1.8/csv.rb:354:in `parse_body'
from /usr/lib/ruby/1.8/csv.rb:227:in `parse_row'
from /usr/lib/ruby/1.8/csv.rb:637:in `get_row'
from /usr/lib/ruby/1.8/csv.rb:556:in `each'
from /usr/lib/ruby/1.8/csv.rb:531:in `parse'
from /usr/lib/ruby/1.8/csv.rb:311:in `open_reader'
from /usr/lib/ruby/1.8/csv.rb:94:in `foreach'
from addtopic.rb:25
EDIT: Ruby version is:
$ ruby --version
ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux]
Your program worked fine for me in Ruby 1.9.
I have a few observations:
If your input pathname does not end in csv, then the input and output file names will be the same. This could easily produce an infinite loop.
You are definitely using the 1.9 flavor of csv. If this program needs to run on 1.8.7 it would need to have patches from the snippet below...
Mods for 1.8.7:
writer = CSV.open(filename_dest, "w", ?;)
#i=0
cycler = lambda do |row|
#i = i + 1
#puts "row number:" + i.to_str
#row[17] = topic
writer << row
end
begin
CSV.open filename_orig, 'r', ?,, &cycler
The main problem with 1.8.7 csv is that the interfaces to CSV.open and CSV.foreach do not take Hash options. Worse, they are expecting numeric code points, a feature of Ruby that apparently didn't work out and was withdrawn in 1.9.