|
@@ -0,0 +1,297 @@
|
|
|
+// MIT License
|
|
|
+//
|
|
|
+// Copyright (c) 2017-2019 MessageKit
|
|
|
+//
|
|
|
+// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
+// of this software and associated documentation files (the "Software"), to deal
|
|
|
+// in the Software without restriction, including without limitation the rights
|
|
|
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
+// copies of the Software, and to permit persons to whom the Software is
|
|
|
+// furnished to do so, subject to the following conditions:
|
|
|
+//
|
|
|
+// The above copyright notice and this permission notice shall be included in all
|
|
|
+// copies or substantial portions of the Software.
|
|
|
+//
|
|
|
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
+// SOFTWARE.
|
|
|
+
|
|
|
+import Foundation
|
|
|
+
|
|
|
+// MARK: - Lorem
|
|
|
+
|
|
|
+public class Lorem {
|
|
|
+ // MARK: Public
|
|
|
+
|
|
|
+ /// Return a random word.
|
|
|
+ ///
|
|
|
+ /// - returns: Returns a random word.
|
|
|
+ public class func word() -> String {
|
|
|
+ wordList.random()!
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Return an array of `count` words.
|
|
|
+ ///
|
|
|
+ /// - parameter count: The number of words to return.
|
|
|
+ ///
|
|
|
+ /// - returns: Returns an array of `count` words.
|
|
|
+ public class func words(nbWords: Int = 3) -> [String] {
|
|
|
+ wordList.random(nbWords)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Return a string of `count` words.
|
|
|
+ ///
|
|
|
+ /// - parameter count: The number of words the string should contain.
|
|
|
+ ///
|
|
|
+ /// - returns: Returns a string of `count` words.
|
|
|
+ public class func words(nbWords: Int = 3) -> String {
|
|
|
+ words(nbWords: nbWords).joined(separator: " ")
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Generate a sentence of `nbWords` words.
|
|
|
+ /// - parameter nbWords: The number of words the sentence should contain.
|
|
|
+ /// - parameter variable: If `true`, the number of words will vary between
|
|
|
+ /// +/- 40% of `nbWords`.
|
|
|
+ /// - returns:
|
|
|
+ public class func sentence(nbWords: Int = 6, variable: Bool = true) -> String {
|
|
|
+ if nbWords <= 0 {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+
|
|
|
+ let result: String = words(nbWords: variable ? nbWords.randomize(variation: 40) : nbWords)
|
|
|
+
|
|
|
+ return result.firstCapitalized + "."
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Generate an array of sentences.
|
|
|
+ /// - parameter nbSentences: The number of sentences to generate.
|
|
|
+ ///
|
|
|
+ /// - returns: Returns an array of random sentences.
|
|
|
+ public class func sentences(nbSentences: Int = 3) -> [String] {
|
|
|
+ (0 ..< nbSentences).map { _ in sentence() }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Generate a paragraph with `nbSentences` random sentences.
|
|
|
+ /// - parameter nbSentences: The number of sentences the paragraph should
|
|
|
+ /// contain.
|
|
|
+ /// - parameter variable: If `true`, the number of sentences will vary
|
|
|
+ /// between +/- 40% of `nbSentences`.
|
|
|
+ /// - returns: Returns a paragraph with `nbSentences` random sentences.
|
|
|
+ public class func paragraph(nbSentences: Int = 3, variable: Bool = true) -> String {
|
|
|
+ if nbSentences <= 0 {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+
|
|
|
+ return sentences(nbSentences: variable ? nbSentences.randomize(variation: 40) : nbSentences).joined(separator: " ")
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Generate an array of random paragraphs.
|
|
|
+ /// - parameter nbParagraphs: The number of paragraphs to generate.
|
|
|
+ /// - returns: Returns an array of `nbParagraphs` paragraphs.
|
|
|
+ public class func paragraphs(nbParagraphs: Int = 3) -> [String] {
|
|
|
+ (0 ..< nbParagraphs).map { _ in paragraph() }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Generate a string of random paragraphs.
|
|
|
+ /// - parameter nbParagraphs: The number of paragraphs to generate.
|
|
|
+ /// - returns: Returns a string of random paragraphs.
|
|
|
+ public class func paragraphs(nbParagraphs: Int = 3) -> String {
|
|
|
+ paragraphs(nbParagraphs: nbParagraphs).joined(separator: "\n\n")
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Generate a string of at most `maxNbChars` characters.
|
|
|
+ /// - parameter maxNbChars: The maximum number of characters the string
|
|
|
+ /// should contain.
|
|
|
+ /// - returns: Returns a string of at most `maxNbChars` characters.
|
|
|
+ public class func text(maxNbChars: Int = 200) -> String {
|
|
|
+ var result: [String] = []
|
|
|
+
|
|
|
+ if maxNbChars < 5 {
|
|
|
+ return ""
|
|
|
+ } else if maxNbChars < 25 {
|
|
|
+ while result.count == 0 {
|
|
|
+ var size = 0
|
|
|
+
|
|
|
+ while size < maxNbChars {
|
|
|
+ let w = (size != 0 ? " " : "") + word()
|
|
|
+ result.append(w)
|
|
|
+ size += w.count
|
|
|
+ }
|
|
|
+
|
|
|
+ _ = result.popLast()
|
|
|
+ }
|
|
|
+ } else if maxNbChars < 100 {
|
|
|
+ while result.count == 0 {
|
|
|
+ var size = 0
|
|
|
+
|
|
|
+ while size < maxNbChars {
|
|
|
+ let s = (size != 0 ? " " : "") + sentence()
|
|
|
+ result.append(s)
|
|
|
+ size += s.count
|
|
|
+ }
|
|
|
+
|
|
|
+ _ = result.popLast()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ while result.count == 0 {
|
|
|
+ var size = 0
|
|
|
+
|
|
|
+ while size < maxNbChars {
|
|
|
+ let p = (size != 0 ? "\n" : "") + paragraph()
|
|
|
+ result.append(p)
|
|
|
+ size += p.count
|
|
|
+ }
|
|
|
+
|
|
|
+ _ = result.popLast()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result.joined(separator: "")
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: Private
|
|
|
+
|
|
|
+ private static let wordList = [
|
|
|
+ "alias", "consequatur", "aut", "perferendis", "sit", "voluptatem",
|
|
|
+ "accusantium", "doloremque", "aperiam", "eaque", "ipsa", "quae", "ab",
|
|
|
+ "illo", "inventore", "veritatis", "et", "quasi", "architecto",
|
|
|
+ "beatae", "vitae", "dicta", "sunt", "explicabo", "aspernatur", "aut",
|
|
|
+ "odit", "aut", "fugit", "sed", "quia", "consequuntur", "magni",
|
|
|
+ "dolores", "eos", "qui", "ratione", "voluptatem", "sequi", "nesciunt",
|
|
|
+ "neque", "dolorem", "ipsum", "quia", "dolor", "sit", "amet",
|
|
|
+ "consectetur", "adipisci", "velit", "sed", "quia", "non", "numquam",
|
|
|
+ "eius", "modi", "tempora", "incidunt", "ut", "labore", "et", "dolore",
|
|
|
+ "magnam", "aliquam", "quaerat", "voluptatem", "ut", "enim", "ad",
|
|
|
+ "minima", "veniam", "quis", "nostrum", "exercitationem", "ullam",
|
|
|
+ "corporis", "nemo", "enim", "ipsam", "voluptatem", "quia", "voluptas",
|
|
|
+ "sit", "suscipit", "laboriosam", "nisi", "ut", "aliquid", "ex", "ea",
|
|
|
+ "commodi", "consequatur", "quis", "autem", "vel", "eum", "iure",
|
|
|
+ "reprehenderit", "qui", "in", "ea", "voluptate", "velit", "esse",
|
|
|
+ "quam", "nihil", "molestiae", "et", "iusto", "odio", "dignissimos",
|
|
|
+ "ducimus", "qui", "blanditiis", "praesentium", "laudantium", "totam",
|
|
|
+ "rem", "voluptatum", "deleniti", "atque", "corrupti", "quos",
|
|
|
+ "dolores", "et", "quas", "molestias", "excepturi", "sint",
|
|
|
+ "occaecati", "cupiditate", "non", "provident", "sed", "ut",
|
|
|
+ "perspiciatis", "unde", "omnis", "iste", "natus", "error",
|
|
|
+ "similique", "sunt", "in", "culpa", "qui", "officia", "deserunt",
|
|
|
+ "mollitia", "animi", "id", "est", "laborum", "et", "dolorum", "fuga",
|
|
|
+ "et", "harum", "quidem", "rerum", "facilis", "est", "et", "expedita",
|
|
|
+ "distinctio", "nam", "libero", "tempore", "cum", "soluta", "nobis",
|
|
|
+ "est", "eligendi", "optio", "cumque", "nihil", "impedit", "quo",
|
|
|
+ "porro", "quisquam", "est", "qui", "minus", "id", "quod", "maxime",
|
|
|
+ "placeat", "facere", "possimus", "omnis", "voluptas", "assumenda",
|
|
|
+ "est", "omnis", "dolor", "repellendus", "temporibus", "autem",
|
|
|
+ "quibusdam", "et", "aut", "consequatur", "vel", "illum", "qui",
|
|
|
+ "dolorem", "eum", "fugiat", "quo", "voluptas", "nulla", "pariatur",
|
|
|
+ "at", "vero", "eos", "et", "accusamus", "officiis", "debitis", "aut",
|
|
|
+ "rerum", "necessitatibus", "saepe", "eveniet", "ut", "et",
|
|
|
+ "voluptates", "repudiandae", "sint", "et", "molestiae", "non",
|
|
|
+ "recusandae", "itaque", "earum", "rerum", "hic", "tenetur", "a",
|
|
|
+ "sapiente", "delectus", "ut", "aut", "reiciendis", "voluptatibus",
|
|
|
+ "maiores", "doloribus", "asperiores", "repellat",
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
+extension String {
|
|
|
+ var firstCapitalized: String {
|
|
|
+ var string = self
|
|
|
+ string.replaceSubrange(string.startIndex ... string.startIndex, with: String(string[string.startIndex]).capitalized)
|
|
|
+ return string
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension Array {
|
|
|
+ /// Shuffle the array in-place using the Fisher-Yates algorithm.
|
|
|
+ public mutating func shuffle() {
|
|
|
+ if count == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for i in 0 ..< (count - 1) {
|
|
|
+ let j = Int(arc4random_uniform(UInt32(count - i))) + i
|
|
|
+ if j != i {
|
|
|
+ swapAt(i, j)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Return a shuffled version of the array using the Fisher-Yates
|
|
|
+ /// algorithm.
|
|
|
+ ///
|
|
|
+ /// - returns: Returns a shuffled version of the array.
|
|
|
+ public func shuffled() -> [Element] {
|
|
|
+ var list = self
|
|
|
+ list.shuffle()
|
|
|
+
|
|
|
+ return list
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Return a random element from the array.
|
|
|
+ /// - returns: Returns a random element from the array or `nil` if the
|
|
|
+ /// array is empty.
|
|
|
+ public func random() -> Element? {
|
|
|
+ (count > 0) ? shuffled()[0] : nil
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Return a random subset of `cnt` elements from the array.
|
|
|
+ /// - returns: Returns a random subset of `cnt` elements from the array.
|
|
|
+ public func random(_ count: Int = 1) -> [Element] {
|
|
|
+ let result = shuffled()
|
|
|
+
|
|
|
+ return (count > result.count) ? result : Array(result[0 ..< count])
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension Int {
|
|
|
+ /// Return a random number between `min` and `max`.
|
|
|
+ /// - note: The maximum value cannot be more than `UInt32.max - 1`
|
|
|
+ ///
|
|
|
+ /// - parameter min: The minimum value of the random value (defaults to `0`).
|
|
|
+ /// - parameter max: The maximum value of the random value (defaults to `UInt32.max - 1`)
|
|
|
+ ///
|
|
|
+ /// - returns: Returns a random value between `min` and `max`.
|
|
|
+ public static func random(min: Int = 0, max: Int = Int.max) -> Int {
|
|
|
+ precondition(min <= max, "attempt to call random() with min > max")
|
|
|
+
|
|
|
+ let diff = UInt(bitPattern: max &- min)
|
|
|
+ let result = UInt.random(min: 0, max: diff)
|
|
|
+
|
|
|
+ return min + Int(bitPattern: result)
|
|
|
+ }
|
|
|
+
|
|
|
+ public func randomize(variation: Int) -> Int {
|
|
|
+ let multiplier = Double(Int.random(min: 100 - variation, max: 100 + variation)) / 100
|
|
|
+ let randomized = Double(self) * multiplier
|
|
|
+
|
|
|
+ return Int(randomized) + 1
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension UInt {
|
|
|
+ fileprivate static func random(min: UInt, max: UInt) -> UInt {
|
|
|
+ precondition(min <= max, "attempt to call random() with min > max")
|
|
|
+
|
|
|
+ if min == UInt.min, max == UInt.max {
|
|
|
+ var result: UInt = 0
|
|
|
+ arc4random_buf(&result, MemoryLayout.size(ofValue: result))
|
|
|
+
|
|
|
+ return result
|
|
|
+ } else {
|
|
|
+ let range = max - min + 1
|
|
|
+ let limit = UInt.max - UInt.max % range
|
|
|
+ var result: UInt = 0
|
|
|
+
|
|
|
+ repeat {
|
|
|
+ arc4random_buf(&result, MemoryLayout.size(ofValue: result))
|
|
|
+ } while result >= limit
|
|
|
+
|
|
|
+ result = result % range
|
|
|
+
|
|
|
+ return min + result
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|