71 lines
1.6 KiB
Crystal
71 lines
1.6 KiB
Crystal
module Ameba::Rule::Naming
|
|
# A rule that disallows boolean properties without the `?` suffix - defined
|
|
# using `Object#(class_)property` or `Object#(class_)getter` macros.
|
|
#
|
|
# Favour this:
|
|
#
|
|
# ```
|
|
# class Person
|
|
# property? deceased = false
|
|
# getter? witty = true
|
|
# end
|
|
# ```
|
|
#
|
|
# Over this:
|
|
#
|
|
# ```
|
|
# class Person
|
|
# property deceased = false
|
|
# getter witty = true
|
|
# end
|
|
# ```
|
|
#
|
|
# YAML configuration example:
|
|
#
|
|
# ```
|
|
# Naming/QueryBoolMethods:
|
|
# Enabled: true
|
|
# ```
|
|
class QueryBoolMethods < Base
|
|
include AST::Util
|
|
|
|
properties do
|
|
description "Reports boolean properties without the `?` suffix"
|
|
end
|
|
|
|
MSG = "Consider using '%s?' for '%s'"
|
|
|
|
CALL_NAMES = %w[getter class_getter property class_property]
|
|
|
|
def test(source, node : Crystal::ClassDef | Crystal::ModuleDef)
|
|
calls =
|
|
case body = node.body
|
|
when Crystal::Call
|
|
[body] if body.name.in?(CALL_NAMES)
|
|
when Crystal::Expressions
|
|
body.expressions
|
|
.select(Crystal::Call)
|
|
.select!(&.name.in?(CALL_NAMES))
|
|
end
|
|
|
|
calls.try &.each do |exp|
|
|
exp.args.each do |arg|
|
|
name_node, is_bool =
|
|
case arg
|
|
when Crystal::Assign
|
|
{arg.target, arg.value.is_a?(Crystal::BoolLiteral)}
|
|
when Crystal::TypeDeclaration
|
|
{arg.var, path_named?(arg.declared_type, "Bool")}
|
|
else
|
|
{nil, false}
|
|
end
|
|
|
|
if name_node && is_bool
|
|
issue_for name_node, MSG % {exp.name, name_node}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|