def valid_sheet_names
Company.find(#company_id).asset_types.pluck(:name).reject(&:nil?).map(&:downcase)
end
["hardware", "computer", "network", "mobile devices"]
this function return an array.i want to remove space, dot and underscore from string. but i don'y know how can i do this
I would filter nil values within the database query and avoid loading them into memory first. Then I would sanitize the names with one tr call:
def valid_sheet_names
Company.find(#company_id).asset_types.where.not(name: nil).pluck(:name)
names.map { |name| name.downcase.tr(' ._', '') }
end
Building off of #Sumak's #spickermann's answers
["hardware", "computer", "network", "mobile devices"].map do |asset_type|
asset_type.gsub(/[._\s]/, '')
end
Which would piece into your code like this
def valid_sheet_names
Company.find(#company_id).asset_types.pluck(:name).reject(&:nil?).map { |name| name.downcase.gsub(/[._\s]/, '') }
end
gsub is preferred here to take advantage of the metacharacter \s which grabs any type of whitespace.
The same way you map over the collection, you can iterate it using a block:
["hardware", "computer", "network", "mobile devices"].map do |asset_type|
asset_type.delete(' ')
.delete('_')
.delete('.')
end
Your function could look something like:
def valid_sheet_names
asset_types = Company.find(#company_id).asset_types.pluck(:name).reject(&:nil?)
# I'd personally extract normalization to a specific function or module
asset_types.map do |asset_type|
asset_type.downcase
.delete(' ')
.delete('.')
.delete('_')
end
end
You can also use gsub (which supports regular expressions). Though I found delete more explicit when we want to... delete
Related
I have two different models: post (it has a content) and keywords (it has the word and the link). I am trying to make a function which would switch words in post content with the same keywords and its link (so it would work as hyperlink) For examples there is a keyword 'Hello' with some link on it and word 'hello', I want 'hello' in post.content to become a hyperlink with link from 'Hello' in keywords.
Here is my function:
def execute
#post = Post.find(params[:post_id])
all_keys = Keyword.all.pluck(:key, :link)
all_keys = all_keys.map.to_h
all_keys = all_keys.transform_keys(&:downcase)
new_content = #post.content.to_s
new_content_downcase = new_content.downcase
all_keys.map { |key, link| new_content_downcase.gsub!(key, "<a href='#{link}'>#{key}</a>") }
#post.content = new_content_downcase
#post.save!
end
Function is easy: I made a hash {key: 'link'} and have #post.content, then I downcase hash keys and #post.content and switch the words in post content with key from hash and link (so it would look like hyperlink).
Everything works fine but the problem is that it switch words in #post.content to lowercase (Hello --> hello). Is there any way to switch compare new_content and new_content_downcase, save the original word AND hyperlink on it?
Just don't downcase the post's content, that's it :) You could use gsub! with the block to make things concise, smth. like the following:
def execute
#post = Post.find(params[:post_id])
keys = Keyword.pluck(:key, :link).to_h.transform_keys(&:downcase)
#post.content.gsub!(/\w+/) do |word|
# We downcase each word when we check for the links presence...
url = keys[word.downcase]
# ... but not when we do replacements.
url ? "<a href='#{url}'>#{word}</a>" : word
end
#post.save!
end
So, your output is all lower case because you've applied #downcase to both your list of keywords and your content. And I assume you did that because you're doing a literal match between the keyword and the content string in your gsub.
One solution is to use a case-insensitive regex instead, :
all_keys.map { |key, link|
#post.content.gsub!(/(#{key})/i, "<a href='#{link}'>\1</a>")
}
Here, I've ignored the downcase and just used #post.content directly (I assume that it's a string so the to_s is redundant).
Then, in the gsub, I replaced the key direct match with a regex. This uses brackets to capture the term that's found for use in the replace term, so that you retain the capitalisation of the source rather than that of the stored keyword. The \1 in the replacement string is how that stored result from the regex gets used.
Fingers crossed that gets you working!
===Edit===
Here's an attempt at doing this properly, updating the entire method. (I'd also not escaped the \1 above, which it needs because it's in double quotes. Sorry about that!)
def export
#post = Post.find(params[:post_id])
_content = #post.content
Keyword.pluck(:key, :link).to_h.each { |_key, _link|
_content.gsub!(/(#{_key})/i, "<a href='#{_link}'>\\1</a>")
}
#post.update(content: _content)
end
Don't add key after \1, as you mention in a comment - the \1 should automatically be replaced with whatever was found by the regex (i.e. the value of key regardless of case).
Also, you shouldn't need to downcase your Keyword entries in any case: the time to do that is when they're created, so you only have to do it once.
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"
There is already created record, like
Company "Life"
How to make this record to the species
сompany-life
I used parameterize, but it turns:
company-quot-life-quot
As I understand, .gsub(""", "") is not suitable for implementation, since to create too large list of exceptions
Is there may be a way to make record in raw format? (to parameterize later)
thanks in advance!
Here is a non-Rails approach:
require 'cgi'
str = 'Company "Life"'
puts CGI.unescape_html(str).gsub(/"/, '').gsub(/\s+/, '-').downcase
# => company-life
And a pure regex solution:
puts str.gsub(/&\w+;/, '').gsub(/\s+/, '-').downcase
# => company-life
And if you are inside Rails(thanks to #nzifnab):
str.gsub(/&\w+;/, '').parameterize
As #meager said, you shouldn't be storing the html-encoded entities in the database to begin with, how did it get in there with "? Theoretically this would work:
class Page < ActiveRecord::Base
before_validation :unescape_entities
private
def unescape_entities
self.name = CGI.unescape_html(name)
end
end
But I'm still curious how name would be getting there in the first place with html entities in it. What's your action/form look like?
"Company "Life"".html_safe.parameterize
"Company "Life"".gsub(/&[^;]+;/, "-").parameterize.downcase
# => "company-life"
Firstly, gsub gets rid of html entities, then parameterize gets rid from all but Ascii alphanumeric (and replaces them with dash), then downcase. Note that "_" will be preserved too, if you don't like them, another gsub('_', '-') is needed.
I want to write a function that allows users to match data based on a regexp, but I am concerned about sanitation of the user strings. I know with SQL queries you can use bind variables to avoid SQL injection attacks, but I am not sure if there's such a mechanism for regexps. I see that there's Regexp.escape, but I want to allow valid regexps.
Here is is the sample function:
def tagged?(text)
tags.each do |tag|
return true if text =~ /#{tag.name}/i
end
return false
end
Since I am just matching directly on tag.name is there a chance that someone could insert a Proc call or something to break out of the regexp and cause havoc?
Any advice on best practice would be appreciated.
Interpolated strings in a Regexp are not executed, but do generate annoying warnings:
/#{exit -3}/.match('test')
# => exits
foo = '#{exit -3}'
/#{foo}/.match('test')
# => warning: regexp has invalid interval
# => warning: regexp has `}' without escape
The two warnings seem to pertain to the opening #{ and the closing } respectively, and are independent.
As a strategy that's more efficient, you might want to sanitize the list of tags into a combined regexp you can run once. It is generally far less efficient to construct and test against N regular expressions than 1 with N parts.
Perhaps something along the lines of this:
class Taggable
def tags
#tags
end
def tags=(value)
#tags = value
#tag_regexp = Regexp.new(
[
'^(?:',
#tags.collect do |tag|
'(?:' + tag.sub(/\#\{/, '\\#\\{').sub(/([^\\])\}/, '\1\\}') + ')'
end.join('|'),
')$'
].to_s,
Regexp::IGNORECASE
)
end
def tagged?(text)
!!text.match(#tag_regexp)
end
end
This can be used like this:
e = Taggable.new
e.tags = %w[ #{exit-3} .*\.gif .*\.png .*\.jpe?g ]
puts e.tagged?('foo.gif').inspect
If the exit call was executed, the program would halt there, but it just interprets that as a literal string. To avoid warnings it is escaped with backslashes.
You should probably create an instance of the Regexp class instead.
def tagged?(text)
return tags.any? { |tag| text =~ Regexp.new(tag.name, Regexp::IGNORECASE) }
end
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.