Why should I use File.join()? - ruby

I wonder why I should use:
puts "In folder #{File.join ENV[HOME], projects}"
Instead of:
puts "In folder #{ENV[HOME]/projects}"
I am aware of that File.join will put the appropriate separator (/ vs \) depending on the OS.
The script is already so tightly tied to what version of ruby you are using, what gems you have installed and so on. My scripts tend not to be like an ORM, (in this case) independent of OS.
I will never run this on Windows (the other dependencies will make the script not to work anyway).
So seems not to be a strong reason for using it, right?

Any of the following :
File.join("first","second")
File.join("first/","second")
File.join("first","/second")
File.join("first/","/second")
Will return
=> "first/second"
Could it be a good reason for you ?
That's only one example I can think of.
Actually, your goal is not to concatenate 2 strings, your goal is creating a path. This looks like a strong reason to use File.join to me.

Haven't used Ruby, but I expect a Path.join to handle corner cases, like paths ending with or without directory separators. Besides, it expresses intent a bit more clearly than string concatenation, and clarity is IMHO almost always a good idea.

I expect join to handle corner cases gracefully, like when ENV[HOME] is empty for some weird reason.

In addition to the other answers your code will be more portable, the correct separator will be used regardless of unix/windows/etc.

be aware of difference between RUBY and PYTHON
RUBY: File.join("","somthing") → "/something"
PYTHON: os.path.join("","somthing") → "something"
RUBY treat empty string as path → I call this a BUG

Related

Did Ruby deprecate the wrong File exists method?

The docs of File.exist? says:
Return true if the named file exists.
Note that last word used; "exists". This is correct. "File exist" without the ending s is not correct.
The method File.exists? exists, but they deprecated this method. I am thinking it should have been the other way around. What am I missing?
Also, it's noteworthy that other languages/libraries use exists, for example Java and .NET.
Similarly, "this equals that" - but Ruby uses equal, again dropping the ending s. I am getting a feeling that Ruby is actively walking in another direction than mainstream. But then there has to be a reason?
This is largely a subjective call. Do you read the call as "Does this file exist?" or "File exists"? Both readings have their merits.
Historically Ruby has had a lot of aliased methods like size vs. length, but lately it seems like the core team is trying to focus on singular, consistent conventions that apply more broadly.
You'd have to look closely at the conversations on the internal mailing list surrounding the decisions here. I can't find them easily, only people dealing with the changes as deprecation warnings pop up.
The Ruby core team is a mix of people who speak different languages but the native language is Japanese, so perhaps that's guiding some of these decisions. It could be a preference to avoid odd inflections on verbs.
I agree that if File.exists?('x.txt') reads much more natural than the plural form, which was probably Matz's intention for the alias. As far as I'm concerned, this particular deprecation was misguided.
However the general preference of a plural form may well be routed in handling enumarables/collections, where plural makes a sense when used with idioms like this:
pathnames.select(&:exist?)
exist? matches the convention used elsewhere throughout the stdlib, and goes back to the early days of ruby. For example array.include? (not includes?), string.match? (not matches?), object.respond_to? (not responds_to?). So in this light, File.exists? was always a blemish.
Some recommend that you read the dot as "does". So "if file does exist," "if array does include," "if string does match," etc.

How to build a portable absolute path in Ruby?

Let's assume a script needs access a directory, say /some/where/abc on an "arbitrary" OS. There are a couple options to build the path in Ruby:
File.join('', 'some', 'where', 'abc')
File.absolute_path("some#{File::SEPARATOR}where#{File::SEPARATOR}abc", File::SEPARATOR)
Pathname in the standard API
I believe the first solution is clear enough, but idiomatic. In my experience, some code reviews ask for a comment to explain what it does...
The Question
Is there a better way to build an absolute path is Ruby, where better means "does the job and speaks for itself"?
What I would pick up if I was doing a code review is that on Windows /tmp is not necessarily the best place to create a temporary directory, and also the initial '', argument is perhaps not obvious to the casual reviewed that it creates <nothing>/tmp/abc. Therefore, I would recommend this code:
File.join(Dir.tmpdir(), 'abc')
See Ruby-doc for an explanation.
UPDATE
If we expand the problem to a more generic solution that does not involve using tmpdir(), I cannot see a way round using the initial '' idiom (hack?). On Linux this is not too much of a problem, perhaps, but on Windows with multiple drive letters it will be. Furthermore, there does not appear to be a Ruby API or gem for iterating the mount points.
Therefore, my recommendation would be to delegate the mount point definition to a configuration option that might be '/' for Linux, 'z:/' for Windows, and smb://domain;user#my.file.server.com/mountpoint for a Samba share, then use File.join(ProjectConfig::MOUNT_POINT, 'some', 'where', 'abc').
File#join is THE canonical way to build a portable path in Ruby. I'm wondering who is doing the review. Perhaps Ruby is new to your organization.
I agree with #ChrisHeald that referring to the documentation is the best way to explain the code to a reviewer.

Ruby OptionParser empty switch "-" behavior

