Is overriding operators with #prepend dangerous? - ruby

I am building a gem that makes an ActiveRecord immutable. The details do not matter, but basically, one thing this allows is for user.country == :CAN to return true if the country's code attribute match.
Of course, this means that :CAN == user.country will never work unless I override the == operator on Symbol, which I am wondering if this is a dangerous thing to do, maybe because of the added overhead, since this operator is used extensively everywhere.
Is there a better/smarter way to do exactly that? #coerce is not an option because Symbol already knows how to ==.
Symbol.prepend(Module.new do
def ==(other)
if other.respond_to?(:immutable?) && other.immutable?
other.==(self)
else
super
end
end
end)
If it changes anything, my main issue also has to do with the === operator, since I wanted to enable the following:
case user.country
when :CAN then ...
when :USA then ...
else ...
end

Related

Elegant way to tell if something is false?

Seeing that .nil? is so useful and makes code so readable, I tried .false? and was surprised it didn't exist.
Question
What is the most elegant / preferred / self-documenting / idiomatic way to check if something is false in ruby, without using any user-defined methods?
Example
A possible use case replacing; the s.false? in this:
def false?
self == false
end
s ||= "hello" # is the same as
s = "hello" if (s.nil? || s.false?)
Well, usually you just compare to false only if it is actually important whether the value is really false as in
if s == false
do_something
end
However, most of the time, people actually check for a value to be truthy or falsy as you often don't (need to) care for the strict difference between false or nil.
Here, you thus merely check whether a value is nil or false (that is: it's falsy) or if it is anything else (that is: it's truthy). This is encouraged by language idioms such as the checks done by if and unless as well as the common boolean operators such as || or &&.
do_something if s # called if s is anything else but false or nil
do_something unless s # called if s is either false or nil
Especially when accepting / expecting boolean values, a nil value is often handled as if it were false because of these Ruby language idioms.
What is the most elegant / preferred / self-documenting / idiomatic
way to check if something is false in ruby, without using any
user-defined methods?
I think s == false is your answer plain and simple.

Detecting a missing sub!, sort!, map!, etc

After returning to Ruby from a long stint coding in another language, I regularly assume that foo.sort, foo.map {...}, foo.sub /bar/, 'zip' will change foo. Of course I meant foo.sort!, etc. But that usually takes 3 or 4 debugging potshots before I notice. Meanwhile, the sort is calculated, but then isn't assigned to anything. Can I make ruby warn about that missing lvalue, like a C compiler warns of a function's ignored return value?
You mean like Perl's somewhat infamous "using map in void context"? I don't know of Ruby having such a thing. Sounds like you need more unit testing to catch mistakes like this before they can worm into your code deeply enough to be considered bugs.
Keep in mind Ruby's a lot more flexible than languages like Perl. For example, the following code might be useful:
def rewrite(list)
list.map do |row|
row += '!'
end
end
Now technically that's a map in a void context, but because it's used as a return value it might be captured elsewhere. It's the responsibility of the caller to make use of it. Flagging the method itself for some sort of warning is a level removed from what most linting type tools can do.
Here's a very basic parser :
#forgetful_methods = %w(sort map sub)
Dir['*.rb'].each do |script|
File.readlines(script).each.with_index(1) do |line, i|
#forgetful_methods.each do |method|
if line =~ /\.#{method}(?!!)/ && $` !~ /(=|\b(puts|print|return)\b|^#)/
puts format('%-25s (%3d) : %s', script, i, line.strip)
end
end
end
end
# =>
# brace_globbing.rb ( 13) : subpatterns.map{|subpattern| explode_extglob(match.pre_match+subpattern+match.post_match)}.flatten
# delegate.rb ( 11) : #targets.map { |t| t.send(m, *args) }
It checks every ruby script in the current directory for sort, map or sub without ! that aren't preceded by =, puts, print or return.
It's just a start, but maybe it could help you find some of the low hanging fruits.
There are many false positives, though.
A more complex version could use abstract syntax trees, for example with Ripper.

Optimizing basic method memoization with early return

When implementing basic memoization in Ruby, is there a pattern or simple way to return the memoized instance var if the value predicates on a more complex evaluation before hand?
Say the assignment of something requires an intense calculation, is Ruby smart enough to return the instance variable if it's present, or will something always be assigned within the scope of that method before setting #some_value?
def some_value
#some_value if #some_value.present? # possible?
something = something_else.try(:method_name) || another_something.method_name # prevent this from evaluating after execution
#some_value ||= MyClass.new(property: something.property)
end
What would a better memoization pattern be to implement what I have?
Based on how your code is currently written, the "intense calculation" will always occur. Ruby uses implicit return unless you explicitly use the keyword return, so, even if #some_value is present, the code will still execute to the last line.
def some_value
return #some_value if #some_value.present? # possible?
something = something_else.try(:method_name) || another_something.method_name # prevent this from evaluating after execution
#some_value ||= MyClass.new(property: something.property)
end
So, if you want to return #some_value if it is present, and not run any code afterwards, you will want to use explicit return. See above.
Now, Ruby will check if #some_value is present, and if that is true, the value is returned, otherwise, it will continue with the calculation.

