How to get file count with Ruby - ruby

I have the following code :
system('cls')
Dir.chdir("testing")
puts Dir.pwd
Dir.glob('*.csv').each do|csv_filename|
next if csv_filename == '.' or csv_filename == '..'
puts "\t" + csv_filename
end
file_Num= Dir[".testing/*"].length
puts "file count = " + file_Num.to_s
I am trying to display all csv filenames within the testing directory and get a count of such csv files, not directories. The above renders only the correct csv file names as expected but file count always = 0. Yes, I am new trying to teach myself Ruby but I've searched for what I am trying to accomplish and cannot seem to put the pieces together. I need a file count because if that num is > 3 I would like to send an alert to the screen of some type. Wold appreciate any help on this. Thanks!

Look like you put the wrong path in file_Num= Dir[".testing/*"].length
Should be
file_Num = Dir["*.csv"].length
as you already change dir to testing.
In case you would like to count all csv files in subdirectories
file_Num = Dir["**/*.csv"].length

Related

Ruby file renamer

this is a text file renamer i made, you throw the file in a certain folder and the program renames them to file1.txt, file2.txt, etc
it gets the job done but it's got two problems
it gives me this error no implicit conversion of nil into String error
if i add new files into the folder where there's already organized files, they're all deleted and a new file is created
what's causing these problems?
i=0
Dir.chdir 'C:\Users\anon\Desktop\newfolder'
arr = Dir.entries('C:\Users\anon\Desktop\newfolder')
for i in 2..arr.count
if (File.basename(arr[i]) == 'file'+((i-1).to_s)+'.txt')
puts (arr[i]+' is already renamed to '+'file'+i.to_s)
else
File.rename(arr[i],'file'+((i-1).to_s)+'.txt')
end
end
There are two main problems in your program.
The first is that you are using an out of bounds value in the array arr. Try this a = [1,2,3]; a[a.count] and you will get nil because you are trying at access a[3] but the last element in the array has index 2.
Then, you are using as indexes for names fileINDEX.txt always 2...foobar without taking into account that some indexes may be already used in your directory.
Extra problem, you are using Dir.entries, this in my OS gives regular entries more . and .. which should be managed properly, they are not what you want to manipulate.
So, I wrote you a little script, I hope you find it readable, to me it works. You can improve it for sure! (p.s. I am under Linux OS).
# Global var only to stress its importance
$dir = "/home/p/tmp/t1"
Dir.chdir($dir)
# get list of files
fnames = Dir.glob "*"
# get the max index "fileINDEX.txt" already used in the directory
takenIndexes = []
fnames.each do |f|
if f.match /^file(\d+).txt/ then takenIndexes.push $1.to_i; end
end
# get the first free index available
firstFreeIndex = 1
firstFreeIndex = (takenIndexes.max + 1) if takenIndexes.length > 0
# get a range of fresh indexes for possible use
idxs = firstFreeIndex..(firstFreeIndex + (fnames.length))
# i transform the range to list and reverse the order because i want
# to use "pop" to get and remove them.
idxs = idxs.to_a
idxs.reverse!
# rename the files needing to be renamed
puts "--- Renamed files ----"
fnames.each do |f|
# if file has already the wanted format then move to next iteration
next if f.match /^file\d+.txt/
newName = "file" + idxs.pop.to_s + ".txt"
puts "rename: #{f} ---> #{newName}"
File.rename(f, newName)
end

Ruby: How do you search for a substring, and increment a value within it?

I am trying to change a file by finding this string:
<aspect name=\"lineNumber\"><![CDATA[{CLONEINCR}]]>
and replacing {CLONEINCR} with an incrementing number. Here's what I have so far:
file = File.open('input3400.txt' , 'rb')
contents = file.read.lines.to_a
contents.each_index do |i|contents.join["<aspect name=\"lineNumber\"><![CDATA[{CLONEINCR}]]></aspect>"] = "<aspect name=\"lineNumber\"><![CDATA[#{i}]]></aspect>" end
file.close
But this seems to go on forever - do I have an infinite loop somewhere?
Note: my text file is 533,952 lines long.
You are repeatedly concatenating all the elements of contents, making a substitution, and throwing away the result. This is happening once for each line, so no wonder it is taking a long time.
The easiest solution would be to read the entire file into a single string and use gsub on that to modify the contents. In your example you are inserting the (zero-based) file line numbers into the CDATA. I suspect this is a mistake.
This code replaces all occurrences of <![CDATA[{CLONEINCR}]]> with <![CDATA[1]]>, <![CDATA[2]]> etc. with the number incrementing for each matching CDATA found. The modified file is sent to STDOUT. Hopefully that is what you need.
File.open('input3400.txt' , 'r') do |f|
i = 0
contents = f.read.gsub('<![CDATA[{CLONEINCR}]]>') { |m|
m.sub('{CLONEINCR}', (i += 1).to_s)
}
puts contents
end
If what you want is to replace CLONEINCR with the line number, which is what your above code looks like it's trying to do, then this will work. Otherwise see Borodin's answer.
output = File.readlines('input3400.txt').map.with_index do |line, i|
line.gsub "<aspect name=\"lineNumber\"><![CDATA[{CLONEINCR}]]></aspect>",
"<aspect name=\"lineNumber\"><![CDATA[#{i}]]></aspect>"
end
File.write('input3400.txt', output.join(''))
Also, you should be aware that when you read the lines into contents, you are creating a String distinct from the file. You can't operate on the file directly. Instead you have to create a new String that contains what you want and then overwrite the original file.

