Modifying files in a zip archive - ruby

I want to modify all of the files in a zip archive of XML files. When I tried to do this though, it tells me that the file doesn't exist. If I comment out the replace call though this works. What am I doing wrong?
Zip::ZipFile.open(temp_file.path) do |zipfile|
for i in 0..(zipfile.entries.count - 1)
entry = zipfile.entries[i]
if entry.name
if entry.name.split("/").last == "patient_manifest.txt"
next
end
end
next if entry.directory?
data = zipfile.read(entry.name)
doc = Nokogiri::XML(data)
doc.root.add_namespace_definition('cda', 'urn:hl7-org:v3')
doc.root.add_namespace_definition('sdtc', 'urn:hl7-org:sdtc')
patient_role_element = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole')
patient_element = patient_role_element.at_xpath('./cda:patient')
first = patient_element.at_xpath('cda:name/cda:given').text
last = patient_element.at_xpath('cda:name/cda:family').text
id_node = patient_role_element.at_xpath('./cda:id')
id_node['extension'] = id_node['extension'] + first + last
xml_file = Tempfile.new('foo')
begin
xml_file.write(doc.to_xml)
zipfile.replace(entry, xml_file.path)
ensure
xml_file.close
xml_file.unlink # deletes the temp file
end
end
end

Related

write a file multiple times

