Zip command in ruby block does not work without binding.pry - ruby

I have a block of code that executes a zip command from another class:
def zip_up_contents path name
Zipper.new path name
end
The problem is that it zips blank copies of all the files passed to it. But when I put a binding before the zip command like so:
def zip_up_contents path name
binding.pry
Zipper.new path name
binding.pry
end
it zips the files successfully. I know this by checking the resulting file's byte size from within pry on the second binding point with and without the first binding present. Without the binding, the zip archive's byte size is half what it should be, and with the binding it's the size I would expect.
The "Zipper" class simply calls the system zip with backticks. I don't think that's the problem because I've used that class without trouble in other contexts. The zip utility is Zip 3.0 on Ubuntu 10.04.
I have no idea why the presence of the binding makes a difference. If anyone has encountered anything similar, or has thoughts about how to better debug the issue, I'd appreciate hearing about it.
EDIT: For anyone encountering anything similar, I resolved this by calling fsync on the files prior to zipping them: http://www.ruby-doc.org/core-2.0.0/IO.html#method-i-fsync

I had this problem with some Rspec tests last week -- turned out to be a race condition. Is there any chance that the file hasn't been saved when you pass it to be zipped? I mean, maybe the binding.pry is just giving it a chance to catch up.

Related

Using Dir.glob not returning any files in specified directory

I am working on a game and am trying to output the names of save files from their directory using Dir.glob (if there's a better way to do this, I'm absolutely not attached to that particular function)
I tried using information from various answers on here, but it still isn't outputting any file names to the console.
The file name generator
file = File.new("Saves\\" + "#{char.name}" + ".sav", 'w')
that's working fine, just wanted to have it in case it has something to do with the file extension.
and the current iteration of the output writer.
Dir.glob("/Saves/*") do |file|
puts file.basename()
end
I'm not sure if it should be working per say, but I've tried several different versions that, in theory should be outputting a list.
It outputs a blank line (which also end the program at the moment) even though there are 3 files currently in the directory.
per a comment (but not answer) from cremno, changing the "/Saves/" to simply "Saves/" fixed it.

Copying files from one directory to another is not working in Ruby

I am using fastlane and snapshot to create screenshots automatically. To facilitate this I need to copy data into the app. In this case a series of folders and documents from one folder into another within a .app container.
So far the Documents folder is being created but no files are ever copied into it. At this point I’m not sure if I’m suppling the path incorrectly or what else I might be doing wrong to lead to this. It may be simply that I’ve got the wrong code to do that since I’m not that familiar with Ruby.
Any suggestions would be greatly appreciated, so tell me, what am I missing?
example_files = "./sample_data/Documents"
folder_name = "Documents"
setup_for_device_change do |lang, device|
app_path = "/tmp/snapshot/build/SyncSpace.app/"
FileUtils.mkdir_p(File.join(app_path, folder_name))
Dir.glob(File.join(example_files, '*')).each do |example_path|
FileUtils.cp_r(example_path, File.join(app_path, folder_name)) rescue nil # in case the file already exists
end
end
Update -
In the end my problem is that the path I’m using doesn’t work correctly for the files I want to transfer. When I give it a full path from the root level to the folder I need it works. Trying to use a shorter path with just the additional folders over the working directory fails.
So as a follow up, when my working directory is .../fastlane and my data is in .../fastlane/sample_data/Documents then why doesn’t just using ./sample_data/Documents work?
Don't use rescue nil. Ever, or at least until you're very aware of what your code could be doing and why you would want to use that. Instead use the normal form of:
begin
do_something
rescue TheExactExceptionYouWantToHandle => e
# handle the exception
end
That way you handle what you expect and blow up if it's something you didn't expect.
One of my programming mentors years ago told me
Never test for an error condition you don't know how to handle.
On the surface that sounds silly but experience teaches us we can get into situations where the program does the wrong thing trying to do the right thing. It's better to crash fast and safely and spew out an error, than to drag it out and damage things trying to recover or silently cover the error. Debugging a program that's rescuing improperly can be a major pain and a trailing rescue is a common culprit.

How to test file creation with RSpec?

I have a simple FileCreator Ruby class that has 1 method create which creates a blank txt file on my desktop. Using RSpec, how would I test this create method to make sure
that the file was created, without having to create the file? Would I use RSpec::Mocks? Can someone please point me in the right directory? Thanks!
After calling file_creator.create(100) you could search the folder for all File*.txt files and make sure the count matches. (Make sure to have your spec remove the test files after completion).
Dir.glob(File.join(File.expand_path("~/Desktop"), "File*.txt")).length.should == 100
Using Mocks: You could do something like this to verify that the File.open method is actually being called (to test that the files actually get created, though, you may want to consider actually creating the files like the first half of my answer).
File.should_receive(:open).exactly(100).times
You could also try using something like FakeFS which mocks the actual file system.
The simplest way to do it is as below:
FileCreator.count.should eq 100