Using Ruby to automate a large directory system

So I have the following little script to make a file setup for organizing reports that we get.
#This script is to create a file structure for our survey data
require 'fileutils'
f = File.open('CustomerList.txt') or die "Unable to open file..."
a = f.readlines
x = 0
while a[x] != nil
Customer = a[x]
FileUtils.mkdir_p(Customer + "/foo/bar/orders")
FileUtils.mkdir_p(Customer + "/foo/bar/employees")
FileUtils.mkdir_p(Customer + "/foo/bar/comments")
x += 1
end
Everything seems to work before the while, but I keep getting:
'mkdir': Invalid argument - Cust001_JohnJacobSmith(JJS) (Errno::EINVAL)
Which would be the first line from the CustomerList.txt. Do I need to do something to the array entry to be considered a string? Am I mismatching variable types or something?
Thanks in advance.
The following worked for me:
IO.foreach('CustomerList.txt') do |customer|
customer.chomp!
["orders", "employees", "comments"].each do |dir|
FileUtils.mkdir_p("#{customer}/foo/bar/#{dir}")
end
end
with data like so:
$ cat CustomerList.txt
Cust001_JohnJacobSmith(JJS)
Cust003_JohnJacobSmith(JJS)
Cust002_JohnJacobSmith(JJS)
A few things to make it more like the ruby way:
Use blocks when opening a file or iterating through arrays, that way you don't need to worry about closing the file or accessing the array directly.
As noted by #inger, local vars start with lower case, customer.
When you want the value of a variable in a string usign #{} is more rubinic than concatenating with +.
Also note that we took off the trailing newline using chomp! (which changes the var in place, noted by the trailing ! on the method name)

Variable changing

I wrote some code to get input from a user and then alter it to my needs. I need it in the altered and unaltered form so I am saving the input into two variables. What I don't understand is why it both variables are changing. I tried some extra puts lines to determine what the cause is but I am unable to figure it out. The code:
puts "Enter the full directory path of the flv files."
folder = gets.chomp
puts "Folder 1: " + folder
path = folder
path.slice!(0..6)
path.gsub!('\\', '/')
path += '/'
puts "Folder: " + folder
puts "Path: " + path
With input: f:\folder\subfolder\another
Output:
Folder 1: f:\folder\subfolder\another
Folder: folder/subfolder/another
Path: folder/subfolder/another/
What I'm going for is getting a directory and keeping the directory for other processes, but also transforming it into a URL friendly format. Ideas?
path = folder # does not actually copy the object, copies the reference
path.object_id == folder.object_id # the objects are the same, see
path.slice!(0..6) # all bang methods work with the same object
Thus your path is a reference to the same object as folder.
To fix this, use
path = folder.clone
When you do b = a, it's making b point at the same value as a, so when you change a's value using something like slice!, b will also point to the changed value.
To avoid this, duplicate the object instead:
b = a.dup

Sort File List in Xcode?

Is there a way in Xcode to sort my list of files under say the Classes folder Alphabetically?
I know I can drag them around, but with tons of files that is a pain.
I am surprised I can not right click on the folder and say to sort.
Click on the folder, and then click Edit > Sort > By Name
Here is a Ruby script that will sort all the files within their respective groups in an Xcode 4 project file (probably Xcode 3 as well but I haven't tried that).
Usage:
ruby sort.rb <infile> <outfile>
where <infile> is an unsorted .pbxproj file and <output> will be the sorted version. Don't make them the same file.
#!/usr/bin/env ruby
state = :primary
group = []
file_count = group_count = 0
File.open ARGV[0] do |infile|
File.open ARGV[1], 'w' do |outfile|
infile.each_line do |line|
case state
when :primary
# copy lines until and including "children = ("
outfile.write line
state = :group if line =~ /^\s*children\s*=\s*\x28\s*$/
when :group
if line =~ /^\s*[0-9A-F]+\s*\/\* (.*) \*\/,\s*$/
# add file to current group if "<guid> /* <filename> */,"
group << [$1,line]
file_count += 1
else
# otherwise, output sorted files,
# empty the group, and go back to primary state
group.sort.each do |fn,ln|
outfile.write ln
end
state = :primary
group = []
outfile.write line
group_count += 1
end
end
end
end
end
puts "Sorted #{file_count} files in #{group_count} groups"
The ruby script from jedediah works great. To also sort resources being copied, you can add:
state = :group if line =~ /^\s*files\s*=\s*\x28\s*$/
Note that sort is case sensitive (capital letters first). To make it insensitive, use:
group << [$1.downcase,line]
There isn't really an easy solution in XCode5.
I opened the pbxproj file in a text editor.
Navigate down to /* Begin PBXResourcesBuildPhase section */
select everything in files.
copy to a new text document.
Replace /* with \t (tab character)
select all, copy and paste into blank excel document. you should have 2 columns of data
insert a column at poisition 2
make all rows for that column /*
sort the sheet on column 3
copy all data and paste back over your section in pbxproj file
save file
That should sort the "Copy Bundle Resources" section of your project.
I feel dirty just doing this, but hey - it works
Czar there are advantages to having it the way you want, instead of automatically having it sort at all times.
Some classes might be related in some way, but the names aren't right next to each other, I've used that for certain. :)

Resources