Open directory and create new file - ruby

I have this statement that creates nested directories:
require 'fileutils'
FileUtils::mkdir_p ''+project_name+'/new_folder'
I want to add for example a new file called README.md inside new_folder. Is there a way to accomplish that with Ruby?

You just need to do
path_name = "#{project_name}/new_folder"
FileUtils::mkdir_p path_name
FileUtils::touch("#{path_name}/README.md")
This will create an empty file named README.md inside your project_name/new_folder directory.

You can do it like this
2.1.2 :015 > project_name = "foo"
=> "foo"
2.1.2 :016 > fld = FileUtils::mkdir_p "#{project_name}/new_folder"
=> ["foo/new_folder"]
2.1.2 :017 > FileUtils.touch "#{fld[0]}/README.md" if fld
=> ["foo/new_folder/README.md"]
[retgoat#iMac-Roman ~/foo/new_folder]$ ls -la
total 0
drwxr-xr-x 3 retgoat staff 102 17 май 17:44 .
drwxr-xr-x# 119 retgoat staff 4046 17 май 17:45 ..
-rw-r--r-- 1 retgoat staff 0 17 май 17:44 README.md
Please note I didn't test your code, but if it works for you, following example will create a file README.md inside new_folder

For building filespecs, it's better to use the File.join method. This is higher level, handles any extra or missing directory separators, and uses the right file separator for the OS on which it's running.
For example:
2.3.0 :006 > project_name = 'my_project'
=> "my_project"
2.3.0 :009 > filespec = File.join(project_name, 'new_folder', 'README.md')
=> "my_project/new_folder/README.md"
When the slashes are provided before and after 'new_folder', it still works:
2.3.0 :010 > filespec = File.join(project_name, '/new_folder/', 'README.md')
=> "my_project/new_folder/README.md"

Related

Why files aren't found with File.exist

I have a working directory like that one:
sascha#sascha-desktop:~/Musik/RMB/Youtube-Music$ ls -la
insgesamt 46456
drwxrwxr-x 2 sascha sascha 4096 Dez 9 10:32 .
drwxrwxr-x 3 sascha sascha 4096 Dez 6 22:47 ..
-rw-rw-r-- 1 sascha sascha 20751305 Apr 22 2015 RMB - Spring-dJl7zWZYj-E.mp4
-rw-rw-r-- 1 sascha sascha 6051641 Apr 22 2015 RMB - Spring.m4a
-rw-rw-r-- 1 sascha sascha 20751305 Apr 22 2015 RMB - Spring.mp4
In my Ruby program i'm having two methods:
def self.rename(title)
filename = title.to_s
ext = file_exist_ogg_m4a(filename)
filenamenew0 = filename.gsub(/ /, '_')
pattern = /[a-zA-Z0-9\-\s\_]/
filenamenew = filenamenew0.split(//).keep_if do |chr|
chr =~ pattern
end.join
puts 'Renaming the downloaded file'
puts "Filename: #{filename}" # debug
puts "Filenamenew: #{filenamenew}" # debug
puts "Extension: #{ext}" # debug
puts Dir.pwd # debug
#FileUtils.mv("#{filename}.#{ext}", "#{filenamenew}.#{ext}")
#[filenamenew, filename]
end
def self.file_exist_ogg_m4a(filename)
puts 'Accessing file_exist_ogg_m4a'
puts Dir.pwd # debug
if File.exist?("#{filename}.ogg")
ext = 'ogg'
elsif File.exist?("#{filename}.m4a")
ext = 'm4a'
elsif File.exist?("#{filename}.webm")
ext = 'webm'
end
puts ext # debug
puts 'Closing file_exist_ogg_m4a'
return ext # debug
end
I'm getting the extension through the file_exist_ogg_m4a method.
By running the program it gives me:
Accessing file_exist_ogg_m4a
/home/sascha/Musik/RMB/Youtube-Music
Closing file_exist_ogg_m4a
Renaming the downloaded file
Filename: RMB - Spring
Filenamenew: RMB_-_Spring
Extension:
/home/sascha/Musik/RMB/Youtube-Music
So it looks like i'm in the right directory, a #{filename}.m4a should be found, and the ext variable should contain "m4a".
But if i'm looking the running method "rename" looks me a empty #{ext}.
If i'm using that code it finds a m4a file:
dir = Dir.pwd
if !Dir.glob("#{dir}/*.ogg").empty?
ext = 'ogg'
elsif !Dir.glob("#{dir}/*.m4a").empty?
ext = 'm4a'
elsif !Dir.glob("#{dir}/*.webm").empty?
ext = 'webm'
end
So i think it has to do with the string "filename".
Maybe anyone has an idea?
File.exist? is related to the current script directory, not to the internals of Dir. One might use:
File.exist?(File.join Dir.pwd, "#{filename}.ogg")
to achieve the requested functionality.

Ruby Errno:ENOENT when filename string is a return from gsub

I'm encountering an issue with a ruby script called from CLI (not in a framework) that results in a ENOENT error (File does not exist) when attempting to open it, but only when the filename has been constructed using gsub regular expression replacement. It works when the string is constructed by any other method. I'm sure it's something simple that I've done wrong, but I've had a heck of a time figuring it out.
System Information
# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 12.04.3 LTS
Release: 12.04
Codename: precise
# rvm -v
rvm 1.23.13 (stable) by Wayne E. Seguin <wayneeseguin#gmail.com>, Michal Papis <mpapis#gmail.com> [https://rvm.io/]
# ruby -v
ruby 2.0.0p195 (2013-05-14 revision 40734) [x86_64-linux]
Filesystem: ext2
Permissions:
# ls -lah /home/boise/config
total 24K
drwxr-xr-x 2 boise boise 4.0K Nov 13 19:40 .
drwxr-xr-x 11 boise boise 4.0K Nov 13 20:22 ..
-rwxr-xr-x 1 boise boise 248 Nov 13 09:31 boise.yaml
-rwxr-xr-x 1 boise boise 335 Nov 13 19:35 config.rb
-rwxr-xr-x 1 boise boise 339 Nov 13 20:06 stanford.yaml
-rwxr-xr-x 1 boise boise 248 Nov 13 09:49 test.yaml
user being used to run scripts and owns containing directory is 'boise'
there is nothing abnormal about the file system here, no symbolic links or
mappings or anything like that.
I started a simple script to reproduce the error. In this I boiled it down as simple as I could, made the prefix of the path static and used absolute paths so that there is no question about relative paths or current working directories.
scriptname: testing
#!/usr/bin/env ruby
require 'yaml'
# Here we are "hardcoding" the values.
$config_yaml = "boise.yaml"
puts $config_yaml
config_filespec = "/home/boise/config/#{$config_yaml}"
puts config_filespec
puts File.exists? config_filespec
$configuration = YAML.load(File.open(config_filespec))
$verbose = true
hosts = []
args = []
puts $config_yaml
ARGV.each do |arg|
if arg.match /hosts\=(.*?)/i
hosts = ARGV.delete(arg).gsub(/hosts\=(.*?)/i,'\2').split(',')
elsif arg == "quiet"
$verbose = false
ARGV.delete(arg)
elsif arg.match /cfg=(.*?)/
#Here the value of the YAML file to be loaded is set with a regular expression substitution.
$config_yaml = ARGV.delete(arg).gsub(/cfg=(.*?)/, "\2")
else
end
end
#do the same output as we did the first time hardcoded, but this time the
#value got reset by a gsub -- same variable, same name, etc
puts $config_yaml
config_filespec = "/home/boise/config/#{$config_yaml}"
puts config_filespec
puts File.exists? config_filespec
$configuration = YAML.load(File.open(config_filespec))
This works as one would expect:
# ./testing
boise.yaml
/home/boise/config/boise.yaml
true
boise.yaml
boise.yaml
/home/boise/config/boise.yaml
true
But watch what happens when I'm passing in the yaml string as a command line parameter. Note that this is even the exact same filename!
# ./testing cfg=boise.yaml
boise.yaml
/home/boise/config/boise.yaml
true
boise.yaml
boise.yaml
/home/boise/config/boise.yaml
false
./testing:31:in `initialize': No such file or directory - /home/boise/config/boise.yaml (Errno::ENOENT)
from ./testing:31:in `open'
from ./testing:31:in `<main>'
I also tried forcefully casting the string with String(config_filespec), config_filespec.to_s, and using + "" to do a string concatenation, in hopes that it was some type issue with string versus literal or regex or something like that. Any ideas?
Thanks in advance Stack Overflow!
The answer is that you're not getting the results that you think you're getting from the gsub. This boils down to a ruby quirk. When using double-quotes, "\2" evaluates to "002". However, using single quotes '\2' will return the second capture group. In your code...
$config_yaml = ARGV.delete(arg).gsub(/cfg=(.*?)/, '\2')
If you're only going to accept a single file name, would it be worth using split?
$config_yaml = ARGV.delete(arg).split(/=/, 2).last

Why does `Dir[directory_path].empty?` return `false` all the time?

Dir[directory_path].empty? returns false all the time. The behavior is the same whether or not I run irb as root:
$ ll
total 12
drwxrwxrwx 2 ndefontenay ndefontenay 4096 Aug 12 12:11 ./
drwxrwxrwx 4 ndefontenay ndefontenay 4096 Aug 5 11:45 ../
-rw-rw-r-- 1 ndefontenay ndefontenay 8 Aug 12 12:11 test
$ irb
> Dir["/opt/purge_entitlement/in"].empty?
=> false
> exit
$ sudo irb
> Dir["/opt/purge_entitlement/in"].empty?
=> false
If someone could shed some light on this problem, it would be pretty helpful.
Dir[].empty? returns false all the time
It should,because it always contains the parent directory (..), and the directory itself (.),that you didn't take care of.
This is not an answer to your question, but to avoid the problem of getting . and .. in the list, use Dir.glob instead of Dir.[]. You will probably get true for this:
Dir.glob("/opt/purge_entitlement/in/*").empty?

ruby webrick and cgi

I can't get Webrick to work with the servlet HTTPServlet::CGIHandler--I get an EACCES error:
[2012-12-06 01:38:02] ERROR CGIHandler: /tmp/cgi-bin:
/Users/7stud/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httpservlet/cgi_runner.rb:46:in `exec': Permission denied - /tmp/cgi-bin (Errno::EACCES)
from /Users/7stud/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httpservlet/cgi_runner.rb:46:in `<main>'
[2012-12-06 01:38:02] ERROR CGIHandler: /tmp/cgi-bin exit with 1
[2012-12-06 01:38:02] ERROR Premature end of script headers: /tmp/cgi-bin
localhost - - [06/Dec/2012:01:38:02 MST] "GET /cgi/my_prog.cgi HTTP/1.1" 500 326
- -> /cgi/my_prog.cgi
Here are the permissions I set:
~/ruby_programs$ cd /
/$ ls -al tmp
lrwxr-xr-x# 1 root wheel 11 Jul 3 2011 tmp -> private/tmp
/$ cd tmp
/tmp$ ls -al
total 0
drwxrwxrwt 8 root wheel 272 Dec 6 01:08 .
drwxr-xr-x# 6 root wheel 204 Mar 27 2010 ..
drwxr-xr-x 3 7stud wheel 102 Dec 6 01:25 cgi-bin
/tmp$ cd cgi-bin/
/tmp/cgi-bin$ ls -al my_prog.cgi
-rwxr-xr-x 1 7stud wheel 123 Dec 6 01:09 my_prog.cgi
My server program(1.rb):
#!/usr/bin/env ruby
require 'webrick'
include WEBrick
port = 12_000
dir = Dir::pwd
server = HTTPServer.new(
:Port => port,
:DocumentRoot => dir + "/html"
)
server.mount("/cgi", HTTPServlet::CGIHandler, "/tmp/cgi-bin")
puts "Listening on port: #{port}"
Signal.trap('SIGINT') { server.shutdown }
server.start
Running my server program:
~/ruby_programs$ ruby 1.rb
[2012-12-06 01:37:58] INFO WEBrick 1.3.1
[2012-12-06 01:37:58] INFO ruby 1.9.3 (2012-04-20) [x86_64-darwin10.8.0]
Listening on port: 12000
[2012-12-06 01:37:58] INFO WEBrick::HTTPServer#start: pid=4260 port=12000
I entered this address in my browser:
http://localhost:12000/cgi/my_prog.cgi
This was displayed in my browser:
Internal Server Error
Premature end of script headers: /tmp/cgi-bin WEBrick/1.3.1
(Ruby/1.9.3/2012-04-20) at localhost:12000
Here's my cgi script(/tmp/cgi-bin/my_prog.cgi):
#!/usr/bin/env ruby
require 'cgi'
cgi = CGI.new
puts cgi.header
puts "<html><body>Hello Webrick</body></html>"
The only way I can get WEBrick to execute cgi files in a directory other than the root, is to use the HTTPServlet::FileHandler servlet:
port = 12_500
...
cgi_dir = File.expand_path("~/ruby_programs/cgi-bin")
server.mount("/cgi", HTTPServlet::FileHandler, cgi_dir)
Then the url used to execute a .cgi file located in the cgi_dir is:
http://localhost:12500/cgi/my_prog.cgi
Apparently, when you write:
server = HTTPServer.new(
:Port => port,
:DocumentRoot => "./html" #Regular files served/.cgi files executed out of this dir
)
Webrick automatically "mounts" an HTTPServlet::FileHandler to handle requests to the :DocumentRoot directory, e.g.
http://localhost:12500/my_html.htm
which will serve files out of the ./html directory (i.e. a directory called html located below the directory from which your program is running). The HTTPServlet::FileHandler will also execute files in that directory if they have a .cgi extension.
If you explicitly use mount() to add an HTTPServlet::FileHandler to another directory, e.g.
cgi_dir = File.expand_path("~/ruby_programs/cgi-bin")
server.mount("/cgi", HTTPServlet::FileHandler, cgi_dir)
then WEBrick will also serve files from that directory and execute files in that directory that have a .cgi extension.
I haven't found a way to configure WEBrick to only serve files out of the :DocumentRoot directory and only execute .cgi files in another directory.
See "Gnome's Guide to WEBrick" here:
http://microjet.ath.cx/webrickguide/html/
In my case I had similar problems because of incorrect file permissions and really incorrect headers. Permissions of CGI-script should be like this:
~/ruby_projects/cgi_webrick/cgi
ls -l
-rwxr-xr-x 1 me me 112 Sep 20 20:29 test.cgi
My server code looks very similar (placed in ~/ruby_projects/cgi_webrick/), but with different handler.
#!/usr/bin/env ruby
require 'webrick'
server = WEBrick::HTTPServer.new :Port => 1234
server.mount "/", WEBrick::HTTPServlet::FileHandler , './'
trap('INT') { server.stop }
server.start
If you run server script ruby my_server_script.cgi, it will serve any scripts from root or other directory. In my case I can access http://localhost:1234/cgi/test.cgi (script placed in cgi subfolder), and http://localhost:1234/test.cgi (placed in the root directory from which server is started).
My test script:
#!/usr/bin/ruby
require 'cgi'
cgi = CGI.new
puts cgi.header
puts "<html><body>This is a test</body></html>"

How to get last modified file in a directory to pass to system commands using Ruby?

I'm trying to do some dev-ops. I need to grab the last modified file in a directory to pass the filename to another command.
If I had a list of files outputted with ls -la in Ruby:
-rw-r--r-- 1 163929215 2012-11-26 00:02 appname_20121126_000002.tgz
-rw-r--r-- 1 164051752 2012-11-27 00:02 appname_20121127_000002.tgz
-rw-r--r-- 1 164160113 2012-11-28 00:02 appname_20121128_000002.tgz
-rw-r--r-- 1 164284597 2012-11-29 00:02 appname_20121129_000004.tgz
-rw-r--r-- 1 164342795 2012-11-30 00:02 appname_20121130_000003.tgz
-rw-r--r-- 1 164448312 2012-12-01 00:02 appname_20121201_000003.tgz
-rw-r--r-- 1 164490727 2012-12-02 00:02 appname_20121202_000002.tgz
-rw-r--r-- 1 164546124 2012-12-03 00:02 appname_20121203_000001.tgz
-rw-r--r-- 1 164594711 2012-12-04 00:02 appname_20121204_000002.tgz
How could I scan this with Ruby and pull the last file?
Is something like this even possible?
There's no need to shell out to ls and parse its output at all. Ruby gives you standard library methods to fetch directory contents and examine file mtimes. Here's a ruby method to return the name of a file in a directory with the latest mtime.
def last_modified_in dir
Dir.glob( File.join( dir,'*' ) ).
select {|f| File.file? f }.
sort_by {|f| File.mtime f }.
last
end
irb> system 'mkdir -p /tmp/foo'
irb> system 'rm /tmp/foo/*'
irb> ('a'..'c').each { |f| system "touch /tmp/foo/#{f}"; sleep 1; }
irb> puts last_modified_in '/tmp/foo'
# => /tmp/foo/c

Resources