Skip to content

Commit

Permalink
Add Typing/MethodReturnTypeRestriction (#519)
Browse files Browse the repository at this point in the history
* Add `Typing/MethodReturnTypeRestriction`

* Refactor specs to put enabled options in contexts

* Apply suggestions from code review

Co-authored-by: Sijawusz Pur Rahnama <[email protected]>

* Apply suggestions from code review

Co-authored-by: Sijawusz Pur Rahnama <[email protected]>

* Fix specs

* Remove undocumented config option

* Apply suggestions from code review

Co-authored-by: Sijawusz Pur Rahnama <[email protected]>

* Fix specs

* Update spec messages

* Apply suggestions from code review

Co-authored-by: Sijawusz Pur Rahnama <[email protected]>

* Update src/ameba/rule/typing/method_return_type_restriction.cr

---------

Co-authored-by: Sijawusz Pur Rahnama <[email protected]>
  • Loading branch information
nobodywasishere and Sija authored Dec 29, 2024
1 parent 870a60f commit bde34f4
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 0 deletions.
122 changes: 122 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,122 @@
require "../../../spec_helper"

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

it "passes if a method has a return type restriction" do
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 restriction" do
expect_no_issues subject, <<-CRYSTAL
private def hello
"hello world"
end
protected def hello
"hello world"
end
CRYSTAL
end

it "fails if a public method doesn't have a return type restriction" 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 restriction" do
expect_no_issues rule, <<-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 protected method doesn't have a return type restriction" 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 restriction" 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 restriction" 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 restriction" 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 restriction" 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
52 changes: 52 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,52 @@
module Ameba::Rule::Typing
# A rule that enforces method definitions have a return type restriction.
#
# For example, this are considered invalid:
#
# ```
# def hello(name = "World")
# "Hello #{name}"
# end
# ```
#
# And this is valid:
#
# ```
# def hello(name = "World") : String
# "Hello #{name}"
# end
# ```
#
# 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
since_version "1.7.0"
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)
issue_for node, MSG unless valid_return_type?(node)
end

def valid_return_type?(node : Crystal::ASTNode) : Bool
!!node.return_type ||
(node.visibility.private? && !private_methods?) ||
(node.visibility.protected? && !protected_methods?)
end
end
end

0 comments on commit bde34f4

Please sign in to comment.