What params on string block (<<-BLOCK, param1, param2) means? - ruby-on-rails

I'm reading some source code at https://github.com/plataformatec/devise and found that line of code:
class_eval <<-URL_HELPERS, __FILE__, __LINE__ + 1
What the params __FILE__ and __LINE__ + 1 does in block declaration (what changes in relation of a string block without these params)?
https://github.com/plataformatec/devise/blob/master/lib/devise/controllers/url_helpers.rb#L47
Thank

Those params belong to the class_eval method, not to the here document. It's common practice to ensure that error, which can raise the evaled code, will be shown with a reference to the current file and with correct line number.

By way of an alternative example showing how HEREDOCs work, the other day in IRB I wrote:
require 'nokogiri'
doc = Nokogiri.XML(<<ENDXML,&:noblanks)
...gobs and gobs of pasted xml...
ENDXML
Even crazier is this legal syntax for passing multiple HEREDOC strings at once:
p( <<END1, <<-END2, <<END3 )
This indented text is part of
the first parameter, END1
END1
And this text is part of param2
whose ending sigil may be indented
END2
and finally this text
is part of
the third parameter
END3
#=> " This indented text is part of\n the first parameter, END1\n"
#=> "And this text is part of param2\n whose ending sigil may be indented\n"
#=> "and finally this text\nis part of\nthe third parameter\n"

Related

How to use gsub twice?