I would like to know how to write a picture twice without writing it once and then copying it.
When a picture is downloaded, it is written in the /tmp and then copied to the wanted path ( I think ) meaning that the following code :
cover_buffer = download_pic(link)
buffer2 = cover_buffer
open(#dir + 'cover.jpg', 'wb') do |pic|
pic << cover_buffer.read()
end
open(#dir + 'cover2.jpg', 'wb') do |pic|
pic << cover_buffer2.read()
end
does not work since the both cover_buffer and buffer2 both point to the same file whitch was moved when writing cover.jpg
Executing that code will correctly write the picture in cover.jpg but cover2.jpg will be an empty file
TESTED SOLUTION
In file two_for_one.rb:
current_dir = File.expand_path(File.dirname(__FILE__))
new_file_1 = File.new(File.join(current_dir, 'image_1.png'), 'w')
new_file_2 = File.new(File.join(current_dir, 'image_2.png'), 'w')
origin_file = File.join(current_dir, 'original_image.png')
begin
File.open(origin_file, "r") do |source|
until source.eof?
chunk = source.read(1024)
new_file_1.write(chunk)
new_file_2.write(chunk)
end
end
ensure
new_file_1.close()
new_file_2.close()
end
Command line:
$ ruby two_for_one.rb

Check if some files in array exist in directory

I wrote the following code to rename some files in a directory (from 'rb' to 'origin'):
original_files = ['test1.rb', 'test2.rb']
ruby_block "Rename file" do
block do
for filename in original_files
newname = filename.split(".")[0] + '.origin'
::File.rename("C:\\Test\\#{filename}", "C:\\Test\\#{newname}")
end
end
end
When I run it for the second time, I get an error that these files don't exist, which is expected.
How can I check if these files exist or not like this:
if ::File.exist?("C:\\Test\\*.origin")
Chef::Log.info("########## Your files are already renamed ############")
else
my_code
end
or in another way (maybe to check it in loop)?
This is my solution after numerous attempts:
origin_files = ['test1.rb', 'test2.rb']
dir_path = "C:\\Test"
ruby_block "Rename file" do
block do
for filename in origin_files
newname = filename.split(".")[0] + '.origin'
if ::File.exist?("#{dir_path}\\#{newname}")
Chef::Log.info("### Your file: #{newname} already renamed ###")
else
::File.rename("#{dir_path}\\#{filename}", "#{dir_path}\\#{newname}")
end
end
end
end
you can check this files like this code
files = ["test1.rb", "test2.rb"]
path = "C:/test"
files.each { |file_name|
base_name = File.basename(file_name, ".rb")
new_name = base_name + ".origin"
if File.exists?(File.join(path, new_name))
Chef::Log.info("########## Your file #{base_name} are already renamed ############")
elsif File.exists?(File.join(path, file_name))
File.rename(File.join(path, file_name), File.join(path, new_name))
Chef::Log.info("########## Your file #{base_name} was renamed ############")
else
Chef::Log.info("########## Your file #{file_name} not exist ############")
end
}
You can use Chef guard for this purpose. It automatically logs the event during the chef-client run as
ruby_block xxx (skipped due to not_if)
Here is the example:
origin_files = ['test1.rb', 'test2.rb']
dir_path = "C:\\Test"
origin_files.each do | old_file |
base_name = File.basename(old_file, ".rb")
newfile = base_name + ".origin"
ruby_block "rename #{old_file}" do
block do
File.rename(File.join(dir_path, old_file), File.join(dir_path, newfile))
end
not_if { File.exist?("#{dir_path}\\#{newfile}") }
end
end

Ruby file full path

I am writing a program where I cycle through all files in sub-folders of a target folder and do stuff with what's writen in it. So my local folder looks like that
Folder
--Subfolder
---File
---File
---File
--Subfolder
---File
.
.
.
So I have a each loop to cycle through all subfolders and for each subfolder I am calling a method that basically do the same thing but in the subfolder and call for each file another method (parsing it a file argument which I obtained through a Dir.foreach(folder){ |file| method(file)} command).
So it looks like this :
Dir.foreach(Dir.pwd){ |folder| call_method(folder) }
def call_method(folder) Dir.foreach(folder){|file| reading_method(file) } end
That last called method (reading_method) should open called a C method and parse as an argument the full path of the file (so that the C program can open it) so I'm using File.absolute_path(file) in the reading_method but instead of returning C:/folder/subfolder/file as I want it to, it returns C:/folder/file skipping the subfolder (and thus the C program fail to execute).
Is there a way to get the full path of that file ?
Thanks for your help
EDIT : Here is the full code as asked
## Module
module GBK_Reader
PATH = "Z:/Folder/"
SAFETY = true
SAFETY_COUNT = 10
end
## Methods definitions
def read_file(file)
path = File.absolute_path(file)
c_string = `C:/Code/GBK_Reader/bin/Debug/GBK_Reader.exe #{path}`
return c_string.split(/ /).collect!{|spec| spec.to_i}
end
def read_folder(folder)
Dir.foreach(folder){ |file|
next if File.extname(file) != ".gbk"
temp = read_file(file)
#$bacteria_specs[0] += temp[0]
#$bacteria_specs[1] += temp[1]
}
return $bacteria_specs
end
## Main
# Look for folder
Dir.chdir(GBK_Reader::PATH)
puts "Directory found"
# Cycle through all sub-folders
$high_gc = {} #Hash to store high GC content bacterias
$count = 0
puts "Array variable set"
Dir.foreach(Dir.pwd){ |file|
next if file == "." || file == ".."
break if $count >= GBK_Reader::SAFETY_COUNT
$count += 1 if GBK_Reader::SAFETY
$bacteria_specs = [0.00, 0.00, 0.00]
$path = File.expand_path(file)
if File.directory?(file)
# Cycle through all .gbk files in sub-folder and call C program
read_folder(file)
else
# Call C program to directly evaluate GC content
c_string = read_file(file) if File.extname(file) == ".gbk"
$bacteria_specs[0] = c_string[0].to_i
$bacteria_specs[1] = c_string[1].to_i
end
# Evaluate GC content and store suitable entries
$bacteria_specs[2] = ($bacteria_specs[0]/$bacteria_specs[1])*100.00
$high_gc[file] = $bacteria_specs if $bacteria_specs[2] > 60
}
# Display suitable entries
puts "\n\n\n"
puts $high_gc
gets.chomp
Ok, I may have found something but it seems ugly so if anyone has a better solution by all means go ahead.
I edited my read_folder method to parse the full path to the read_file method as follow :
def read_folder(folder)
Dir.foreach(folder){ |file|
next if File.extname(file) != ".gbk"
path = File.absolute_path(folder)+'/'+File.basename(file)
temp = read_file(path)
$bacteria_specs[0] += temp[0]
$bacteria_specs[1] += temp[1]
}
return $bacteria_specs
end
And I do get the path I expect. (though my calling the C program still fails so I'll have to check somewhere else :D)

Trying to prepend using ruby

I'm trying to prepend text to an existing file.. This code works just great, BUT the last line never seems to execute. I can delete the original file, but the file is never renamed from the new temp file back to the original filename...
I'm sure it's something easy, but, I don't know why it doesn't work. Can anyone help?
# grab input text
s = "{query}"
# create insert value in template with timestamp
tmp = "#{Time.now.strftime('%Y-%m-%d %I:%M %p')}\n#{s}"
# path to file you wish to append...
# folder path must exist, file will be created if it doesn't
o = File.expand_path("~/Dropbox/Notes/1scratchpad.txt")
n = File.expand_path("~/Dropbox/Notes/1scratchpad.new.txt")
# open file in append mode and add the string
File.open(n, 'w') do |n|
n.puts tmp
n.puts "\n"
File.foreach(o) do |li|
n.puts li
end
end
File.delete(o)
File.rename(n, o)
Try this
# grab input text
s = "{query}"
# create insert value in template with timestamp
tmp = "#{Time.now.strftime('%Y-%m-%d %I:%M %p')}\n#{s}"
# path to file you wish to append...
# folder path must exist, file will be created if it doesn't
o = File.expand_path("~/Dropbox/Notes/1scratchpad.txt")
n = File.expand_path("~/Dropbox/Notes/1scratchpad.new.txt")
# open file in append mode and add the string
File.open(n, 'a') do |n|
n << tmp
n << "\n"
n << File.read(o)
end
#File.delete(o)
## Delete is no longer rename would take care of everthing
File.rename(n, o)

When to use a new variable vs string interpolation?

I wrote a script that I decided to refactor so I could add functionality to it as my coworkers think of it. I only saved four lines in the effort, but the main change is I removed both methods and reduced the number of called variables in favor of string interpolation/manipulation. Is there a preference for this? Is it better to declare a new variable just to use once, or is it more DRY to just make minor tweaks to the string when you need to use it? For example here is the original code:
def validate_directory(dir)
puts "Enter the full directory path of the flv files." unless dir
input = dir || gets.chomp
input.gsub!('\\', '/')
input += '/' unless input[-1..-1] == '/'
until File.directory?(input) && Dir.glob("#{input}*.flv") != []
puts "That directory either doesn't exist or contains no .flv files. \nEnter the full directory path of the flv files."
input = $stdin.gets.chomp
input.gsub!('\\', '/')
input += '/' unless input[-1..-1] == '/'
end
dir = input
end
def output(flv, location)
title = flv.dup.gsub!(".flv", ".html")
vid = flv.dup
vid.slice!(0..6)
body = $EMBED.gsub("sample.flv", vid)
htmlOutput = File.open(title, "w")
htmlOutput.write(body)
htmlOutput.close
linkList = File.open("#{location}List of Links.txt", "a")
linkList.write($BASE + vid.gsub(".flv", ".html") + "\n")
linkList.close
puts "Files created successfully."
end
dir = ARGV[0].dup unless ARGV.empty?
folder = validate_directory(dir)
files = folder.clone + "*.flv"
flvs = Dir.glob("#{files}")
File.delete("#{folder}List of Links.txt") if File.exists?("#{folder}List of Links.txt")
flvs.each { |flv| output(flv, folder) }
And the new stuff:
flash_folder = ARGV[0].dup unless ARGV.empty?
if !flash_folder
puts "Enter the full directory path of the flv files."
flash_folder = gets.chomp
end
flash_folder.gsub!('\\', '/')
flash_folder += '/' unless flash_folder[-1..-1] == '/'
until File.directory?(flash_folder) && Dir.glob("#{flash_folder}*.flv") != []
puts "That directory either doesn't exist or contains no .flv files. \nEnter the full directory path of the flv files."
flash_folder = $stdin.gets.chomp
flash_folder.gsub!('\\', '/')
flash_folder += '/' unless flash_folder[-1..-1] == '/'
end
flash_files = Dir.glob("#{flash_folder}*.flv")
File.delete("#{flash_folder}List of Links.txt") if File.exists?("#{flash_folder}List of Links.txt")
flash_files.each do |flv|
html_output = File.open("#{flv.gsub(".flv", ".html")}", "w")
html_output.write("#{embed_code.gsub("sample.flv", flv.slice(7..flv.length))}")
html_output.close
link_list = File.open("#{flash_folder}List of Links.txt", "a")
link_list.write("#{flash_url}#{flv.slice(2..flv.length).gsub(".flv", ".html")}\n")
link_list.close
end
puts "Finished."

Resources