EDITED:
I've wrote code that uses OptionParser to handle command line input gracefully. I am facing two major hits.
Passing an empty switches '-' doesn't give an error. Of course some programs take that as valid, but mine shouldn't.
The program requires two mandatory switches, but it accepts one switch without complaining! e.g. program.ruby -f foo -b bar is the valid input and both switches are :REQUIRED. But providing only one switch passes without problem and this is not the desired behavior.
For the first case I've done this:
opts.on('-', /\A-\Z/) do
$stderr.print "Invalid empty switch"
exit 1
end
It works fine. But is this the proper way of doing it?
For the second case, I've looked around for a solution within the OptionParser.new block but I couldn't find one. e.g.
unless options.foo && options.bar
puts "Error."
exit 2
end
Doing it outside the OptionParser.new block is the normal way?
If you are using OptionParser, then yes, you need to explicitly disallow the empty switch and manually check the required parameters.
However, if you used another tool for option parsing, such as defunkt's gem choice, you could mark options as required and the invalid options (such as the empty switch) would cause the help to be printed and application to exit. I understand that in some cases it makes more sense to use OptionParser, but personally I prefer to use the more convenient tools out there.
Even though making options required is pretty easy one way or the other, I would recommend that you think your API decision through. How many command line utilities do you know, that have required options? There's a reason why command line is usually separated into options and arguments, with the former being usually optional and the latter usually required. I would stick to that established convention.
I think Thor(https://github.com/wycats/thor) can resolve your problem more efficiently.

syntax-check a VimL script

I have a sizable vim script (a .vim file, in viml syntax). I'd like to check (but not execute!) the file for simple syntax errors.
How do I accomplish this?
I just want a very rough syntax check. Something along the lines of perl -c or pyflakes.
Here is a syntax checker for VimL.
https://github.com/syngan/vim-vimlint/
I don't think (I'm relatively sure, as much as one can be) one exists. VimL is an internal language of Vim (and only Vim), and there aren't many tools developed for it.
I tried searching on vim.org and several other places, with no luck. Not suprising, because I've never heard of one either.
So you're either stuck with running the script, or switching to an outside language like Python, Perl or Ruby.
https://github.com/osyo-manga/vim-watchdogs
vim-watchdogs, apparently, is a syntax checker for vim, it says that it supports many languages, including vimL
if you use vundle, you can just drop this into your vimrc:
Plugin 'git://github.com/osyo-manga/vim-watchdogs.git'
..and then run:
:PluginInstall
..to set it up (vundle is a very nifty plugin manager) If you have syntastic, you might want to be careful and disable it first, and then see if it is an adequate replacement (since it says it supports all those languages anyway).
It is a safe bet that when you have multiple syntax checkers going, you will need to put your "dogs on a leash", so to speak; by configuring one to check languages that the other one does not, and vice-versa. If you do not, there will be at best collisions, duplications, or misdirections. At worst, you will have all of the above and more.
Make sure that you always backup your ~/.vim directory (or your VIMRUNTIME directory if you install things on a global level), you will be glad you did. Hope that helped you or someone else out, good luck! Sorry you had to wait 7.5 months for a response, heh :)
There's now a second option: vim-lint (as opposed to vimlint)

What are the pros and cons of Ruby's general delimited input? (percent syntax)

I don't understand why some people use the percentage syntax a lot in ruby.
For instance, I'm reading through the ruby plugin guide and it uses code such as:
%w{ models controllers }.each do |dir|
path = File.join(File.dirname(__FILE__), 'app', dir)
$LOAD_PATH << path
ActiveSupport::Dependencies.load_paths << path
ActiveSupport::Dependencies.load_once_paths.delete(path)
end
Every time I see something like this, I have to go and look up the percentage syntax reference because I don't remember what %w means.
Is that syntax really preferable to ["models", "controllers"].each ...?
I think in this latter case it's more clear that I've defined an array of strings, but in the former - especially to someone learning ruby - it doesn't seem as clear, at least for me.
If someone can tell me that I'm missing some key point here then please do, as I'm having a hard time understanding why the percent syntax appears to be preferred by the vast majority of ruby programmers.
One good use for general delimited input (as %w, %r, etc. are called) to avoid having to escape delimiters. This makes it especially good for literals with embedded delimiters. Contrast the regular expression
/^\/home\/[^\/]+\/.myprogram\/config$/
with
%r|^/home/[^/]+/.myprogram/config$|
or the string
"I thought John's dog was called \"Spot,\" not \"Fido.\""
with
%Q{I thought John's dog was called "Spot," not "Fido."}
As you read more Ruby, the meaning of general delimited input (%w, %r, &c.), as well as Ruby's other peculiarities and idioms, will become plain.
I believe that is no accident that Ruby often has several ways to do the same thing. Ruby, like Perl, appears to be a postmodern language: Minimalism is not a core values, but merely one of many competing design forces.
The %w syntax shaves 3 characters off each item in the list... can't beat that!
It's easy to remember: %w{} is for "words", %r{} for regexps, %q{} for "quotes", and so on... It's pretty easy once you build such memory aids.
As the size of the array grows, the %w syntax saves more and more keystrokes by not making you type in all the quotes and commas. At least that's the reason given in Learning Ruby.

Resources