Ruby ".Downcase! " and "Downcase" Confusion

Difference Between downcase and downcase! in Ruby

Methods with an exclamation mark at the end are often called bang-methods. A bang method doesn't necessarily modify its receiver as well as there is no guarantee that methods without a exclamation mark doesn't.

It's all very well explained in this blog post. To quote the post:

The ! in method names that end with !
means, “This method is dangerous”—or,
more precisely, this method is the
“dangerous” version of an otherwise
equivalent method, with the same name
minus the !. “Danger” is relative; the
! doesn’t mean anything at all unless
the method name it’s in corresponds to
a similar but bang-less method name.

and

The ! does not mean “This method
changes its receiver.” A lot of
“dangerous” methods do change their
receivers. But some don’t. I repeat: !
does not mean that the method changes
its receiver.

Ruby on Rails Tutorial -- strange uses of upcase/downcase and case-insensitivity

seems to me that by converting to upper case, and storing the data as lower case, you make sure they're not equivalent, so the "case_sensitive:false" part of the validator will really be tested.

Rails: What does this shorthand '.map(&:downcase)' mean?

It is the same as:

self.keywords = [title, author, description].map { |keyword| keyword.downcase }.join(' ')

has_key combined with .downcase isn't working properly

What you are experiencing is becuase you're calling String#downcase! and not String#downcase. If you run IRB and test this out you'll see:

> "TeSt".downcase!
=> "test"
> "test".downcase!
=> nil
> "TeSt".downcase
=> "test"
> "test".downcase
=> "test"

What happens here is that if the string is already lowercase then String#downcase! will return nil; however, the alternative String#downcase will always return a valid lowercase string even when the initial string is already lowercase. It's also important to note that String#downcase! modifies the string object referenced by the variable which may or may not be a desired result.

> s = "TeSt"
=> "TeSt"
> s.downcase!
=> "test"
> s
=> "test"

This is generally not what you'd like to do, instead you want to call the unmarked downcase which returns a new String object that represents the lowercase version of the string.

Downcase words except their first character

Advanced regular expressions: positive lookbehind

"My name is MARC".gsub(/(?<=\w)\w+/) { |s| s.downcase }
#=> "My name is Marc"

Even shorter (as suggested by @falsetru):

"My name is MARC".gsub /(?<=\w)\w+/, &:downcase
#=> "My name is Marc"

Why would downcase the key of has not work in this case?

map wants to do the operation on each pair and return 1 value.

When you use [] it is returning one value - an array. When you use k.downcase, v it can do the k.downcase part, but then it doesn't know what , v means. It's confused about trying to have a result of two things when it should be one. When those are inside the [] (array) brackets they are just elements of the one array that is returned.
`

Before validation method breaking spec with 'undefined method downcase'

As per the documentation exemplifies, you could use attribute_present? before:

class User < ApplicationRecord
before_validation :normalize_params, on: %i[create update]

validates :email, presence: true, uniqueness: true
validates :username, presence: true, uniqueness: true

private

def normalize_params
titleize_name
downcase_email
# You can any other here.
end

def titleize_name
self.name = name.downcase.titleize if attribute_present? 'name'
end

def downcase_email
self.email = email.downcase if attribute_present? 'email'
end
end

Note you can:

  • Use %i[] to create an array of symbols.
  • Validates presence and uniqueness by separating them by comma.
  • Prefer the is_expected.to than should syntax (it { is_expected.to validate_presence_of :attribute })
  • Separate each of your attribute modifications to easily work and include them.
  • Avoid using hash rocket when not needed. See ruby-style-guide#hash-literals.


Related Topics



Leave a reply



Submit