Ruby equivalent of PHP's ucfirst() function - ruby-on-rails

What's the best way in Ruby (with Rails, if relevant) to capitalize the first letter of a string?
Note that String#capitalize is not what I want since, in addition to capitalizing the first letter of the string, this function makes all other characters lowercase (which I don't want -- I'd like to leave them untouched):
>> "a A".capitalize
=> "A a"

In Rails you have the String#titleize method:
"testing string titleize method".titleize #=> "Testing String Titleize Method"

You can use "sub" to get what you want (note: I haven't tested this with multibyte strings)
"a A".sub(/^(\w)/) {|s| s.capitalize}
(and you can of course monkeypatch String to add this as a method if you like)

Upper case the first char, and save it back into the string
s = "a A"
s[0] = s[0,1].upcase
p s # => "A A"
Or,
class String
def ucfirst!
self[0] = self[0,1].upcase
self
end
end

If you don't want to modify the original string, you can do it this way:
class String
def ucfirst
str = self.clone
str[0] = str[0,1].upcase
str
end
end

I propose the following solution, works through whitespace
' ucfirstThis'.sub(/\w/, &:capitalize)
# => "UcfirstThis"

Since rails 5:
"a A".upcase_first
=> "A A"
http://api.rubyonrails.org/v5.1/classes/ActiveSupport/Inflector.html#method-i-upcase_first

If you are looking for a real similar function to PHPs ucfirst() try
"a A".gsub(/(\w+)/) {|s| s.capitalize}
will result in "A A".
"a neW APPROACH".gsub(/(\w+)/) {|s| s.capitalize}
will result in "A New Approach".
You can extend String class with:
class String
def ucfirst
self.gsub(/(\w+)/) { |s| s.capitalize }
end
def ucfirst!
self.gsub!(/(\w+)/) { |s| s.capitalize }
end
end

Have a look at this.
capitalizing-first-letter-of-each-word
There's not an inbuilt function. You need to split the letters and rejoin or try Rails' String#titleize and see if it does what you want.

That one liner does not depend on ActiveSupport. Not sure it's totally bulletproof though:
"my great uncle and grand-ma".gsub(/(\A\w|\s\w)/) { |m| m.upcase }
# My Great Uncle And Grand-ma

Related

Capitalize First Letter of all Words and Keep Already Capitalized

Using rails 4, and having trouble finding documentation on this. I would like to capitalize the first letter of each word in a string but keep already capitalized letters.
I would like the following outputs:
how far is McDonald's from here? => How Far Is McDonald's From Here?
MDMA is also known as molly => MDMA Is Also Known As Molly
i drive a BMW => I Drive A BMW
I thought .titleize would do it, but that will turn BMW into Bmw. Thank you for any help.
You can try the following:
a.split.map{|x| x.slice(0, 1).capitalize + x.slice(1..-1)}.join(' ')
# or
a.split.map{|x| x[0].upcase + x[1..-1]}.join(' ')
#=> ["MDMA Is Also Known As Molly",
"How Far Is McDonald's From Here?",
"I Drive A BMW"]
Demonstration
You can do a custom method like this:
string = "your string IS here"
output = []
string.split(' ').each do |word|
if word =~ /[A-Z]/
output << word
else
output << word.capitalize
end
end
output.join(' ')
Of course, this will not change a word like "tEST" or "tEst" because it has at least one capital letter in it.
to capitalize only the first letter while preserving existing capitalization:
your_string.then { |s| s[0].upcase + s[1..-1] }

Ruby (Rails) gsub: pass the captured string into a method

