I want to save the path of a file that lives in the desktop but seem that rails can not recognise it with the path specified. I tried this:
def calculate_hash
require 'digest'
file_path = "Users/crs/Desktop/index.xml"
sha1 = Digest::SHA1.file file_path
puts "Checksum SHA1: #{sha1.hexdigest}"
end
If I run this method I get an error saying " No such file or directory # rb_sysopen - /Users/crsDesktop/index.xml
"
Please hep me how I can make it recognisable.
Since Users is a root directory you must specify the full path:
file_path = "/Users/crs/Desktop/index.xml"
Notice the / prefix.
Another thing to note is paths use slash (/) and not backslash (\\). If you use a backslash by accident it will "disappear" in most cases:
file_path = "/Users/crs\Desktop/index.xml"
# => "/Users/crsDesktop/index.xml"
Where \D has special meaning within double-quoted strings and means, in this case, literal capital D.
Related
Facing below issue eventhough the file is present in the folder.
H:\Ruby_test_works>ruby hurrah.rb
hurrah.rb:7:in `read': No such file or directory # rb_sysopen - H:/Ruby_
test_works/SVNFolders.txt (Errno::ENOENT)
from hurrah.rb:7:in `block in <main>'
from hurrah.rb:4:in `each_line'
from hurrah.rb:4:in `<main>'
Input file (input.txt) Columns are tab separated.
10.3.2.021.asd 10.3.2.041.def SVNFolders.txt
SubversionNotify Subversionweelta post-commit.bat
Commit message still rake customemail.txt
mckechney.com yahoo.in ReadMe.txt
Code :
dir = 'H:/Ruby_test_works'
file = File.open("#{dir}/input.txt", "r")
file.each_line do |line|
initial, final, file_name = line.split("\t")
#puts file_name
old_value = File.read("#{dir}/#{file_name}")
replace = old_value.gsub( /#{Regexp.escape(initial)}, #{Regexp.escape(final)}/)
File.open("#{dir}/#{file_name}", "w") { |fi| fi.puts replace }
end
I have tried using both forward and backward slashes but no luck. What I'm missing, not sure. Thanks.
puts file_name gives the below values
SVNFolders.txt
post-commit.bat
customemail.txt
ReadMe.txt
The file_name contains the newline character \n at the end, which won't get printed but messes up the path. You can fix the issue by stripping the line first:
initial, final, file_name = line.strip.split("\t")
When debugging code, be careful with puts. Quoting its documentation reveals an ugly truth:
Writes the given object(s) to ios. Writes a newline after any that do not already end with a newline sequence.
Another way to put this is to say it ignores (potential) newlines at the end of the object(s). Which is why you never saw that the file name actually was SVNFolders.txt\n.
Instead of using puts, you can use p when troubleshooting issues. The very short comparison between the two is that puts calls to_s and adds a newline, while p calls inspect on the object. Here is a bit more details about the differences: http://www.garethrees.co.uk/2013/05/04/p-vs-puts-vs-print-in-ruby/
Sometimes the issue is not the file, but the path to the file. Consider compare the file path with what you think the file path is with something like:
File.expand_path('my_file.rb')
Let says I've this path:
path = "D:\Google Drive\Samples\Black Octopus Sound\Leviathan\Drums - Kicks\Lev_Kick_A_003.wav"
what's the smart and clean way to get the parent path from this string/path? i.e.:
D:\Google Drive\Samples\Black Octopus Sound\Leviathan\Drums - Kicks\
Couple of ways of doing it as a pure string, either via a regular expression or using split,pop,join.
path = "D:\\Google Drive\\Samples\\Black Octopus Sound\\Leviathan\\Drums - Kicks\\Lev_Kick_A_003.wav"
items = path.split("\\")
items.pop
result = items.join("\\")
puts result
> D:\Google Drive\Samples\Black Octopus Sound\Leviathan\Drums - Kicks
Note I've replaced "\" with "\\" in all cases to escape the slashes
Or in a one liner:
path.split("\\").reverse.drop(1).reverse.join("\\")
The best way is probably Pathname as per other answers, but if you can't use that then string manipulation should work.
Use Pathname:
require 'pathname'
path = "D:\\Google Drive\\Samples/Drums - Kicks\\Lev_Kick_A_003.wav"
Pathname(path).parent
#=> #<Pathname:D:\Google Drive\Samples\Drums - Kicks>
Pathname correctly handles the specific file path syntax of the given operating system.
If I do:
require 'inifile'
# read an existing file
file = IniFile.load('~/.config')
data = file['profile'] # error here
puts data['region']
I get an error here:
t.rb:6:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError)
It goes away if I specify an absolute path:
file = IniFile.load('/User/demo1/.config')
But I do not want to hardcode the location. How can I resolve ~ to a path in Ruby?
Ruby has a method for this case. It is File::expand_path.
Converts a pathname to an absolute pathname. Relative paths are referenced from the current working directory of the process unless dir_string is given, in which case it will be used as the starting point. The given pathname may start with a “~”, which expands to the process owner’s home directory (the environment variable HOME must be set correctly). “~user” expands to the named user’s home directory.
require 'inifile'
# read an existing file
file = IniFile.load(File.expand_path('~/.config'))
When given ~ in a path at the command line, the shell converts ~ to the user's home directory. Ruby doesn't do that.
You could replace ~ using something like:
'~/.config'.sub('~', ENV['HOME'])
=> "/Users/ttm/.config"
or just reference the file as:
File.join(ENV['HOME'], '.config')
=> "/Users/ttm/.config"
or:
File.realpath('.config', ENV['HOME'])
=> "/Users/ttm/.config"
I'm developing a library that provides access to gem metadata, including it's location on the file system. The idea was to let gem authors set it to a relative path from any script:
# $root/example.gemspec
Example::Gem.root '.' # => $root/
# $root/lib/example/gem.rb
Example::Gem.root '../..' # => $root/
Then, the path of the current script would be used to compute the absolute path. My implementation is currently as follows:
def root(relative_to = nil, file = __FILE__)
unless relative_to.nil?
#root = File.expand_path relative_to, File.dirname(file)
end
#root
end
I thought __FILE__ would return the path to the caller's script, but that assumption is wrong.
It worked within the library itself, but broke down when I tried to integrate it with one of my other gems; the generated path was always relative to the support library itself.
How can I implement this without having to pass the current __FILE__ on every call? Otherwise, there isn't much value to be gained; writing root('../..', __FILE__) is almost the same as writing an actual method to do the same thing.
If it's possible to figure out the path without having to specify anything, that would be even better, but I couldn't think of anything. How does Rails do it?
By the way, I'm aware of Gem::Specification#gem_dir, but it always returns paths relative to the installation directory, even if the gem is not actually there, which makes it useless in a development environment.
You can always make use of the backtrace facility provided:
caller.first
It produces an amalgam of file and line but is usually separated by :. I'd be careful to allow for filenames or paths that may contain colon for whatever reason by ignoring the line information but preserving the rest. In other words, do not split but sub:
caller.first.sub(/:\d+:in .*$/, '')
I would like to generate a list of files within a directory. Some of the filenames contain Chinese characters.
eg: [试验].Test.txt
I am using the following code:
require 'find'
dirs = ["TestDir"]
for dir in dirs
Find.find(dir) do |path|
if FileTest.directory?(path)
else
p path
end
end
end
Running the script produces a list of files but the Chinese characters are escaped (replaced with backslashes followed by numbers). Using the example filename above would produce:
"TestDir/[\312\324\321\351]Test.txt" instead of "TestDir/[试验].Test.txt".
How can the script be altered to output the Chinese characters?
Ruby needs to know that you are dealing with unicode in your code. Set appropriate character encoding using KCODE, as below:
$KCODE = 'utf-8'
I think utf-8 is good enough for chinese characters.
The following code is more elegant and doesn't require 'find.' It produces a list of files (but not directories) in whatever the working directory is (or whatever directory you put in).
Dir.entries(Dir.pwd).each do |x|
p x.encode('UTF-8') unless FileTest.directory?(x)
end
And to get a recursive digging down one level use:
Dir.glob('*/*').each do |x|
p x.encode('UTF-8') unless FileTest.directory?(x)
end
I'm sure there is a way to get it to go all the way down but Dir.glob('**/*') will go through the whole file system if I remember right.