I have some string inputs, which I want to validate whether it's a valid Ruby Symbol literal. If it is, then convert it to a Symbol. Otherwise return the passed string.
Example,
def parse_symbol(str)
... # Validate and convert to Symbol
# Return Symbol if valid Symbol literal
# Otherwise return str
end
input1 = ':foo_bar' #=> Valid Symbol
parse_symbol(input1) #=> :foo_bar
input2 = ':"foo bar"' #=> Valid Symbol
parse_symbol(input2) #=> :"foo bar"
input3 = ':foo bar' #=> Invalid
parse_symbol(input3) #=> :foo bar
input4 = '::"foo_bar"' #=> Invalid
parse_symbol(input4) #=> ::"foo_bar"
... # all other possible valid and invalid symbol literal goes here
str.to_sym # Transforms every string into Symbol form
Edit
Is eval
an expensive tool to use here?
eval(str).is_a?(Symbol) rescue str
CodePudding user response:
I'd recommend using a real parser for this.
require 'parser/current'
require 'minitest/autorun'
def parse_symbol(str)
ast = Parser::CurrentRuby.parse(str)
if ast.type == :sym
ast.children[0]
else
str
end
rescue Parser::SyntaxError
str
end
class TestAnswer < Minitest::Test
def test_1
assert_equal :foo_bar, parse_symbol(':foo_bar')
end
def test_2
assert_equal :"foo bar", parse_symbol(':"foo bar"')
end
def test_3
assert_equal ":foo bar", parse_symbol(':foo bar')
end
def test_4
assert_equal '::"foo_bar"', parse_symbol('::"foo_bar"')
end
end
CodePudding user response:
def parse_symbol(str)
result = str.scan /^\:(([a-zA-Z_] [a-zA-Z0-9_]*)|\"([a-zA-Z0-9_\- ] )\")$/
return str unless !result.empty?
if !result[0][1].nil?
result[0][1].to_sym
else
result[0][2].to_sym
end
end
CodePudding user response:
Using a regular expression like this.
def parse_symbol(str)
if str ~= /:([^:\s] ||"[^:] ")/
return str.to_sym
else
return str
end
end
Is
eval
an expensive tool to use here?
It might not be that expensive, but it can be dangerous depending on where this input is coming from.