I can't figure out the require in ruby

I'm new to Ruby
MakModule.rb
module Display
class Multiply
def Multiply.mul(first, second)
return first * second
end
end
end
MakRequire1.rb
require "Display"
puts Multiply.mul 5,6
MakRequire2.rb
require "MakModule.rb"
puts Multiply.mul 5,6
both file give me the error below
ruby: No such file or directory -- makRequire (LoadError)
How should I correct my code?
It is simply impossible that the code you posted here generates that error message. The error message says that you tried to require a file named makRequire, but that filename doesn't appear anywhere in the code you posted.
Without the actual code that is generating the actual error, it is impossible to answer your question. However, here are a few general tips:
Whenever the computer tells you that it cannot find something, in 99% of the cases, the problem is that the thing the computer tells it couldn't find isn't actually there.
So, in this case, the computer tells you that it cannot find a file named makRequire.rb, and the most likely explanation for that is that makRequire.rb doesn't actually exist. So, the first thing you need to check is: does makRequire.rb (note the capitalization and the file extension) actually exist? Because if it doesn't exist, then the reason why the computer cannot find it, should be rather obvious.
In 99% of the rest of the cases, the problem is that the thing the computer is looking for does exist, but the computer is looking in the wrong place. So, after you have verified that makRequire.rb actually does exist, you need to make sure that the directory the file is in, is in Ruby's $LOAD_PATH, and if it isn't, you need to add that directory to Ruby's $LOAD_PATH. Alternatively, if you want to require the file relative to the path of the file that is doing the requiring, you need to use require_relative instead of require.
The third thing to check for, is whether the user who own the ruby process has sufficient privileges to access the file makRequire.rb, the directory it is in and all of its parent directories.
Try this,
require File.join(File.dirname(__FILE__),'MarkModule')
Try require './MakModule', because the . is the current directory.
require 'MakModule'
You can require a file that is in the same directory. To use a module you would typically include the module inside a class definition. So you would never require Display, you would require the file that contains Display (without the .rb extension, usually).

Ruby - How to prevent wiping your hard drive when using delete file and directory commands in your code

I'm writing some code that at run time may create or delete directories within the project path. I haven't really used ruby for file processing so i'm really uneasy about having code that, with a few mistypes weeks down the line, could result in wiping other directories outside of my project path.
Is there anyway to make it impossible for the program to delete files outside of its own path regardless of whats typed in destructive calls?
Pathname is a wrapper class for almost any file operations.
require "pathname"
path= Pathname.new("/home/johannes")
path.directory? # => true
path.children # => [#<Pathname:.bash_history>, #<Pathname:Documents>, #<Pathname:Desktop>]
path.children.each do |p|
p.delete if p.file?
end
Pathname#children does not contain . or .. so you don't accidently walk up the tree instead of down. If you still don't trust in the code, you can even check if on path is contained in another
Pathname.new("test") <=> Pathname.new("test/123") # => -1
You might want to create a wrapper method around your favourite delete method (or, perhaps, around whole class, because not only deleting files is potentially destructive file operation), which would expand all the submitted paths and check whether they begin with your "sandbox" path). You can also try to redefine delete method, if you are willing to cripple it through whole application.
And maybe the cleanest solution of them all would be to create a new user on your system and run your program as him.
On a POSIX system, you can use Dir.chroot to change the root that your application sees. Then ALL actions, not just delete ones, will be limited to the project directory. This does mean that external commands will be unavailable unless you make them part of your project directory as well.
This is the standard 'sandboxing' method used in Unix based systems. It can be difficult to setup (eliminating all external dependancies is sometimes hard), but affords significant protection when configured properly.
You could generate an Array of filenames in your project directory using
my_files = Dir["/bla/bla/your/directory/**/*"]
and then simply check if the filename passed to your "delete" function exist in your my_files array.
I'm sure there is a more elegant solution, but this could work ^_^
You could use File.expand_path and File.dirname on the input, and check that against __FILE__. So something like this might work:
File.delete(path) if File.dirname(File.expand_path(path)).include? File.dirname(File.expand_path(__FILE__))
I've got automated tests that routinely create and wipe out directories. I've taken two approaches:
Use /tmp as much as possible. The 'tmpdir' standard library module will create temporary directories which will be destroyed when your program exits. Or,
When the code creates a directory that it will later be deleting, it drops a marker file into the directory. When it comes time to delete the directory, if the marker file is not found, the code refuses to delete the directory. A marker file might be called ".ok_to_delete", for example.

Resources