-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
Typing/MethodReturnTypeRestriction
(#519)
* 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
1 parent
870a60f
commit bde34f4
Showing
2 changed files
with
174 additions
and
0 deletions.
There are no files selected for viewing
122 changes: 122 additions & 0 deletions
122
spec/ameba/rule/typing/method_return_type_restriction_spec.cr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |