Trying to write correct validation.
I have symbols/letters which can be only used:
ALLOWED_SYMBOLS = %w(/ # _ + - ( ) . , : ? ' & ; " 0 1 2 3 4 5 6 7 8 9 A a Ā ā Ą ą Ä ä B b C c Č č D d E e Ē ē Ę ę Ė ė F f G g Ģ ģ H h I i Ī ī Į į Y y J j K k Ķ ķ L l Ļ ļ M m N n Ņ ņ O o Õ õ Ö ö P p Q q R r S s Š š T t U u Ū ū Ü ü V v W w Z z Ž ž X x)
Afterwards i'm trying to validate it
validates :reference inclusion: { in: ALLOWED_SYMBOLS, allow_blank: true }
But it's not working properly as if i'm writing 2 or more allowed symbols i get an error, it does not happen when i type only 1 allowed one.
Looking forward for your help. The idea is to only allow mentioned symbols(they can be duplicated and such)
Rails 5.2
Your problem is that validating inclusion: {in: ...} is saying "the value must be one of the items in the list" -- which is not what you want at all.
Instead, what you're trying to check is "does reference only contain characters from this list?".
I would solve that with a regex. Suppose, for example, you wanted a string to only contain the characters a, b, c, d, ..., z. Then you could check the format with:
/\A[a-z]*\z/
Where \A means "start of string", \z means "end of string" and [a-z]* means "zero or more letters from the collection: a, b, c, ...., z".
However, your scenario is a little more awkward because you don't have a nice character set/range like [a-z]. You could write that very verbosely (but it's difficult to read/reuse the code):
/\A[\/#_+\-().,:?'&;"0123456789ĀāĄąÄäBb....]*\z/
Or, better, you could get a little fancy and convert the constant into a suitable regex:
/\A#{Regexp.union(*ALLOWED_SYMBOLS)}*\z/
And therefore your final answer is to replace this:
validates :reference inclusion: { in: ALLOWED_SYMBOLS, allow_blank: true }
With this:
validates :reference, format: { with: /\A#{Regexp.union(*ALLOWED_SYMBOLS)}*\z/ }
See also: https://guides.rubyonrails.org/active_record_validations.html
Related
I'm doing a bit of code golfing, and I've gotten to this:
for i=1,100 do for j=1,i do if i%j<1 then io.write(j.." ") end end print() end
Is there any way to get the if statement as an inline? So that it's wrapped into the io.write()
The ternary operation in lua can be mimicked with and..or operators:
a and b or c
is similar to
a ? b : c
under truthy values. For your case:
for i=1,100 do
for j=1,i do
io.write( ((i % j) < 1 and j.." " or '')
-- (i % j) < 1 and io.write(.." ")
end
print() -- why print here?
end
golfed, it is
io.write(i%j<1 and j.." "or'')
which saves you 4 characters
I need to verify that a string has at least one comma but not more than 4 commas.
This is what I've tried:
/,{1,4}/
/,\s{1,4}/
Neither of those work.
Note: I've been testing my RegEx's on Rubular
Any help is greatly appreciated.
Note: I'm using this in the context of an Active Record Validation:
validates :my_string, format: { with: /,\s{1,4}/}
How can do this as an Active Record Validation?
Does it have to be a regex? If not, use Ruby's count method:
> "a,a,a,a,a".count(',')
=> 4
str ="a,b,a,,"
p str.count(",").between?(1, 4) # => true
I too would suggest using count, but to address your specific question, you could do it thusly:
r = /^(?:[^,]*,){1,4}[^,]*$/
!!"eenee"[r]
#=> false
!!"eenee, meenee"[r]
#=> true
!!"eenee, meenee, minee, mo"[r]
#=> true
!!"eenee, meenee, minee, mo, oh, no!"[r]
#=> false
(?:[^,]*,) is a non-capture group that matches any string of characters other than a comma, followed by a comma;
{1,4} ensures that the non-capture group is matched between 1 and 4 times;
the anchor ^ ensures there is no comma before the first non-capture group; and
[^,]*$ ensures there is no comma after the last non-capture group.
How can I solve following problem?
I have a html string like following one:
<p>aaa, b aa aaaaa?<br/>Next possible text b bb aa b.</p>
Now I'd like to replace for example only
"aaa"
with
"<div class='special'>aaa</div>"
new string after replace:
<p><div class='special'>aaa</div>, b aa aaaaa?<br/>Next possible text b bb aa b.</p>
So I´d like a generic replacer, which only replace an exact matching string. "aaa" was just an example. It could also be "bb" or "two words" (=> two words, so text.split won't work in my opinion).
Anybody an idea for such an dynamic find, match and replacer?
I tried it already like following:
items = ["aaa", "a", "aa", "aa b", "c"]
text = "<p>aaa, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
words = text.split => ["<p>aaa,", "b", "aa", "aaaaa?<br/>Next", "possible", "text", "b", "bb", "aa", "b.</p>"]
new_words = []
words.each do |w|
items.each do |item|
if w == item
w = '<div class="special">#{item}</div>'
end
end
new_words << w
end
text = new_words.join(" ")
Result:
"<p>aaa, b <div class='special'>aa</div> aaaaa?<br/>Next possible text b bb <div class='special'>aa</div> b.</p>"
But it should be:
"<p><div class='special'>aaa</div>, b <div class='special'>aa</div> aaaaa?<br/>Next possible text b bb <div class='special'>aa b</div>.</p>"
My biggest problems are:
Special characters like ",.?()%€"-characters at the end of a string
=> "aaa," from the example
Substrings with same parts => like "aaa" and "aa"
Two words as one item => like "aa b" from the example
Someone an idea for fixing my problems?
EDIT: something is only a placeholder for my replacement.. my real replacement could also be:
%Q( <dfn title="#{strip_tags item.text}">#{item.name}</dfn> )
item.text could be everything => could contain also "aaa"
item.name is for example "aaa"
So multiple gsub would replace also already replaced content.
It's not clear whether there is a single instance of aaa or multiple, and whether you want them all replaced, or just the first one.
This will replace just the first:
text = "<p>aaa, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
text.sub(/\b(aaa)\b/, %q"<div class='special'>\1</div>")
=> "<p><div class='special'>aaa</div>, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
This will replace all occurrences:
text = "<p>aaa, b aa aaaaa?<br/>Next possible text b bb aa b.</p>" * 2
=> "<p>aaa, b aa aaaaa?<br/>Next possible text b bb aa b.</p><p>aaa, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
text.gsub(/\b(aaa)\b/, %q"<div class='special'>\1</div>")
=> "<p><div class='special'>aaa</div>, b aa aaaaa?<br/>Next possible text b bb aa b.</p><p><div class='special'>aaa</div>, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
You can put "aaa" into a variable and find it by interpolating that target into the pattern:
target = 'aaa'
text.gsub(/\b(#{ target })\b/, %q"<div class='special'>\1</div>")
=> "<p><div class='special'>aaa</div>, b aa aaaaa?<br/>Next possible text b bb aa b.</p><p><div class='special'>aaa</div>, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
Regular expressions have the \b (word-break) marker, which makes it easy to define words, or substring, matches. You can replace "aaa" with multiple words also.
You're looking for String#sub (not gsub)
s = "<p>aaa, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
# => "<p>aaa, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
match = "aaa"
# => "aaa"
replacement = "<div class='special'>aaa</div>"
# => "<div class='special'>aaa</div>"
s.sub match, replacement
# => "<p><div class='special'>aaa</div>, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
"<p><div class='special'>aaa</div>, b aa aaaaa?<br/>Next possible text b bb aa b.</p>" == _
# => true
I would use a regular expression, Rubular is a great place to learn and test out your expressions. For more information on how to use gsub check out Jayfields Blog post. This may not fit all your use cases for this problem so you may need to modify it.
str.gsub /^<p>a{3}/, "<div class='special'>aaa</div>"
What this says is starting at the beginning of the string (^)
find <p> and 3 assurances of the letter a.
Here is the replacer method you wanted (using gsub, of course):
def replacer(orig,pattern,replace)
orig.gsub(/#{pattern}(\s|\.|,)/,replace+'\1').to_s
end
2.0.0dev :001 > def replacer(orig,pattern,replace)
2.0.0dev :002?> orig.gsub(/#{pattern}(\s|\.|,)/,replace+'\1').to_s
2.0.0dev :003?> end
=> nil
2.0.0dev :004 > replacer("<p>aaa, b aa aaaaa?<br/>Next possible text b bb aa b.</p>", "aaa", "<div class='special'>aaa</div>")
=> "<p><div class='special'>aaa</div>, b aa aaaaa?<br/>Next possible text b bb aa b.</p>"
I am using Rails 3.2.2 and I would like to quote all array elements with ' and return a string containing all those quoted and comma-separated elements. At this time I am using
['a', 'b', 'c'].collect {|x| "'#{x}'"}.join(", ")
# => "'a', 'b', 'c'"
but I think I can improve the above code (maybe by using a unknown to me Ruby method, if it exists). Is it possible?
I use
"'#{%w{a b c}.join("', '")}'"
Here is expanded version:
' # Starting quote
%w{a b c}.join("', '") # Join array with ', ' delimiter that would give a', 'b', 'c
' # Closing quote
You can replace collect with its alias map and .join with the equivalent *. Finally, you can use the shortcut for writing an array of strings, %w(...), and you can use single quotes for the argument of .join/* as it does not use string interpolation (though it may be questionable if it preferable when it comes to performance).
%w(a b c).map {|x| "'#{x}'"} * ', '
It appears there is no performance difference between this version and the original but that that Sigurd's version is performing better:
Original 3.620000 0.000000 3.620000 ( 3.632081)
This 3.640000 0.000000 3.640000 ( 3.651763)
Sigurd's 2.300000 0.000000 2.300000 ( 2.303195)
Code for benchmark:
require 'benchmark'
n = 1000000
Benchmark.bm do |x|
x.report("Original") { n.times do
['a', 'b', 'c'].collect {|x| "'#{x}'"}.join(", ")
end}
x.report("This") { n.times do
%w(a b c).map {|x| "'#{x}'"} * ', '
end}
x.report("Sigurd's") { n.times do
"'#{%w{a b c}.join("', '")}'"
end}
end
Is the following statement possible with Rails/Ruby? If so, how :)
IF XXX Equals At Least One (Var1, Var2, Var3)
Try this:
if [v1, v2, v3].any?{|v| v=="XXX"}
p "Success"
end
OR
if [v1, v2, v3].include?("XXX")
p "Success"
end
if [a, b, c].find_index(XXX)
Sounds simple enough. And there's nothing wrong with classical way too:
if XXX == a || XXX == b || XXX == c