         name: "Closure End Indentation",
         description: "Closure end should have the same indentation as the line that started it.",
         kind: .style,
-        nonTriggeringExamples: [
-            "SignalProducer(values: [1, 2, 3])\n" +
-            "   .startWithNext { number in\n" +
-            "       print(number)\n" +
-            "   }\n",
-            "[1, 2].map { $0 + 1 }\n",
-            "return match(pattern: pattern, with: [.comment]).flatMap { range in\n" +
-            "   return Command(string: contents, range: range)\n" +
-            "}.flatMap { command in\n" +
-            "   return command.expand()\n" +
-            "}\n",
-            "foo(foo: bar,\n" +
-            "    options: baz) { _ in }\n",
-            "someReallyLongProperty.chainingWithAnotherProperty\n" +
-            "   .foo { _ in }",
-            "foo(abc, 123)\n" +
-            "{ _ in }\n",
-            "function(\n" +
-            "    closure: { x in\n" +
-            "        print(x)\n" +
-            "    },\n" +
-            "    anotherClosure: { y in\n" +
-            "        print(y)\n" +
-            "    })"
-        ],
-        triggeringExamples: [
-            "SignalProducer(values: [1, 2, 3])\n" +
-            "   .startWithNext { number in\n" +
-            "       print(number)\n" +
-            "↓}\n",
-            "return match(pattern: pattern, with: [.comment]).flatMap { range in\n" +
-            "   return Command(string: contents, range: range)\n" +
-            "   ↓}.flatMap { command in\n" +
-            "   return command.expand()\n" +
-            "↓}\n",
-            "function(\n" +
-            "    closure: { x in\n" +
-            "        print(x)\n" +
-            "↓},\n" +
-            "    anotherClosure: { y in\n" +
-            "        print(y)\n" +
-            "↓})"
-        ]
+        nonTriggeringExamples: ClosureEndIndentationRuleExamples.nonTriggeringExamples,
+        triggeringExamples: ClosureEndIndentationRuleExamples.triggeringExamples
     )
 
     private static let notWhitespace = regex("[^\\s]")

            return []
        }

        var closureArguments = filterClosureArguments(dictionary.enclosedArguments, file: file)

        if hasTrailingClosure(in: file, dictionary: dictionary), !closureArguments.isEmpty {
            closureArguments.removeLast()
        }

        let argumentViolations = closureArguments.flatMap { dictionary in
            return validateClosureArgument(in: file, dictionary: dictionary)
        }

        let callViolations = validateCall(in: file, dictionary: dictionary)

        return argumentViolations + callViolations
    }

    private func hasTrailingClosure(in file: File,

        ]
    }

    func validateArguments(in file: File,
                           dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
        guard isFirstArgumentOnNewline(dictionary, file: file) else {
            return []
        }

        var closureArguments = filterClosureArguments(dictionary.enclosedArguments, file: file)

        if hasTrailingClosure(in: file, dictionary: dictionary), !closureArguments.isEmpty {
            closureArguments.removeLast()
        }

        let argumentViolations = closureArguments.flatMap { dictionary in
            return validateClosureArgument(in: file, dictionary: dictionary)
        }

        return argumentViolations
    }

    private func validateClosureArgument(in file: File,
                                         dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
        let contents = file.contents.bridge()
