Open a file case-insensitively in Ruby under Linux
One approach would be to write a little method to build a case insensitive glob for a given filename:
def ci_glob(filename)
glob = ''
filename.each_char do |c|
glob += c.downcase != c.upcase ? "[#{c.downcase}#{c.upcase}]" : c
end
glob
end
irb(main):024:0> ci_glob('foo.txt')
=> "[fF][oO][oO].[tT][xX][tT]"
and then you can do:
filename = Dir.glob(ci_glob('foo.txt')).first
Alternatively, you can write the directory search you suggested quite concisely. e.g.
filename = Dir.glob('*').find { |f| f.downcase == 'foo.txt' }
Prior to Ruby 3.1 it was possible to use the FNM_CASEFOLD
option to make glob
case insensitive e.g.
filename = Dir.glob('foo.txt', File::FNM_CASEFOLD).first
if filename
# use filename here
else
# no matching file
end
The documentation suggested FNM_CASEFOLD
couldn't be used with glob but it did actually work in older Ruby versions. However, as mentioned by lildude in the comments, the behaviour has now been brought inline with the documentation and so this approach shouldn't be used.
In Ruby, how can I interpret (expand) a glob relative to a directory?
If I were implementing that behaviour, I would go with filtering an array, returned by Dir#entries
:
Dir.entries("#{target}").select { |f| f =~ /\A#{filename}\z/i }
Please be aware that on unix platform both .
and ..
entries will be listed as well, but they are unlikely to be matched on the second step. Also, probably the filename should be escaped with Regexp.escape
:
Dir.entries("#{target}").select { |f| f =~ /\A#{Regexp.escape(filename)}\z/i }
case insensitive name, while preserving capitalization, in Devise
What you might try is to not set :name
as case insensitive, which will properly save the case-sensitive name in the database:
config.case_insensitive_keys = []
Then, override the find_first_by_auth_conditions
class method on User to find the user by their name. Note that this code will vary depending on the database (below is using Postgres):
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where("lower(name) = ?", login.downcase).first
else
where(conditions).first
end
end
Doing this, a User.find_for_authentication(login: 'thefourthmusketeer')
will properly return the record with a name
of "TheFourthMusketeer".
See https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address for an explanation of overriding this method.
How to do case-insensitive order in Rails with postgresql
result = Users.find(:all, :order => "LOWER(name)")
To take a little bit from both Brad and Frank.
A lot of warnings after require 'Time'
There is no Time
library in Ruby. There is, however, a time
library.
It looks like you are using a case-insensitive file system, so when you require 'Time'
, the Operating System will "lie" to Ruby and tell it that Time.rb
actually exists, even though there is really only a time.rb
. (The OS will say the same thing about TIME.RB
or tImE.rB
or TiMe.Rb
or …)
Therefore, Ruby will load Time.rb
(which is really time.rb
). However, internally, the time
library will of course use require 'time'
everywhere. Now, Ruby detects when a file has already been loaded and will just ignore it, BUT Time.rb
and time.rb
are two different file names, so Ruby will naturally load them both.
Since they are the same file, though, everything in time.rb
will get executed twice, which means that you will get a warning for every single constant definition and every single method definition in that file.
The solution is simple: use require 'time'
because that's the name of the library's entry file.
The alternative would be to use a case-sensitive file system, in which case you would simply get a LoadError
exception telling you that there is no file named Time.rb
.
cannot load such file -- Kconv
The name of the file is kconv.rb
, not Kconv.rb
. On your Mac, you are presumably using a case-insensitive file system such as FAT, NTFS or HFS, whereas on your CentOS box, you are using a case-sensitive file system such as ext4, btrfs or ZFS.
So, it should be
require 'kconv'
and the fact that
require 'Kconv'
works on a case-insensitive file system is just pure dumb luck.
Related Topics
Generate String for Regex Pattern in Ruby
After Ruby 2.4 Upgrade - Error While Trying to Load The Gem 'Uglifier' (Bundler::Gemrequireerror)
How to Do a Before_Action in Ruby (Like in Rails)
How to Calculate Next, Previous Business Day in Rails
How to Use Your Own MySQL Database Server with Heroku
Ruby/Rails Collection to Collection
What's The Impact of Eager_Load=True
Ruby No Implicit Conversion of Fixnum into String (Typeerror)
How Does One Downgrade Jekyll to Work with Github Pages
Capturing Logger Output Inside a Method
More Efficient Ruby Way to Map Attribute in Array of Objects to Another Array
What Are Some Examples of Using Nokogiri
How to Read from Redis Inside a Multi Block in Ruby
What's the Easiest Way to Send a Message Through Outlook with Ruby
Why Is Rack Response Body an Array Not a String
Fresh Install of Rvm in Ubuntu Isn't Letting Me Install Gems (Zlib Error)