In environments that take Boolean arguments, is it a good idea to wrap all functions instead of allowing them to be implicitly coerced?

Take the String#=~ function for instance. It will return the index of the first match if the match is found, which, as a Fixnum will always act as true in boolean environments. If the match isn't found, it returns null, which acts as false.
Now suppose I have a class:
class A
attr_accessor :myprop
# prints "I am awesome" if #myprop matches /awesome/
# and "I am not awesome" otherwise
def report_on_awesomeness!
puts "I am #{myprop =~ /awesome/ ? 'awesome' : 'not awesome'}."
end
end
This code will pretty much work just as expected, but the first element in the trial conditional operator is the subject of my question.
Is it a good idea not to wrap myprop =~ /awesome/? I'm not talking about abstracting it into another method like def is_awesome?; myprop =~ /awesome/; end but rather whether my current convention, which forces Ruby to implicitly casts Fixnums to true and nils to false, is preferable over wrapping the condition into something I cast myself. I could easily do this:
class A
attr_accessor :myprop
# prints "I am awesome" if #myprop matches /awesome/
# and "I am not awesome" otherwise
def report_on_awesomeness!
puts "I am #{(myprop =~ /awesome/).nil? ? 'not awesome' : 'awesome'}."
end
end
Pros I see for the first style:
Most maintainers (including future me) are used to the implicit type
It's shorter
Pros I see for the second style:
It's more obvious exactly what the relationship is between the result of the =~ method and its boolean interpretation
It gives you more freedom to use more creative explicit casting
I suspect that there might be some middle ground, where you leave implicit type conversions in cases where it's idiomatic (e.g., regular expression matching using =~) and do it explicitly when it's not (e.g., your own properties, especially if they have multiple return types).
I would appreciate any insights or experiences the community can share on this issue.
IMHO that's a personal choice. You can take any style, since you feels better by working with that.
Once I defined true? on Object to get its boolean value (another name could be to_bool):
class Object
def true?
!!self
end
end
But the double bang (!!) is simpler to convert anything to Boolean and I prefer to use it - but not everywhere. I use it only when I need explicity a boolean value (I wouldn't use it in the case of this question).
BTW, false.nil? == false; it could lead to confusion.

How can I avoid truthiness in Ruby?

Is there any standard way to avoid truthiness in Ruby, or would I need to roll my own solution, such as
class FalseClass
def to_bool
self
end
end
class TrueClass
def to_bool
self
end
end
true.to_bool # => true
false.to_bool # => false
nil.to_bool # => NoMethodError
42.to_bool # => NoMethodError
Background: I know that to_bool would go against the permissive nature of Ruby, but I'm playing around with ternary logic, and want to avoid accidentally doing something like
require "ternary_logic"
x = UNKNOWN
do_something if x
I'm using ternary logic because I'm writing a parser of a flatmate-share web site (for personal, not commercial, use) and it's possible for some fields to be missing information, and therefore it'd be unknown whether the place meets my criteria or not. I'd try to limit the amount of code that uses the ternary logic, however.
It is not possible to influence truthiness or falsiness in Ruby. nil and false are falsy, everything else is truthy.
It's a feature that comes up every couple of years or so, but is always rejected. (For reasons that I personally don't find convincing, but I'm not the one calling the shots.)
You will have to implement your own logic system, but you cannot prohibit someone from using Ruby's logical operators on an unknown value.
I re-implemented Ruby's logic system once, for fun and to show it can be done. It should be fairly easy to extend this to ternary logic. (When I wrote this, I actually took the conformance tests from RubySpec and ported them to my implementation, and they all passed, so I'm fairly confident that it matches Ruby's semantics.)
You can take advantage of the overridable ! operator in 1.9 and the !! idiom to redefine truthiness.
Let's have a Pythonesque truthiness:
class Numeric
def !
zero?
end
end
class Array
def !
empty?
end
end
!![] #=> false
!!0 #=> false
I also made my own logic system in Ruby (for fun), and you can easily redefine truthiness:
Note, the analogs of the normal conditionals are if!/else_if!/else!
# redefine truthiness with the `truth_test` method
CustomBoolean.truth_test = proc { |b| b && b != 0 && b != [] }
if!(0) {
puts 'true'
}.
else! {
puts 'false'
}
#=> false
see: http://github.com/banister/custom_boolean

Resources