are there different sensitivities/settings to whitespace in ruby?
i have a RoR project, where an active record call has a lot of components:
max_stuff = FooSummary.select("max(stuff) as stuff")
.joins(:foo => :bar)
.where("user_id = ? and record_date < ?", r.user_id, r.record_date)
.group("user_id")
.first
1.9.3 works fine with this on my mac, but on the ubuntu server it runs on, it complains about the fact that .joins is on a separate line (unexpected . expecting kEND)
what gives?
This syntax was introduced in Ruby 1.9.1:
Language core changes
New syntax and semantics
…
Newlines allowed before ternary colon operator (:) and method call dot operator (.)
Most likely your server is running an older Ruby version, i.e. 1.9.0 or 1.8.x.
Move the period to the preceding line. If parsing line-by-line,
foo = bar
looks like a full statement, and the next line, taken separately, is a syntax error:
.baz
However, this can't be a statement:
foo = bar.
and the parser knows it has to append the next line as well:
baz
(which gives the same parse as foo = bar.baz, as expected).
Maybe
max_stuff = FooSummary.select("max(stuff) as stuff") \
.joins(:foo => :bar) \
.where("user_id = ? and record_date < ?", r.user_id, r.record_date) \
.group("user_id") \
.first
You can also try various combinations of the following, where either ( ends the line, or ) begins the line. Here I am showing both, and you can adjust to your liking.
max_stuff = FooSummary.select(
"max(stuff) as stuff"
).joins(
:foo => :bar
).where(
"user_id = ? and record_date < ?", r.user_id, r.record_date
).group(
"user_id"
).first
Put dottes on the end of lines
max_stuff = FooSummary.select("max(stuff) as stuff").
joins(:foo => :bar).
where("user_id = ? and record_date < ?", r.user_id, r.record_date).
group("user_id").
first
Related
I see that strip! and chomp! (and other similar methods) return nil when the string is not altered. This apparently forbids combining these methods in one line:
s = 'a' # => "a"
s.strip!.chomp!(',')
# => NoMethodError: undefined method `chomp!' for nil:NilClass
So I seem to be forced to write one per line:
s.strip! # => nil
s.chomp!(',') # => nil
Is this the only way or am I missing something?
You could use the non-mutating versions of those methods:
s = s.strip.chomp(',')
You could use a semicolon (but that would usually be poor taste):
s.strip!; s.chomp!(',')
This looks like a case where tap could be a useful tool:
s.tap {|t| t.strip!}.chomp!
R = /
^\s+ # match >= 1 whitespace at the beginning of string
| # or
,\s*$ # match comma then >= 0 whitespace at the end of the line
| # or
\s+$ # match >= 1 whitespace at the end of the line
/x
def clean(s)
s.gsub!(R,'') || s
end
In all of the following, the return value is "ab", which is also the new value of the string:
clean ' ab '
clean ' ab,'
clean ' ab, '
clean 'ab,'
clean 'ab'
I would like to compose regexps, that is reusing a regex in a new regex.
Is that possible in Ruby ?
For instance, in order to simplify this assembly-like parsing :
LABELED_INSTR = /(\w+):(movi|addi)\s+(\w+),(\w+),(w+)/
NON_LABELED_INSTR = /(movi|addi)\s+(\w+),(\w+),(w+)/
I would like to resort to :
IMMEDIATE = /(movi|addi)/
But then I don't know how to share this regex in the two previous ones.
Any hint ?
Sure, regular expressions can be reused (or composed) within other regexes. Here's an example that combines two regexes to make a third:
>> a = /boo/
=> boo
>> b = /foo/
=> foo
>> c = /#{a}|#{b}/
=> -mix:boo-mix:foo
>> if "boo" =~ c
>> puts "match!"
>> end
match!
=> nil
Your example is pretty similar. Here, it would be:
IMMEDIATE = /(movi|addi)/
LABELED_INSTR = /(\w+):#{IMMEDIATE}\s+(\w+),(\w+),(w+)/
NON_LABELED_INSTR = /#{IMMEDIATE}\s+(\w+),(\w+),(w+)/
You can also use strings:
IMMEDIATE = "(movi)|(addi)"
LABELED_INSTR = Regexp.new("(\\w+):#{IMMEDIATE}\\s+(\\w+),(\\w+),(w+)/")
NON_LABELED_INSTR = Regexp.new(IMMEDIATE + "\\s+(\\w+),(\\w+),(w+)/")
notice you must escape the inverted slashes.
I want to replace the last occurrence of a substring in Ruby. What's the easiest way?
For example, in abc123abc123, I want to replace the last abc to ABC. How do I do that?
How about
new_str = old_str.reverse.sub(pattern.reverse, replacement.reverse).reverse
For instance:
irb(main):001:0> old_str = "abc123abc123"
=> "abc123abc123"
irb(main):002:0> pattern="abc"
=> "abc"
irb(main):003:0> replacement="ABC"
=> "ABC"
irb(main):004:0> new_str = old_str.reverse.sub(pattern.reverse, replacement.reverse).reverse
=> "abc123ABC123"
"abc123abc123".gsub(/(.*(abc.*)*)(abc)(.*)/, '\1ABC\4')
#=> "abc123ABC123"
But probably there is a better way...
Edit:
...which Chris kindly provided in the comment below.
So, as * is a greedy operator, the following is enough:
"abc123abc123".gsub(/(.*)(abc)(.*)/, '\1ABC\3')
#=> "abc123ABC123"
Edit2:
There is also a solution which neatly illustrates parallel array assignment in Ruby:
*a, b = "abc123abc123".split('abc', -1)
a.join('abc')+'ABC'+b
#=> "abc123ABC123"
Since Ruby 2.0 we can use \K which removes any text matched before it from the returned match. Combine with a greedy operator and you get this:
'abc123abc123'.sub(/.*\Kabc/, 'ABC')
#=> "abc123ABC123"
This is about 1.4 times faster than using capturing groups as Hirurg103 suggested, but that speed comes at the cost of lowering readability by using a lesser-known pattern.
more info on \K: https://www.regular-expressions.info/keep.html
Here's another possible solution:
>> s = "abc123abc123"
=> "abc123abc123"
>> s[s.rindex('abc')...(s.rindex('abc') + 'abc'.length)] = "ABC"
=> "ABC"
>> s
=> "abc123ABC123"
When searching in huge streams of data, using reverse will definitively* lead to performance issues. I use string.rpartition*:
sub_or_pattern = "!"
replacement = "?"
string = "hello!hello!hello"
array_of_pieces = string.rpartition sub_or_pattern
( array_of_pieces[(array_of_pieces.find_index sub_or_pattern)] = replacement ) rescue nil
p array_of_pieces.join
# "hello!hello?hello"
The same code must work with a string with no occurrences of sub_or_pattern:
string = "hello_hello_hello"
# ...
# "hello_hello_hello"
*rpartition uses rb_str_subseq() internally. I didn't check if that function returns a copy of the string, but I think it preserves the chunk of memory used by that part of the string. reverse uses rb_enc_cr_str_copy_for_substr(), which suggests that copies are done all the time -- although maybe in the future a smarter String class may be implemented (having a flag reversed set to true, and having all of its functions operating backwards when that is set), as of now, it is inefficient.
Moreover, Regex patterns can't be simply reversed. The question only asks for replacing the last occurrence of a sub-string, so, that's OK, but readers in the need of something more robust won't benefit from the most voted answer (as of this writing)
You can achieve this with String#sub and greedy regexp .* like this:
'abc123abc123'.sub(/(.*)abc/, '\1ABC')
simple and efficient:
s = "abc123abc123abc"
p = "123"
s.slice!(s.rindex(p), p.size)
s == "abc123abcabc"
string = "abc123abc123"
pattern = /abc/
replacement = "ABC"
matches = string.scan(pattern).length
index = 0
string.gsub(pattern) do |match|
index += 1
index == matches ? replacement : match
end
#=> abc123ABC123
I've used this handy helper method quite a bit:
def gsub_last(str, source, target)
return str unless str.include?(source)
top, middle, bottom = str.rpartition(source)
"#{top}#{target}#{bottom}"
end
If you want to make it more Rails-y, extend it on the String class itself:
class String
def gsub_last(source, target)
return self unless self.include?(source)
top, middle, bottom = self.rpartition(source)
"#{top}#{target}#{bottom}"
end
end
Then you can just call it directly on any String instance, eg "fooBAR123BAR".gsub_last("BAR", "FOO") == "fooBAR123FOO"
.gsub /abc(?=[^abc]*$)/, 'ABC'
Matches a "abc" and then asserts ((?=) is positive lookahead) that no other characters up to the end of the string are "abc".
How can I get the first character in a string using Ruby?
Ultimately what I'm doing is taking someone's last name and just creating an initial out of it.
So if the string was "Smith" I just want "S".
You can use Ruby's open classes to make your code much more readable. For instance, this:
class String
def initial
self[0,1]
end
end
will allow you to use the initial method on any string. So if you have the following variables:
last_name = "Smith"
first_name = "John"
Then you can get the initials very cleanly and readably:
puts first_name.initial # prints J
puts last_name.initial # prints S
The other method mentioned here doesn't work on Ruby 1.8 (not that you should be using 1.8 anymore anyway!--but when this answer was posted it was still quite common):
puts 'Smith'[0] # prints 83
Of course, if you're not doing it on a regular basis, then defining the method might be overkill, and you could just do it directly:
puts last_name[0,1]
If you use a recent version of Ruby (1.9.0 or later), the following should work:
'Smith'[0] # => 'S'
If you use either 1.9.0+ or 1.8.7, the following should work:
'Smith'.chars.first # => 'S'
If you use a version older than 1.8.7, this should work:
'Smith'.split(//).first # => 'S'
Note that 'Smith'[0,1] does not work on 1.8, it will not give you the first character, it will only give you the first byte.
"Smith"[0..0]
works in both ruby 1.8 and ruby 1.9.
For completeness sake, since Ruby 1.9 String#chr returns the first character of a string. Its still available in 2.0 and 2.1.
"Smith".chr #=> "S"
http://ruby-doc.org/core-1.9.3/String.html#method-i-chr
In MRI 1.8.7 or greater:
'foobarbaz'.each_char.first
Try this:
>> a = "Smith"
>> a[0]
=> "S"
OR
>> "Smith".chr
#=> "S"
In Rails
name = 'Smith'
name.first
>> s = 'Smith'
=> "Smith"
>> s[0]
=> "S"
Another option that hasn't been mentioned yet:
> "Smith".slice(0)
#=> "S"
Because of an annoying design choice in Ruby before 1.9 — some_string[0] returns the character code of the first character — the most portable way to write this is some_string[0,1], which tells it to get a substring at index 0 that's 1 character long.
Try this:
def word(string, num)
string = 'Smith'
string[0..(num-1)]
end
If you're using Rails You can also use truncate
> 'Smith'.truncate(1, omission: '')
#=> "S"
or for additional formatting:
> 'Smith'.truncate(4)
#=> "S..."
> 'Smith'.truncate(2, omission: '.')
#=> "S."
While this is definitely overkill for the original question, for a pure ruby solution, here is how truncate is implemented in rails
# File activesupport/lib/active_support/core_ext/string/filters.rb, line 66
def truncate(truncate_at, options = {})
return dup unless length > truncate_at
omission = options[:omission] || "..."
length_with_room_for_omission = truncate_at - omission.length
stop = if options[:separator]
rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
else
length_with_room_for_omission
end
"#{self[0, stop]}#{omission}"
end
Other way around would be using the chars for a string:
def abbrev_name
first_name.chars.first.capitalize + '.' + ' ' + last_name
end
Any of these methods will work:
name = 'Smith'
puts name.[0..0] # => S
puts name.[0] # => S
puts name.[0,1] # => S
puts name.[0].chr # => S
This is what I have now - which looks too verbose for the work it is doing.
#title = tokens[Title].strip! || tokens[Title] if !tokens[Title].nil?
Assume tokens is a array obtained by splitting a CSV line.
now the functions like strip! chomp! et. all return nil if the string was not modified
"abc".strip! # => nil
" abc ".strip! # => "abc"
What is the Ruby way to say trim it if it contains extra leading or trailing spaces without creating copies?
Gets uglier if I want to do tokens[Title].chomp!.strip!
I guess what you want is:
#title = tokens[Title]
#title.strip!
The #strip! method will return nil if it didn't strip anything, and the variable itself if it was stripped.
According to Ruby standards, a method suffixed with an exclamation mark changes the variable in place.
Update: This is output from irb to demonstrate:
>> #title = "abc"
=> "abc"
>> #title.strip!
=> nil
>> #title
=> "abc"
>> #title = " abc "
=> " abc "
>> #title.strip!
=> "abc"
>> #title
=> "abc"
Btw, now ruby already supports just strip without "!".
Compare:
p "abc".strip! == " abc ".strip! # false, because "abc".strip! will return nil
p "abc".strip == " abc ".strip # true
Also it's impossible to strip without duplicates. See sources in string.c:
static VALUE
rb_str_strip(VALUE str)
{
str = rb_str_dup(str);
rb_str_strip_bang(str);
return str;
}
ruby 1.9.3p0 (2011-10-30) [i386-mingw32]
Update 1:
As I see now -- it was created in 1999 year (see rev #372 in SVN):
Update2:
strip! will not create duplicates — both in 1.9.x, 2.x and trunk versions.
There's no need to both strip and chomp as strip will also remove trailing carriage returns - unless you've changed the default record separator and that's what you're chomping.
Olly's answer already has the canonical way of doing this in Ruby, though if you find yourself doing this a lot you could always define a method for it:
def strip_or_self!(str)
str.strip! || str
end
Giving:
#title = strip_or_self!(tokens[Title]) if tokens[Title]
Also keep in mind that the if statement will prevent #title from being assigned if the token is nil, which will result in it keeping its previous value. If you want or don't mind #title always being assigned you can move the check into the method and further reduce duplication:
def strip_or_self!(str)
str.strip! || str if str
end
As an alternative, if you're feeling adventurous you can define a method on String itself:
class String
def strip_or_self!
strip! || self
end
end
Giving one of:
#title = tokens[Title].strip_or_self! if tokens[Title]
#title = tokens[Title] && tokens[Title].strip_or_self!
If you are using Ruby on Rails there is a squish
> #title = " abc "
=> " abc "
> #title.squish
=> "abc"
> #title
=> " abc "
> #title.squish!
=> "abc"
> #title
=> "abc"
If you are using just Ruby you want to use strip
Herein lies the gotcha.. in your case you want to use strip without the bang !
while strip! certainly does return nil if there was no action it still updates the variable so strip! cannot be used inline. If you want to use strip inline you can use the version without the bang !
strip! using multi line approach
> tokens["Title"] = " abc "
=> " abc "
> tokens["Title"].strip!
=> "abc"
> #title = tokens["Title"]
=> "abc"
strip single line approach... YOUR ANSWER
> tokens["Title"] = " abc "
=> " abc "
> #title = tokens["Title"].strip if tokens["Title"].present?
=> "abc"
If you want to use another method after you need something like this:
( str.strip || str ).split(',')
This way you can strip and still do something after :)
I think your example is a sensible approach, although you could simplify it slightly as:
#title = tokens[Title].strip! || tokens[Title] if tokens[Title]
Alternative you could put it on two lines:
#title = tokens[Title] || ''
#title.strip!
If you have either ruby 1.9 or activesupport, you can do simply
#title = tokens[Title].try :tap, &:strip!
This is really cool, as it leverages the :try and the :tap method, which are the most powerful functional constructs in ruby, in my opinion.
An even cuter form, passing functions as symbols altogether:
#title = tokens[Title].send :try, :tap, &:strip!
My way:
> (#title = " abc ").strip!
=> "abc"
> #title
=> "abc"
#title = tokens[Title].strip! || tokens[Title]
It's entirely possible i'm not understanding the topic, but wouldn't this do what you need?
" success ".strip! || "rescue" #=> "success"
"failure".strip! || "rescue" #=> "rescue"