I installed settingslogic and in the configuration file I put the regex for the email as follows:
#config/settings.yml
defaults: &defaults
email_regex: /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
development:
<<: *defaults
# neat_setting: 800
test:
<<: *defaults
production:
<<: *defaults
That I load in devise configuration in this way:
#config/initializers/devise.rb
# Regex to use to validate the email address
# config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
config.email_regexp = eval Settings.email_regex
It works, but what do you think about that eval
? Is it the correct way to convert a string to a regex?
-
\$\begingroup\$ Did you choose email only as an example or are you actually making the regexp pattern that matches emails a configurable option? If the latter, allow me to ask: why? Are you really planning to deploy multiple versions of this app that need to match emails in different ways? \$\endgroup\$user804– user8042011年01月27日 16:43:58 +00:00Commented Jan 27, 2011 at 16:43
-
\$\begingroup\$ sorry for late answer, I store several email around the prj and I taught to have a single place where to store the regex all the emails have to respect, a constant would be enough \$\endgroup\$ecoologic– ecoologic2011年01月29日 21:58:02 +00:00Commented Jan 29, 2011 at 21:58
-
\$\begingroup\$ the solution is for getting the regex from a yaml, while if you have it in a regular string this could help you stackoverflow.com/questions/4840626/… \$\endgroup\$ecoologic– ecoologic2011年02月02日 19:09:03 +00:00Commented Feb 2, 2011 at 19:09
-
\$\begingroup\$ Sorry for my even later reply. To clarify, I was asking why this needs to be set in a config file at all instead of being somewhere in the code where it makes sense - only once of course. E.g. something like this: Email.valid?(string) \$\endgroup\$user804– user8042011年02月08日 23:01:01 +00:00Commented Feb 8, 2011 at 23:01
-
\$\begingroup\$ The string is read in devise configuration, it's not my own auth and I use Settingslogic to store all my config in one place. \$\endgroup\$ecoologic– ecoologic2011年03月10日 09:11:44 +00:00Commented Mar 10, 2011 at 9:11
5 Answers 5
If you want to use a regexp in a yaml file you need to use !ruby/regexp
#config/settings.yml
defaults: &defaults
email_regex: !ruby/regexp '/^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i'
Edit: The solution proposed by Mike Bethany is very similar to the yaml implementation.
You can take a look to what is used in Ruby 1.9.2 here (search for "!ruby/regexp"): https://github.com/tenderlove/psych/blob/master/lib/psych/visitors/to_ruby.rb
PS (and OT): I think, like Mike Bethany, that this basic functionality belong to the Regexp class not yaml, and need to be moved to a Regexp method. What do you think?
I'm not crazy about using eval for such a simple task, it's easy and it works but it just doesn't sit well with me; it's like giving your gran' an Indy car to go get a loaf of bread. Instead you could do something like this.
split = Settings.email_regex.split("/")
options = (split[2].include?("x") ? Regexp::EXTENDED : 0) |
(split[2].include?("i") ? Regexp::IGNORECASE : 0) |
(split[2].include?("m") ? Regexp::MULTILINE : 0) unless split[2].nil?
Regexp.new(split[1], options)
This will work if there are options or not and doesn't require a potentially dangerous eval.
P.S. Sinetris made the much better suggestion of just adding !ruby/regexp
before your regex and wrapping it in single quotes in your settings.yml file. That still doesn't fix the issue with the RegExp class not properly dealing with string representations of regex statements though so I'll leave the above code for anyone that wants to do that outside of a YML file.
-
\$\begingroup\$ I agree on everything and by the way thanks for editing, where then would you put this function for reuse? \$\endgroup\$ecoologic– ecoologic2011年01月22日 23:16:14 +00:00Commented Jan 22, 2011 at 23:16
-
\$\begingroup\$ It's a little verbose anyway... \$\endgroup\$ecoologic– ecoologic2011年01月22日 23:17:01 +00:00Commented Jan 22, 2011 at 23:17
-
1\$\begingroup\$ It's almost criminal that this kind of basic functionality isn't in the Regexp class so I'd monkey patch it into there. I would use a new function name though like Regexp#new_from_string or whatever you think sounds best. (I just added the "ruby" tag since it's more of a Ruby question than a Rails one). \$\endgroup\$Mike Bethany– Mike Bethany2011年01月23日 02:13:37 +00:00Commented Jan 23, 2011 at 2:13
-
\$\begingroup\$ It's probably not part of the class because you can just prepend (?xim) to the regex itself. Monkeypatching a new constructor into a core class because the default doesn't do what you want /at first glance/ is a little nuts. \$\endgroup\$Eevee– Eevee2011年01月27日 17:11:31 +00:00Commented Jan 27, 2011 at 17:11
-
\$\begingroup\$ I think you may not have bothered to read the actual question. Your comment makes no sense otherwise. The issue has nothing to do with regex options but converting a string representation of a regex to an actual regex. I'll bet you feel pretty nuts yourself now huh? Next time you might find it benificial to actually read the whole issue before commenting. \$\endgroup\$Mike Bethany– Mike Bethany2011年01月27日 20:45:34 +00:00Commented Jan 27, 2011 at 20:45
I would definately not put the regex in the comment. That means that it needs to be changed in two places, one of which doesn't matter and will be misleading. Place a comment on the declaration of email_regex
that explains what it is filtering. That way if it ever changes, all the places to change are contained and easy to find.
#config/initializers/devise.rb
# Regex to use to validate the email address
config.email_regexp = eval Settings.email_regex
and
# Email validation regex - <short explanation to taste>
email_regex: /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
I see no readability problems with the code, if that is the correct method of retrieving a setting. (I'm not a Ruby expert.)
-
\$\begingroup\$ the comment was the old code before I put the setting, I left in there in case I had to go back to the old solution, you right, I'll remove it or comment it better. \$\endgroup\$ecoologic– ecoologic2011年01月22日 19:34:50 +00:00Commented Jan 22, 2011 at 19:34
If you want avoiding the eval you can. It's a little more trick but you can be sure, you have a regexps after this code in your devise :
#config/initializers/devise.rb
# Regex to use to validate the email addres
# config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
Setting.email_regexp[/\/(.*)\/(.?)/]
config.email_regexp = x ; Regexp.new(/#{1ドル}/)
The problem with this trick is you failed the second argument in your case the insensitive-case. You just need add a new setting like :
email_regexp_sensitive_case: true
And now you just need call like this :
#config/initializers/devise.rb
# Regex to use to validate the email addres
# config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
Setting.email_regexp[/\/(.*)\/(.?)/]
config.email_regexp = Regexp.new(/#{1ドル}/, Setting.email_regexp_sensitive_case)
In my case you are sure to have a Regexp define in your email_regexp without any eval.
-
\$\begingroup\$ but what do you think about the code the way it was? is there anything we should be aware of (using eval this way)? because right now the initial implementation is the one that offers more readability \$\endgroup\$ecoologic– ecoologic2011年01月23日 14:46:31 +00:00Commented Jan 23, 2011 at 14:46
As Sinetris mentioned, YAML has support for loading an instance of Regexp from a string.
require 'yaml'
YAML.load('!ruby/regexp /abc/ix')
# => /abc/ix
YAML.load('!ruby/regexp /abc/ix').class
# => Regexp
Explore related questions
See similar questions with these tags.