I need to perform to search and replace activity
"{{content}}" => replace. (this to keep same type) regex gsub(/"{{(.*?)}}"/)
"hello {{content}}" => repalce (this to replace from string) regex gsub(/{{(.*?)}}/)
Method that i build is
def fill_in(template)
template.gsub(/\"\{\{(.*?)\}\}\"/) do
"test"
end
end
Tried template.gsub(/\"\{\{(.*?)\}\}\"/).gsub(/\{\{(.*?)\}\}/) do but this is giving
me error
undefined method `gsub' for #<Enumerator:
"{{user_name}}":gsub(/"{{(.*?)}}"/)>
first gsub is priority if it matches that pattern replace based on then if not check for second gsub
template.gsub(/\"\{\{(.*?)\}\}\"/) do
# content will be replaced from the data object
end.gsub(/\"\{\{(.*?)\}\}\"/) do
# content will be replaced from the data object
end
do body for both gsub is same, how to stop this repetition
The gsub with just a regex as a single argument to return an Enumerator, so you won't be able to chain the gsub in this way.
You can combine the two patterns into one:
/(")?\{\{(.*?)\}\}(?(1)"|)/
See the regex demo. Details:
(")? - Capturing group 1 (optional):
\{\{ - a {{ text
(.*?) - Capturing group 2: any zero or more chars other than line break chars, as few as possible (if you need to match line breaks, too, use ((?s:.*?)) instead, or simply add /m flag)
\}\} - a }} string
(?(1)"|) - a conditional construct: if Group 1 matched, match ", else, match an empty string.
In the code, you will need to check if Group 1 matched, and if so, implement one replacement logic, else, use another replacement logic. See the Ruby demo:
def fill_in(template)
template.gsub(/(")?\{\{(.*?)\}\}(?(1)"|)/) {
$~[1] ? "Replacement 1" : "Replacement 2"
}
end
p fill_in('"{{hello}}" and {{hello}}')
# => "Replacement 1 and Replacement 2"

Match a word or whitespaces in Lua

(Sorry for my broken English)
What I'm trying to do is matching a word (with or without numbers and special characters) or whitespace characters (whitespaces, tabs, optional new lines) in a string in Lua.
For example:
local my_string = "foo bar"
my_string:match(regex) --> should return 'foo', ' ', 'bar'
my_string = " 123!#." -- note: three whitespaces before '123!#.'
my_string:match(regex) --> should return ' ', ' ', ' ', '123!#.'
Where regex is the Lua regular expression pattern I'm asking for.
Of course I've done some research on Google, but I couldn't find anything useful. What I've got so far is [%s%S]+ and [%s+%S+] but it doesn't seem to work.
Any solution using the standart library, e.g. string.find, string.gmatch etc. is OK.
Match returns either captures or the whole match, your patterns do not define those. [%s%S]+ matches "(space or not space) multiple times more than once", basically - everything. [%s+%S+] is plain wrong, the character class [ ] is a set of single character members, it does not treat sequences of characters in any other way ("[cat]" matches "c" or "a"), nor it cares about +. The [%s+%S+] is probably "(a space or plus or not space or plus) single character"
The first example 'foo', ' ', 'bar' could be solved by:
regex="(%S+)(%s)(%S+)"
If you want a variable number of captures you are going to need the gmatch iterator:
local capt={}
for q,w,e in my_string:gmatch("(%s*)(%S+)(%s*)") do
if q and #q>0 then
table.insert(capt,q)
end
table.insert(capt,w)
if e and #e>0 then
table.insert(capt,e)
end
end
This will not however detect the leading spaces or discern between a single space and several, you'll need to add those checks to the match result processing.
Lua standard patterns are simplistic, if you are going to need more intricate matching, you might want to have a look at lua lpeg library.

Ruby regex to find words starting with #

I'm trying to write a very simple regex to find all words in a string that start with the symbol #. Then change the word to a link. Like you would see in a Twitter where you can mention other usernames.
So far I have written this
def username_link(s)
s.gsub(/\#\w+/, "<a href='/username'>username</a>").html_safe
end
I know it's very basic and not much, but I'd rather write it on my own right now, to fully understand it, before searching GitHub to find a more complex one.
What I'm trying to find out is how can I reference that matched word and include it in the place of username. Once I can do that i can easily strip the first character, #, out of it.
Thanks.
You can capture using parentheses and backreference with \1 (and \2, and so on):
def username_link(s)
s.gsub(/#(\w+)/, "<a href='/\\1'>\\1</a>").html_safe
end
See also this answer
You should use gsub with back references:
str = "I know it's very basic and not much, but #tim I'd rather write it on my own."
def username_to_link(str)
str.gsub(/\#(\w+)/, '#\1')
end
puts username_to_link(str)
#=> I know it's very basic and not much, but #tim I'd rather write it on my own.
Following Regex should handle corner cases which other answers ignore
def auto_username_link(s)
s.gsub(/(^|\s)\#(\w+)($|\s)/, "\\1<a href='/\\2'>\\2</a>\\3").html_safe
end
It should ignore strings like "someone#company" or "#username-1" while converting everything like "Hello #username rest of message"
How about this:
def convert_names_to_links(str)
str = " " + str
result = str.gsub(
/
(?<=\W) #Look for a non-word character(space/punctuation/etc.) preceeding
# #an "#" character, followed by
(\w+) #a word character, one or more times
/xm, #Standard normalizing flags
'#\1'
)
result[1..-1]
end
my_str = "#tim #tim #tim, ##tim,#tim t#mmy?"
puts convert_names_to_links(my_str)
--output:--
#tim #tim #tim, ##tim,#tim t#mmy?

gsub { $1.upcase } ? Is equivalent to .capitalize?

I found in the legacy code the following:
"myString".sub(/^(.)/) {$1.upcase} seems very weird. While executing in IRB, I got the same result as "myString".capitalize
Wasn't able to find the documentation... so ended up on SO
Not exactly,
"myString".capitalize
#=> "Mystring"
"myString".sub(/^(.)/) {$1.upcase}
#=> "MyString"
From the docs for capitalize
Returns a copy of str with the first character converted to uppercase and the remainder to lowercase. Note: case conversion is effective only in ASCII region.
sub accepts an optional block instead of a replacement parameter. If given, it places the sub-matches into global variables, invokes the block, and returns the matched portion of the string with the block's return value.
The regular expression in question finds the first character at the beginning of a line. It places that character in $1 because it's contained in a sub-match (), invokes the block, which returns $1.upcase.
As an aside, this is a brain-dead way of capitalizing a string. Even if you didn't know about .capitalize or this code is from before .capitalize was available (?), you could still have simply done myString[0] = myString[0].upcase. The only possible benefit is the .sub method will work if the string is empty, where ""[0].upcase will raise an exception. Still, the better way of circumventing that problem is myString[0] = myString[0].upcase if myString.length > 0
Both are not exactly same. sub is used to replace the first occurrence of the pattern specified, whereas gsub does it for all occurrences (that is, it replaces globally).
In your question, regular expression is the first character i.e., $1 and replaces with $1.upcase.
CODE :
"myString".sub(/^(.)/) {$1.upcase}
OUTPUT :
"MyString"
CODE :
"myString".capitalize
OUTPUT :
"Mystring"

Assistance with Some Interesting Syntax in Some Ruby Code I've Found

I'm currently reading Agile Web Development With Rails, 3rd edition. On page 672, I came across this method:
def capitalize_words(string)
string.gsub(/\b\w/) { $&.upcase }
end
What is the code in the block doing? I have never seen that syntax. Is it similar to the array.map(&:some_method) syntax?
It's Title Casing The Input. inside the block, $& is a built-in representing the current match (\b\w i.e. the first letter of each word) which is then uppercased.
You've touched on one of the few things I don't like about Ruby :)
The magic variable $& contains the matched string from the previous successful pattern match. So in this case, it'll be the first character of each word.
This is mentioned in the RDoc for String.gsub:
http://ruby-doc.org/core/classes/String.html#M000817
gsub replaces everything that matched in the regex with the result of the block. so yes, in this case you're matching the first letter of words, then replacing it with the upcased version.
as to the slightly bizarre syntax inside the block, this is equivalent (and perhaps easier to understand):
def capitalize_words(string)
string.gsub(/\b\w/) {|x| x.upcase}
end
or even slicker:
def capitalize_words(string)
string.gsub /\b\w/, &:upcase
end
as to the regex (courtesy the pickaxe book), \b matches a word boundary, and \w any 'word character' (alphanumerics and underscore). so \b\w matches the first character of the word.

Resources