Reputation: 458
Is there an idiomatic Ruby pattern to test two 'strings' for equality that is indifferent to whether the operands are strings or symbols?
I'd like to use some operator to perform this comparison: :abc == 'abc'.to_sym
without the need to normalize the operands to strings or symbols.
The HashWithIndifferentAccess
behaviour in active_support
is a pretty useful analogy for the sort of thing I'm looking for.
Upvotes: 13
Views: 12454
Reputation: 640
Since Ruby 2.4 You can use match?
method
> :abc.match?(/abc/)
=> true
> 'abc'.match?(/abc/)
=> true
Upvotes: 1
Reputation: 74670
If you want to monkey patch the generic functionality in everywhere.
class Object
def to_s_equals? var
self.to_s == var
end
end
As mentioned, only convert symbols to strings, not strings to symbols unless you have a subsequent use for the symbol. You could be more specific and only do that on Symbol
Alternatively you could add something for String and Symbols, but I can't think of a good common name.
class Symbol
def equals_string? var
self.to_s == var
end
end
class String
def equals_symbol? var
self == var.to_s
end
end
Even then equals
isn't quite right, but match
infers a regex. homologous
maybe? (corresponding in structure, but not necessarily function)
I don't think your getting much brevity on to_s ==
. Maybe a bit of clarity enforcing the order you do the comparisons in.
Upvotes: 4
Reputation: 29318
You could also patch into Symbol
if you know that the symbol will always be used as the receiver. Such as
class Symbol
alias_method :old_match, :=~
def =~(s)
old_match(s.is_a?(String) ? /#{Regexp.quote(s)}/ : s)
end
end
:abc =~ "abc"
#=> 0
:abc =~ /abc/
#=> 0
:abc =~ "abcd"
#=> nil
This will work the exact same way as :abc =~
currently works but with a transformation of a String
to a Regex
first.
Although I generally suggest against monkey patching built in classes unless the implementation is isolated this should not have too many foreseeable side effects
Upvotes: 0
Reputation: 118261
You can use regex pattern to do this comparisons :-
/\Aabc\z/ === "abc" # => true
/\Aabc\z/ === :abc # => true
So, you can make your own method :-
def comparisons(sym, str, patt)
[sym, str].all? { |i| patt === i }
end
comparisons(:abc, "abc", /\Aabc\z/) # => true
comparisons(:abc, "abcd", /\Aabc\z/) # => false
comparisons(:abcd, "abc", /\Aabc\z/) # => false
Upvotes: 1
Reputation: 5615
HashWithIndifferentAccess explicitly tests is_a?(Symbol)
and, if so, converts it to a string.
Side note, converting a symbol to a string is probably better practice than the other direction. Strings are subject to cleanup and symbols are not, so symbols will hang around forever and slowly leak memory.
Upvotes: 1