Create Directory if it doesn't exist with Ruby - ruby

I am trying to create a directory with the following code:
Dir.mkdir("/Users/Luigi/Desktop/Survey_Final/Archived/Survey/test")
unless File.exists?("/Users/Luigi/Desktop/Survey_Final/Archived/Survey/test")
However, I'm receiving this error:
No such file or directory - /Users/Luigi/Desktop/Survey_Final/Archived/Survey/test (Errno::ENOENT)
Why is this directory not being created by the Dir.mkdir statement above?

You are probably trying to create nested directories. Assuming foo does not exist, you will receive no such file or directory error for:
Dir.mkdir 'foo/bar'
# => Errno::ENOENT: No such file or directory - 'foo/bar'
To create nested directories at once, FileUtils is needed:
require 'fileutils'
FileUtils.mkdir_p 'foo/bar'
# => ["foo/bar"]
Edit2: you do not have to use FileUtils, you may do system call (update from #mu is too short comment):
> system 'mkdir', '-p', 'foo/bar' # worse version: system 'mkdir -p "foo/bar"'
=> true
But that seems (at least to me) as worse approach as you are using external 'tool' which may be unavailable on some systems (although I can hardly imagine system without mkdir, but who knows).

Simple way:
directory_name = "name"
Dir.mkdir(directory_name) unless File.exists?(directory_name)

Another simple way:
Dir.mkdir('tmp/excel') unless Dir.exist?('tmp/excel')

How about just Dir.mkdir('dir') rescue nil ?

Related

Why does Ruby on Linux return true to File.writable?('/tmp/file') but raises Errno::EACCES while trying to write the file?

I am using a GNU/Linux system.
Firstly, I have:
Moved to the /tmp/ directory.
Created a file called ruby.rb as a non-root user.
Opened irb as su user.
Now in IRB:
┌┄┄[root::archlinux]┈[/tmp]
└──╼⮚ irb
irb(main):001:0> File.writable?('ruby.rb')
=> true
irb(main):002:0> File.stat('ruby.rb')
=> #<File::Stat dev=0x2d, ino=819138, mode=0100644, nlink=1, uid=1000, gid=1000, rdev=0x0, size=0, blksize=4096, blocks=0, atime=2019-07-14 04:44:13 +0530, mtime=2019-07-14 04:44:13 +0530, ctime=2019-07-14 04:44:13 +0530>
irb(main):003:0> File.write('ruby.rb', '#!/usr/bin/ruby -w')
Traceback (most recent call last):
3: from /root/.irb:351:in `<main>'
2: from (irb):3
1: from (irb):3:in `write'
Errno::EACCES (Permission denied # rb_sysopen - ruby.rb)
irb(main):004:0>
Apart from this, actually I am trying to do is writing a log file. I am checking if the file is writable. If not, it sends notification to the user.
I have faced the problem previously where File#writable?(str) returned true in such case (and it works on the /tmp/ directory). And just used a begin <...> rescue Errno::EACCES block to fix the problem. But in the current project, I don't want to use a rescue block.
Why does the File#writable?(str) return true in the first place?
EDIT: First of all this should be moved to unix.stackexchange.
Secondly I understood
You can't modify a file on a tmp filesystem: I have mounted a mere 4 MiB partition as tmpfs on /mnt. Created a file as local user. Then changed the permission to omnipotent 777! Then I changed my account to root. I tried to edit the contents with nano. It's not possible.
Ruby's File#writable? probably doesn't detect the mounted filesystem type. Whether it's XFS or EXT4 or procfs or tmpfs. If all it does is checking the mode, in such scenario, the File#writable? returns true while in reality, it's not actually writable!
Edit 2: I have uploaded 2 screenshots at imgur:
Okay this is not a Ruby specific problem. That said, any programming language will have such problem because it's all about the file system protection implemented in systemd.
The option fs.protected_regular is implemented in Linux Kernel 4.19+ to make data spoofing attacks harder.
So, firstly you need to check:
sysctl fs.protected_regular
In your case, it should print 1
So, change the value to 0:
sysctl fs.protected_regular=0
Hopefully the problem will get solved. Or try this:
sysctl fs.protected_regular=0
sysctl fs.protected_fifos=0
Note that the option is enabled by default. You may not prefer telling every user of your program to set the above to 0! They may not even prefer that!
So, in Ruby:
You can delete the file:
File.delete('file') if File.exist?('file')
# Better use the '/tmp/file' or File.join(%w(/ tmp file)) otherwise the file will get delete from the Dir.pwd
Which will delete the file every time the script runs.
You can also use begin ... rescue block and use Warning.warn or Kernel.warn or STDERR.puts to print a warning message.
Could be one of 2 things, file is not being opened for writing, or permissions issue with user.
Try to open the file for writing with either 'w' or 'w+'
File.open('ruby.rb', 'w') { |file| file.write("#!/usr/bin/ruby -w") }
If that doesn't work, try using chmod to update file permissions for ruby.rb with
chmod -R 777 <path_to_file>

Failed to run a very simple ruby script [duplicate]

This question already has answers here:
Ruby: how to "require" a file from the current working dir?
(5 answers)
Closed 6 years ago.
I have create a Ruby class Worker, file name is Worker.rb:
class Worker
def initialize
...
end
def doTask(task_name)
...
end
end
Then, I created another Ruby script file, named run.rb (it requires Worker):
require 'Worker'
worker = Worker.new
worker.doTask("sort")
Both two ruby files are located directly under the project folder:
ProjectFolder/
-- Worker.rb
-- run.rb
I run the run.rb under project folder by command:
ruby run.rb
But get following error:
/Users/John/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- Worker (LoadError)
from /Users/John/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from runme.rb:1:in `<main>'
Why?
I figured out after checking #Geo 's github project, I should use:
require_relative "worker"
require looks for the required file from the so called load path and not the current directory. Since the syntax for looking in the current directory was awkward Ruby 1.9 introduces require_relative, which looks in the current directory.
Change your code like this:
require_relative "Worker"
instead of
require "Worker"
The reason this does not work is because the current directory is not part of ruby's default load path.
If you run the following command, you will see what the current load path is and it will confirm that the current directory is not part of that path.
ruby -e 'puts $LOAD_PATH'
This should answer your primary question as to why the required file was not loaded.
As for a solution, require_relative will work and is probably the best solution in this case.
There are however still cases were inserting directories into the load path is helpful, if not required. For example say you have a script that can be run anywhere in the file system and you want the flexibility to require a particular version of your co-worker's foo class.
/afs/some_cell/u/john/some_ruby_lib
prod/
foo.rb
bar.rb
prev/
foo.rb
bar.rb
beta/
foo.rb
bar.rb
In a case like this either setting the RUBYSIM var (maybe in a wrapper) or setting the proper include path on the ruby command line can be a useful solution.
Again, your co-worker has not published this as a gem, he is just providing a shared directory.
There are several ways you can insert directories into the load path when it is appropriate, as demonstrated below:
You can use the -I command line flag
ruby -I some_path -e 'puts $LOAD_PATH'
You can set the RUBYLIB env var to include your current directory.
on unix/linix/osx
export RUBYLIB=some_path
on windows
set RUBYLIB=some_path

how to read file using path in ruby by function IO.readlines("path")[0]

i want to read first line of file by using following function in ruby
IO.readlines("path")[0]
But file is not in current directory, so i use path there
puts IO.readlines("Home/Documents/vikas/SHIF.doc")
but it is giving error as
a1.rb:1:in `readlines': No such file or directory # rb_sysopen - Home/Documents/vikas/SHIF.doc (Errno::ENOENT)
from a1.rb:1:in `<main>'
You can also open a file and read only the first line instead of the entire file
File.open("Home/Documents/vikas/SHIF.doc").readline
You can use File.expand_path:
puts IO.readlines(File.expand_path("Home/Documents/vikas/SHIF.doc", __FILE__))
Note however that it will create path relatively to a file directory, not to a root directory.
If you are using rails, you could use:
puts IO.readlines(Rails.root.join 'Home', 'Documents', 'vikas', 'SHIF.doc')

utime permission denied in windows 7 when call FileUtils.touch(f)

I'm working with ruby 2.0 on windows 7 (unfortunately I have to) and have issue with this code:
FileUtils.touch(file)
This code is needed to update file.ctime (which probably will have problems too)
So, when files is processed I 'touch' them and not processing them in next iteration.
How can I deal with it error?
ruby_path/fileutils.rb:1137:in 'utime': Permission denied 'path_to_file' Errno::EACCES
'block in touch'
'each'
'touch'
example:
file = File.new('file_path')
FileUtils.mkdir_p(path)
FileUtils.cp(file.path, path)
FileUtils.touch(file)
I tested with ruby 1.9 and 2.0. FileUtils.touch works without problems.
Can you provide a MWE. Did you check the permissions on the file you want to check.
Especially: Are you sure, you don't touch a directory?
If you don't want to check for directories, you may extend FileUtils by FileUtils.save_touch:
require 'fileutils'
module FileUtils
def self.save_touch(fpath)
FileUtils.touch(fpath) unless File.directory?(fpath)
end
end
FileUtils.save_touch(Dir.pwd)
After update of question:
FileUtils.touch has one parameter: a file name or path to a file.
You have to adapt your example:
file = File.new('file_path')
FileUtils.mkdir_p(path)
FileUtils.cp(file.path, path)
FileUtils.touch(file.path)

Ruby 'require' error: cannot load such file

I've one file, main.rb with the following content:
require "tokenizer.rb"
The tokenizer.rb file is in the same directory and its content is:
class Tokenizer
def self.tokenize(string)
return string.split(" ")
end
end
If i try to run main.rb I get the following error:
C:\Documents and Settings\my\src\folder>ruby main.rb
C:/Ruby193/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- tokenizer.rb (LoadError)
from C:/Ruby193/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require '
from main.rb:1:in `<main>'
I just noticed that if I use load instead of require everything works fine. What may the problem be here?
I just tried and it works with require "./tokenizer".
Just do this:
require_relative 'tokenizer'
If you put this in a Ruby file that is in the same directory as tokenizer.rb, it will work fine no matter what your current working directory (CWD) is.
Explanation of why this is the best way
The other answers claim you should use require './tokenizer', but that is the wrong answer, because it will only work if you run your Ruby process in the same directory that tokenizer.rb is in. Pretty much the only reason to consider using require like that would be if you need to support Ruby 1.8, which doesn't have require_relative.
The require './tokenizer' answer might work for you today, but it unnecessarily limits the ways in which you can run your Ruby code. Tomorrow, if you want to move your files to a different directory, or just want to start your Ruby process from a different directory, you'll have to rethink all of those require statements.
Using require to access files that are on the load path is a fine thing and Ruby gems do it all the time. But you shouldn't start the argument to require with a . unless you are doing something very special and know what you are doing.
When you write code that makes assumptions about its environment, you should think carefully about what assumptions to make. In this case, there are up to three different ways to require the tokenizer file, and each makes a different assumption:
require_relative 'path/to/tokenizer': Assumes that the relative path between the two Ruby source files will stay the same.
require 'path/to/tokenizer': Assumes that path/to/tokenizer is inside one of the directories on the load path ($LOAD_PATH). This generally requires extra setup, since you have to add something to the load path.
require './path/to/tokenizer': Assumes that the relative path from the Ruby process's current working directory to tokenizer.rb is going to stay the same.
I think that for most people and most situations, the assumptions made in options #1 and #2 are more likely to hold true over time.
Ruby 1.9 has removed the current directory from the load path, and so you will need to do a relative require on this file, as David Grayson says:
require_relative 'tokenizer'
There's no need to suffix it with .rb, as Ruby's smart enough to know that's what you mean anyway.
require loads a file from the $LOAD_PATH. If you want to require a file relative to the currently executing file instead of from the $LOAD_PATH, use require_relative.
I would recommend,
load './tokenizer.rb'
Given, that you know the file is in the same working directory.
If you're trying to require it relative to the file, you can use
require_relative 'tokenizer'
I hope this helps.
Another nice little method is to include the current directory in your load path with
$:.unshift('.')
You could push it onto the $: ($LOAD_PATH) array but unshift will force it to load your current working directory before the rest of the load path.
Once you've added your current directory in your load path you don't need to keep specifying
require './tokenizer'
and can just go back to using
require 'tokenizer'
This will work nicely if it is in a gem lib directory and this is the tokenizer.rb
require_relative 'tokenizer/main'
For those who are absolutely sure their relative path is correct, my problem was that my files did not have the .rb extension! (Even though I used RubyMine to create the files and selected that they were Ruby files on creation.)
Double check the file extensions on your file!
What about including the current directory in the search path?
ruby -I. main.rb
I used jruby-1.7.4 to compile my ruby code.
require 'roman-numerals.rb'
is the code which threw the below error.
LoadError: no such file to load -- roman-numerals
require at org/jruby/RubyKernel.java:1054
require at /Users/amanoharan/.rvm/rubies/jruby-1.7.4/lib/ruby/shared/rubygems/custom_require.rb:36
(root) at /Users/amanoharan/Documents/Aptana Studio 3 Workspace/RubyApplication/RubyApplication1/Ruby2.rb:2
I removed rb from require and gave
require 'roman-numerals'
It worked fine.
The problem is that require does not load from the current directory. This is what I thought, too but then I found this thread. For example I tried the following code:
irb> f = File.new('blabla.rb')
=> #<File:blabla.rb>
irb> f.read
=> "class Tokenizer\n def self.tokenize(string)\n return string.split(
\" \")\n end\nend\n"
irb> require f
LoadError: cannot load such file -- blabla.rb
from D:/dev/Ruby193/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `req
uire'
from D:/dev/Ruby193/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `req
uire'
from (irb):24
from D:/dev/Ruby193/bin/irb:12:in `<main>'
As it can be seen it read the file ok, but I could not require it (the path was not recognized). and here goes code that works:
irb f = File.new('D://blabla.rb')
=> #<File:D://blabla.rb>
irb f.read
=> "class Tokenizer\n def self.tokenize(string)\n return string.split(
\" \")\n end\nend\n"
irb> require f
=> true
As you can see if you specify the full path the file loads correctly.
First :
$ sudo gem install colored2
And,you should input your password
Then :
$ sudo gem update --system
Appear
Updating rubygems-update
ERROR: While executing gem ... (OpenSSL::SSL::SSLError)
hostname "gems.ruby-china.org" does not match the server certificate
Then:
$ rvm -v
$ rvm get head
Last
What language do you want to use?? [ Swift / ObjC ]
ObjC
Would you like to include a demo application with your library? [ Yes / No ]
Yes
Which testing frameworks will you use? [ Specta / Kiwi / None ]
None
Would you like to do view based testing? [ Yes / No ]
No
What is your class prefix?
XMG
Running pod install on your new library.
you need to give the path.
Atleast you should give the path from the current directory. It will work for sure.
./filename

Resources