Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Typing/MethodReturnTypeRestriction #519

Merged
1 change: 1 addition & 0 deletions spec/ameba/base_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module Ameba::Rule
Naming
Performance
Style
Typing
]
end
end
Expand Down
127 changes: 127 additions & 0 deletions spec/ameba/rule/typing/method_return_type_restriction_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
require "../../../spec_helper"

module Ameba::Rule::Typing
subject = MethodReturnTypeRestriction.new

it "passes if a method has a return type" do
nobodywasishere marked this conversation as resolved.
Show resolved Hide resolved
expect_no_issues subject, <<-CRYSTAL
def hello : String
"hello world"
end

private def hello : String
"hello world"
end

protected def hello : String
"hello world"
end
CRYSTAL
end

it "passes if a private or protected method doesn't have a return type" do
expect_no_issues subject, <<-CRYSTAL
private def hello
"hello world"
end

protected def hello : String
nobodywasishere marked this conversation as resolved.
Show resolved Hide resolved
"hello world"
end
CRYSTAL
end

it "fails if a public method doesn't have a return type" do
expect_issue subject, <<-CRYSTAL
def hello
# ^^^^^ error: Method should have a return type restriction
"hello world"
end
CRYSTAL
end

context "properties" do
context "#private_methods" do
rule = MethodReturnTypeRestriction.new
rule.private_methods = true

it "passes if a method has a return type" do
expect_no_issues rule, <<-CRYSTAL
def hello : String
"hello world"
end

# This method is documented
def hello : String
"hello world"
end

nobodywasishere marked this conversation as resolved.
Show resolved Hide resolved
private def hello : String
"hello world"
end

protected def hello : String
"hello world"
end
CRYSTAL
end

it "passes if a protected method doesn't have a return type" do
expect_no_issues rule, <<-CRYSTAL
protected def hello
"hello world"
end
CRYSTAL
end

it "fails if a public or private method doesn't have a return type" do
expect_issue rule, <<-CRYSTAL
def hello
# ^^^^^ error: Method should have a return type restriction
"hello world"
end

private def hello
# ^^^^^ error: Method should have a return type restriction
"hello world"
end
CRYSTAL
end
end

context "#protected_methods" do
rule = MethodReturnTypeRestriction.new
rule.protected_methods = true

it "passes if a method has a return type" do
expect_no_issues rule, <<-CRYSTAL
protected def hello : String
"hello world"
end
CRYSTAL
end

it "passes if a private method doesn't have a return type" do
expect_no_issues rule, <<-CRYSTAL
private def hello
"hello world"
end
CRYSTAL
end

it "fails if a public or protected method doesn't have a return type" do
expect_issue rule, <<-CRYSTAL
def hello
# ^^^^^ error: Method should have a return type restriction
"hello world"
end

protected def hello
# ^^^^^ error: Method should have a return type restriction
"hello world"
end
CRYSTAL
end
end
end
end
61 changes: 61 additions & 0 deletions src/ameba/rule/typing/method_return_type_restriction.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
module Ameba::Rule::Typing
# A rule that enforces method definitions have a return type restriction.
#
# For example, these are considered valid:
#
# ```
# def hello : String
# "hello world"
# end
#
# def listen(a, b) : Int32
# 0
# end
# ```
#
# And these are considered invalid:
#
# ```
# def hello
# "hello world"
# end
#
# def listen(a, b)
# 0
# end
# ```
nobodywasishere marked this conversation as resolved.
Show resolved Hide resolved
#
# When the config options `PrivateMethods` and `ProtectedMethods`
# are true, this rule is also applied to private and protected methods, respectively.
#
# YAML configuration example:
#
# ```
# Typing/MethodReturnTypeRestriction:
# Enabled: false
# PrivateMethods: false
# ProtectedMethods: false
# ```
class MethodReturnTypeRestriction < Base
properties do
nobodywasishere marked this conversation as resolved.
Show resolved Hide resolved
description "Recommends that methods have a return type restriction"
enabled false
private_methods false
protected_methods false
end

MSG = "Method should have a return type restriction"

def test(source, node : Crystal::Def)
return if node.return_type || valid?(node)

issue_for node, MSG, prefer_name_location: true
nobodywasishere marked this conversation as resolved.
Show resolved Hide resolved
end

def valid?(node : Crystal::ASTNode) : Bool
(!private_methods? && node.visibility.private?) ||
(!protected_methods? && node.visibility.protected?) ||
false
end
nobodywasishere marked this conversation as resolved.
Show resolved Hide resolved
end
end
Loading