I'm trying to match a string as such:
text = "This is a #hastag"
raw(
h(text).gsub(/(?:\B#)(\w*[A-Z]+\w*)/i, embed_hashtag('\1'))
)
def embed_hashtag('data')
#... some code to turn the captured hashtag string into a link
#... return the variable that includes the final string
end
My problem is that when I pass '\1' in my embed_hashtag method that I call with gsub, it simply passes "\1" literally, rather than the first captured group from my regex. Is there an alternative?
FYI:
I'm wrapping text in h to escape strings, but then I'm embedding code into user inputted text (i.e. hashtags) which needs to be passed raw (hence raw).
It's important to keep the "#" symbol apart from the text, which is why I believe I need the capture group.
If you have a better way of doing this, don't hesitate to let me know, but I'd still like an answer for the sake of answering the question in case someone else has this question.
Use the block form gsub(regex){ $1 } instead of gsub(regex, '\1')
You can simplify the regex to /\B#(\w+)/i as well
You can leave out the h() helper, Rails 4 will escape malicious input by default
Specify method arguments as embed_hashtag(data) instead of embed_hashtag('data')
You need to define embed_hashtag before doing the substitution
To build a link, you can use link_to(text, url)
This should do the trick:
def embed_hashtag(tag)
url = 'http://example.com'
link_to tag, url
end
raw(
text.gsub(/\B#(\w+)/i){ embed_hashtag($1) }
)
The correct way would be the use of a block here.
Example:
def embed_hashtag(data)
puts "#{data}"
end
text = 'This is a #hashtag'
raw(
h(text).gsub(/\B#(\S+)/) { embed_hashtag($1) }
)
Try last match regexp shortcut:
=> 'zzzdzz'.gsub(/d/) { puts $~[0] }
=> 'd'
=> "zzzzz"

Ruby: Splitting string on last number character

I have the following method in my Ruby model:
Old:
def to_s
numbers = self.title.scan(/\d+/) if self.title.scan(/\d+/)
return numbers.join.insert(0, "#{self.title.chop} ") if numbers
"#{self.title.titlecase}"
end
New:
def to_s
numbers = self.title.scan(/\d+/)
return numbers.join.insert(0, "#{self.title.sub(/\d+/, '')} ") if numbers.any?
self.title.titlecase
end
A title can be like so: Level1 or TrackStar
So TrackStar should become Track Star and Level1 should be come Level 1, which is why I am doing the scan for numbers to begin with
I am trying to display it like Level 1. The above works, I was just curious to know if there was a more eloquent solution
Try this:
def to_s
self.title.split(/(?=[0-9])/, 2).join(" ")
end
The second argument to split is to make sure a title like "Level10" doesn't get transformed into "Level 1 0".
Edit - to add spaces between words as well, I'd use gsub:
def to_s
self.title.gsub(/([a-z])([A-Z])/, '\1 \2').split(/(?=\d)/, 2).join(" ")
end
Be sure to use single-quotes in the second argument to gsub.
How about this:
'Level1'.split(/(\d+)/).join(' ')
#=> "Level 1"

How do I convert a string to a class method?

This is how to convert a string to a class in Rails/Ruby:
p = "Post"
Kernel.const_get(p)
eval(p)
p.constantize
But what if I am retrieving a method from an array/active record object like:
Post.description
but it could be
Post.anything
where anything is a string like anything = "description".
This is helpful since I want to refactor a very large class and reduce lines of code and repetition. How can I make it work?
Post.send(anything)
While eval can be a useful tool for this sort of thing, and those from other backgrounds may take to using it as often as one might a can opener, it's actually dangerous to use so casually. Eval implies that anything can happen if you're not careful.
A safer method is this:
on_class = "Post"
on_class.constantize.send("method_name")
on_class.constantize.send("method_name", arg1)
Object#send will call whatever method you want. You can send either a Symbol or a String and provided the method isn't private or protected, should work.
Since this is taged as a Ruby on Rails question, I'll elaborate just a little.
In Rails 3, assuming title is the name of a field on an ActiveRecord object, then the following is also valid:
#post = Post.new
method = "title"
#post.send(method) # => #post.title
#post.send("#{method}=","New Name") # => #post.title = "New Name"
Try this:
class Test
def method_missing(id, *args)
puts "#{id} - get your method name"
puts "#{args} - get values"
end
end
a = Test.new
a.name('123')
So the general syntax would be a.<anything>(<any argument>).

Strip method for non-whitespace characters?

Is there a Ruby/Rails function that will strip a string of a certain user-defined character? For example if I wanted to strip my string of quotation marks "... text... "
http://api.rubyonrails.org/classes/ActiveSupport/Multibyte/Chars.html#M000942
I don't know if I'm reinventing the wheel here so if you find a built-in method that does the same, please let me know :-)
I added the following to config/initializers/string.rb , which add the trim, ltrim and rtrim methods to the String class.
# in config/initializers/string.rb
class String
def trim(str=nil)
return self.ltrim(str).rtrim(str)
end
def ltrim(str=nil)
if (!str)
return self.lstrip
else
escape = Regexp.escape(str)
end
return self.gsub(/^#{escape}+/, "")
end
def rtrim(str=nil)
if (!str)
return self.rstrip
else
escape = Regexp.escape(str)
end
return self.gsub(/#{escape}+$/, "")
end
end
and I use it like this:
"... hello ...".trim(".") => " hello "
and
"\"hello\"".trim("\"") => "hello"
I hope this helps :-)
You can use tr with the second argument as a blank string. For example:
%("... text... ").tr('"', '')
would remove all the double quotes.
Although if you are using this function to sanitize your input or output then it will probably not be effective at preventing SQL injection or Cross Site Scripting attacks. For HTML you are better off using the gem sanitize or the view helper function h.
I don't know of one out of the box, but this should do what you want:
class String
def strip_str(str)
gsub(/^#{str}|#{str}$/, '')
end
end
a = '"Hey, there are some extraneous quotes in this here "String"."'
puts a.strip_str('"') # -> Hey, there are some extraneous quotes in this here "String".
You could use String#gsub:
%("... text... ").gsub(/\A"+|"+\Z/,'')
class String
# Treats str as array of char
def stripc(str)
out = self.dup
while str.each_byte.any?{|c| c == out[0]}
out.slice! 0
end
while str.each_byte.any?{|c| c == out[-1]}
out.slice! -1
end
out
end
end
Chuck's answer needs some + signs if you want to remove all extra instances of his string pattern. And it doesn't work if you want to remove any of a set of characters that might appear in any order.
For instance, if we want a string to not end with any of the following: a, b, c, and our string is fooabacab, we need something stronger like the code I've supplied above.

Resources