Permalink
Browse files

New rule: LongLineRule

  • Loading branch information...
ryuichis committed Jun 21, 2017
1 parent 8cee34b commit fa2808a2bd999658bd4e4ec143cecf8b4ec851fa
View
@@ -1,6 +1,7 @@
lint:
rule-configurations:
- NESTED_CODE_BLOCK_DEPTH: 6
- LONG_LINE: 120
severity-thresholds:
- critical: 0
- major: 0
@@ -127,3 +127,35 @@ func example(
##### References:
Fowler, Martin (1999). *Refactoring: Improving the design of existing code.* Addison Wesley.
## Long Line
<dl>
<dt>Identifier</dt>
<dd>long_line</dd>
<dt>File name</dt>
<dd>LongLineRule.swift</dd>
<dt>Severity</dt>
<dd>Minor</dd>
<dt>Category</dt>
<dd>Readability</dd>
</dl>
When a line of code is very long, it largely harms the readability.
Break long lines of code into multiple lines.
##### Thresholds:
<dl>
<dt>LONG_LINE</dt>
<dd>The long line reporting threshold, default value is 100.</dd>
</dl>
##### Examples:
###### Example 1
```
let a012345678901234567890123456789...1234567890123456789012345678901234567890123456789
```
@@ -127,3 +127,35 @@ func example(
##### References:
Fowler, Martin (1999). *Refactoring: Improving the design of existing code.* Addison Wesley.
## Long Line
<dl>
<dt>标识名</dt>
<dd>long_line</dd>
<dt>文件名</dt>
<dd>LongLineRule.swift</dd>
<dt>严重级别</dt>
<dd>Minor</dd>
<dt>分类</dt>
<dd>Readability</dd>
</dl>
When a line of code is very long, it largely harms the readability.
Break long lines of code into multiple lines.
##### Thresholds:
<dl>
<dt>LONG_LINE</dt>
<dd>The long line reporting threshold, default value is 100.</dd>
</dl>
##### Examples:
###### Example 1
```
let a012345678901234567890123456789...1234567890123456789012345678901234567890123456789
```
@@ -127,3 +127,35 @@ func example(
##### References:
Fowler, Martin (1999). *Refactoring: Improving the design of existing code.* Addison Wesley.
## Long Line
<dl>
<dt>識別子</dt>
<dd>long_line</dd>
<dt>ファイル名</dt>
<dd>LongLineRule.swift</dd>
<dt>激しさ</dt>
<dd>Minor</dd>
<dt>分類</dt>
<dd>Readability</dd>
</dl>
When a line of code is very long, it largely harms the readability.
Break long lines of code into multiple lines.
##### Thresholds:
<dl>
<dt>LONG_LINE</dt>
<dd>The long line reporting threshold, default value is 100.</dd>
</dl>
##### Examples:
###### Example 1
```
let a012345678901234567890123456789...1234567890123456789012345678901234567890123456789
```
@@ -0,0 +1,61 @@
/*
Copyright 2017 Ryuichi Saito, LLC and the Yanagiba project contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
class LongLineRule : RuleBase, SourceCodeRule {
static let ThresholdKey = "LONG_LINE"
static let DefaultThreshold = 100
let name = "Long Line"
var description: String? {
return """
When a line of code is very long, it largely harms the readability.
Break long lines of code into multiple lines.
"""
}
var examples: [String]? {
return [
"let a012345678901234567890123456789...1234567890123456789012345678901234567890123456789",
]
}
var thresholds: [String: String]? {
return [
LongLineRule.ThresholdKey:
"The long line reporting threshold, default value is \(LongLineRule.DefaultThreshold)."
]
}
let severity = Issue.Severity.minor
let category = Issue.Category.readability
private func getThreshold(of lineNumber: Int) -> Int {
return getConfiguration(
forKey: LongLineRule.ThresholdKey,
atLineNumber: lineNumber,
orDefault: LongLineRule.DefaultThreshold)
}
func inspect(line: String, lineNumber: Int) {
let threshold = getThreshold(of: lineNumber)
let lineCount = line.count
guard lineCount > threshold else {
return
}
emitIssue(
lineNumber,
description: "Line with \(lineCount) characters exceeds limit of \(threshold)")
}
}
@@ -35,6 +35,7 @@ public struct RuleSet {
RedundantVariableDeclarationKeywordRule(),
RedundantEnumCaseStringValueRule(),
TooManyParametersRule(),
LongLineRule(),
]
public static var ruleIdentifiers: [String] {
@@ -24,15 +24,40 @@ protocol SourceCodeRule : Rule {
}
extension SourceCodeRule where Self : RuleBase {
private var lines: [String] {
guard let astContext = astContext else {
return []
}
return astContext.sourceFile.content.components(separatedBy: .newlines)
}
func inspect(_ astContext: ASTContext, configurations: [String: Any]? = nil) {
self.astContext = astContext
self.configurations = configurations
let sourceContent = astContext.sourceFile.content
let lines = sourceContent.components(separatedBy: .newlines)
for (lineNumber, line) in lines.enumerated() {
inspect(line: line, lineNumber: lineNumber + 1)
}
}
func emitIssue(
_ lineNumber: Int,
description: String,
correction: Correction? = nil
) {
guard lineNumber > 0 && lineNumber <= lines.count,
let path = astContext?.sourceFile.path
else {
return
}
let lineIndex = lineNumber - 1
let line = lines[lineIndex]
let sourceRange = SourceRange(
start: SourceLocation(path: path, line: lineNumber, column: 1),
end: SourceLocation(path: path, line: lineNumber, column: line.count)
)
emitIssue(sourceRange, description: description, correction: correction)
}
}
@@ -0,0 +1,72 @@
/*
Copyright 2017 Ryuichi Saito, LLC and the Yanagiba project contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import XCTest
@testable import Lint
class LongLineRuleTests : XCTestCase {
func testShortText() {
XCTAssertTrue(getIssues(from: """
let a
b
""").isEmpty)
}
func testLongText() {
let issues = getIssues(from: """
let a = b
foo() {}
""")
XCTAssertEqual(issues.count, 2)
let issue0 = issues[0]
XCTAssertEqual(issue0.ruleIdentifier, "long_line")
XCTAssertEqual(issue0.description, "Line with 9 characters exceeds limit of 5")
XCTAssertEqual(issue0.category, .readability)
XCTAssertEqual(issue0.severity, .minor)
let range0 = issue0.location
XCTAssertEqual(range0.start.path, "test/test")
XCTAssertEqual(range0.start.line, 1)
XCTAssertEqual(range0.start.column, 1)
XCTAssertEqual(range0.end.path, "test/test")
XCTAssertEqual(range0.end.line, 1)
XCTAssertEqual(range0.end.column, 9)
let issue1 = issues[1]
XCTAssertEqual(issue1.ruleIdentifier, "long_line")
XCTAssertEqual(issue1.description, "Line with 8 characters exceeds limit of 5")
XCTAssertEqual(issue1.category, .readability)
XCTAssertEqual(issue1.severity, .minor)
let range1 = issue1.location
XCTAssertEqual(range1.start.path, "test/test")
XCTAssertEqual(range1.start.line, 2)
XCTAssertEqual(range1.start.column, 1)
XCTAssertEqual(range1.end.path, "test/test")
XCTAssertEqual(range1.end.line, 2)
XCTAssertEqual(range1.end.column, 8)
}
private func getIssues(from content: String) -> [Issue] {
return content.inspect(
withRule: LongLineRule(),
configurations: [LongLineRule.ThresholdKey: 5]
)
}
static var allTests = [
("testShortText", testShortText),
("testLongText", testLongText),
]
}
@@ -38,6 +38,7 @@ public func allTests() -> [XCTestCaseEntry] {
testCase(RedundantVariableDeclarationKeywordRuleTests.allTests),
testCase(RedundantEnumCaseStringValueRuleTests.allTests),
testCase(TooManyParametersRuleTests.allTests),
testCase(LongLineRuleTests.allTests),
]
}
#endif

0 comments on commit fa2808a

Please sign in to comment.