Is there and way to write code like this in a way that makes what it does clearer?
a = (a.split(" ")[1..-1]).join(" ")
That deletes the first word of a sentence but the code doesn't look expressive at all.
irb(main):024:0> "this is a test".split.drop(1) * " "
=> "is a test"
Edited to add:
Explanation:
By default #split delimits on whitespace.
#drop(1) gets rid of the first entry.
* " " does the same as #join(" ").
for somebody who is used to reading rexep this is pretty clean:
a = a.sub(/^\S+\s/, "")
ymmv
code
a = a.split[1..-1] * " "
explanation
String#split's default parameter is " "
Array * String is an alias for Array.join(String)
On second thought, I'm not sure if it's more transparent to someone who is not familiar with ruby, per se. But anyone who has worked with Ruby strings for a little bit will understand what's going on. And it's a lot more clean than the original version.
UPDATE
As per just-my-correct-opinion's answer (which you all should vote up instead of mine), if you are running Ruby 1.9.1 (which you should be, anyway) or Ruby 1.8.7, you can do:
a = a.split.drop(1) * " "
maybe making the process explicit will help
words = a.split
words.pop
a = words.join " "
And if you were using this throughout some code you might want to create the
methods in String and Array to make your code readable. (works in 1.8.6 too)
class String
def words
split
end
end
class Array
def but_first
self[1..-1]
end
def to_sentence
join(' ')
end
end
str = "And, this is a sentence"
puts str.words.but_first.to_sentence
Something like following
a = a[a.index(' '), a.length-(a.index(' ')+1)]
No check though
Related
I am attempting to make a console based calculator to practice some Ruby, I am using the 'case' statement to check the consoles arguments then use Ruby's arithmetic to interpret and return the result.
The issue I am having is that I cannot get Ruby to execute the line associated with the Multiplication. It simply goes to the 'else' block and executes my help method. I have all other methods except the Exponent I assume Ruby is treating the STAR characters as 'Everything' (I am not sure how to word that)
case #args[1]
when '+'
puts "#{#args[0].to_i + #args[2].to_i}"
when '-'
puts "#{#args[0].to_i - #args[2].to_i}"
when '*'
puts "#{#args[0].to_i * #args[2].to_i}"
when '/'
puts "#{#args[0].to_i / #args[2].to_i}"
when '%'
puts "#{#args[0].to_i % #args[2].to_i}"
when '**'
puts "#{#args[0].to_i**#args[2].to_i}"
else
help
end
I know it looks dodgy, bare in mind I plan on fixing it up once I have everything working.
I am fairly new to Ruby so I am not 100% sure on what I need to do to have Ruby treat these as simple stars and not Regular Expressions...
I assure you this is not homework, I am simply trying to learn some Ruby as I have also recently started learning Rails.
Did you try escaping the asterisk by writing '\*'?
There's something else going on. This irb session confirms that strings in case statements work the way you expect:
str = '*'
=> "*"
>> case str
>> when '*' then "foo"
>> end
=> "foo"
Double check that #args[1] actually is what you think it is.
Is there a method (perhaps in some library from Rails) or an easy way that capitalizes the first letter of a string without affecting the upper/lower case status of the rest of the string? I want to use it to capitalize error messages. I expect something like this:
"hello iPad" #=> "Hello iPad"
There is a capitalize method in Ruby, but it will downcase the rest of the string. You can write your own otherwise:
class String
def capitalize_first
(slice(0) || '').upcase + (slice(1..-1) || '')
end
def capitalize_first!
replace(capitalize_first)
end
end
Edit: Added capitalize_first! variant.
Rather clumsy, but it works:
str = "hello IiPad"
str[0] = str[0].upcase #or .capitalize
Thanks to other answers, I realized some points that I need to be aware of, and also that there is no built in way. I looked into the source of camelize in Active Support of Rails as hinted by Vitaly Zemlyansky, which gave me a hint: that is to use a regex. I decided to use this:
sub(/./){$&.upcase}
Try this
"hello iPad".camelize
I'd like to switch the extension of a file. For example:
test_dir/test_file.jpg to .txt should give test_dir/test_file.txt.
I also want the solution to work on a file with two extensions.
test_dir/test_file.ext1.jpg to .txt should should give test_dir/test_file.ext1.txt
Similarly, on a file with no extension it should just add the extension.
test_dir/test_file to .txt should give test_dir/test_file.txt
I feel like this should be simple, but I haven't found a simple solution. Here is what I have right now. I think it is really ugly, but it does seem to work.
def switch_ext(f, new_ext)
File.join(File.dirname(f), File.basename(f, File.extname(f))) + new_ext
end
Do you have any more elegant ways to do this? I've looked on the internet, but I'm guessing that I'm missing something obvious. Are there any gotcha's to be aware of? I prefer a solution that doesn't use a regular expression.
Your example method isn't that ugly. Please do continue to use file naming semantic aware methods over string regexp. You could try the Pathname stdlib which might make it a little cleaner:
require 'pathname'
def switch_ext(f, new_ext)
p = Pathname.new f
p.dirname + "#{ p.basename('.*') }#{ new_ext }"
end
>> puts %w{ test_dir/test_file.jpg test_dir/test_file.ext1.jpg testfile .vimrc }.
| map{|f| switch_ext f, '.txt' }
test_dir/test_file.txt
test_dir/test_file.ext1.txt
testfile.txt
.vimrc.txt
def switch_ext(f, new_ext)
(n = f.rindex('.')) == 0 ? nil : (f[0..n] + new_ext)
end
It will find the most right occurrence of '.' if it is not the first character.
Regular expressions were invented for this sort of task.
def switch_ext f, new_ext
f.sub(/((?<!\A)\.[^.]+)?\Z/, new_ext)
end
puts switch_ext 'test_dir/test_file.jpg', '.txt'
puts switch_ext 'test_dir/test_file.ext1.jpg', '.txt'
puts switch_ext 'testfile', '.txt'
puts switch_ext '.vimrc', '.txt'
Output:
test_dir/test_file.txt
test_dir/test_file.ext1.txt
testfile.txt
.vimrc.txt
def switch_ext(filename, new_ext)
filename.chomp( File.extname(filename)) + new_ext
end
I just found this answer to my own question here at the bottom of this long discussion.
http://www.ruby-forum.com/topic/179524
I personally think it is the best one I've seen. I definitely want to avoid a regular expression, because they are hard for me to remember and therefore error prone.
For dotfiles this function just adds the extension onto the file. This behaviour seems sensible to me.
switch_ext('.vimrc', '.txt') # => ".vimrc.txt"
Please continue to post better answers if there are any, and post comments to let me know if you see any deficiencies in this answer. I'll leave the question open for now.
You can use regular expressions, or you can use things like the built-in filename manipulation tools in File:
%w[
test_dir/test_file.jpg
test_dir/test_file.ext1.jpg
test_dir/test_file
].each do |fn|
puts File.join(
File.dirname(fn),
File.basename(fn, File.extname(fn)) + '.txt'
)
end
Which outputs:
test_dir/test_file.txt
test_dir/test_file.ext1.txt
test_dir/test_file.txt
I personally use the File methods. They're aware of different OS's needs for filename separators so porting to another OS is a no brainer. In your use-case it's not a big deal. Mix in path manipulations and it becomes more important.
def switch_ext f, new_ext
"#{f.sub(/\.[^.]+\z/, "")}.#{new_ext}"
end
def switch_ext(filename, ext)
begin
filename[/\.\w+$/] = ext
rescue
filename << ext
end
filename
end
Usage
>> switch_ext('test_dir/test_file.jpeg', '.txt')
=> "test_dir/test_file.txt"
>> switch_ext('test_dir/no_ext_file', '.txt')
=> "test_dir/no_ext_file.txt"
Hope this help.
Since Ruby 1.9.1 the easiest answer is Pathname::sub_ext(replacement) which strips off the extension and replaces it with the given replacement (which can be an empty string ''):
Pathname.new('test_dir/test_file.jpg').sub_ext('.txt')
=> #<Pathname:test_dir/test_file.txt>
Pathname.new('test_dir/test_file.ext1.jpg').sub_ext('.txt')
=> #<Pathname:test_dir/test_file.ext1.txt>
Pathname.new('test_dir/test_file').sub_ext('.txt')
=> #<Pathname:test_dir/test_file.txt>
Pathname.new('test_dir/test_file.txt').sub_ext('')
=> #<Pathname:test_dir/test_file>
One thing to watch out for is that you need to have a leading . in the replacement:
Pathname.new('test_dir/test_file.jpg').sub_ext('txt')
=> #<Pathname:test_dir/test_filetxt>
Just trying to write a simple Ruby program here. I'm trying to get the program to ask for the user's favorite number and then suggest a new favorite number that's one greater. What's wrong with the code below?
puts "hey, whats your favorite number?"
favnumber = gets.chomp
newfavnumber = favnumber.to_i + 1
puts "how about " + newfavnumber "?"
puts "how about " + newfavnumber "?"
First of all, you probably wanted a + before the "?" there. The way this is written now, it parses as puts("how about " + newfavnumber("?")), i.e. you're calling a function called newfavnumber, which is obviously not what you want.
However if you change it to puts "how about " + newfavnumber + "?", which you presumably intended, it still won't work: newfavnumber is a number and "how about " is a string. In ruby you can't add numbers to strings. To fix this you can call to_s on newfavnumber to convert it to a string.
A better way to write this would be using string interpolation: puts "how about #{newfavnumber}?". This way you don't need to call to_s because you can use any type inside #{}.
You're missing a + after newfavnumber and a conversion to string.
puts "how about " + newfavnumber.to_s + "?"
Let us imagine, that we have a simple abstract input form, whose aim is accepting some string, which could consist of any characters.
string = "mystical characters"
We need to process this string by making first character uppercased. Yes, that is our main goal. Thereafter we need to display this converted string in some abstract view template. So, the question is: do we really need to check whether the first character is already written correctly (uppercased) or we are able to write just this?
theresult = string.capitalize
=> "Mystical characters"
Which approach is better: check and then capitalize (if need) or force capitalization?
Check first if you need to process something, because String#capitalize doesn't only convert the first character to uppercase, but it also converts all other characters downcase. So..
"First Lastname".capitalize == "First lastname"
That might not be the wanted result.
If I understood correctly you are going to capitalize the string anyway, so why bother checking if it's already capitalized?
Based on Tonttu answer I would suggest not to worry too much and just capitalize like this:
new_string = string[0...1].capitalize + string[1..-1]
I ran in to Tonttu's problem importing a bunch of names, I went with:
strs = "first lastname".split(" ")
return_string = ""
strs.each do |str|
return_string += "#{str[0].upcase}#{str[1..str.length].downcase} "
end
return_string.chop
EDIT: The inevitable refactor (over a year) later.
"first lastname".split(" ").map do |str|
"#{str[0].upcase}#{str[1..str.length].downcase}"
end.join(' ')
while definitely not easier to read, it gets the same result while declaring fewer temporary variables.
I guess you could write something like:
string.capitalize unless string =~ /^[A-Z].*/
Personally I would just do string.capitalize
Unless you have a flag to be set for capitalized strings which you going to check than just capitalize without checking.
Also the capitalization itself is probably performing some checking.