Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@crmitchelmore
Last active November 17, 2017 17:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crmitchelmore/793f4eae09309aa12c31c929d8efaabc to your computer and use it in GitHub Desktop.
Save crmitchelmore/793f4eae09309aa12c31c929d8efaabc to your computer and use it in GitHub Desktop.
Split model structs, enum, classes, extensions from 1 file to 1 per type. Types should be codable or regex will need changing
import Foundation
import PlaygroundSupport
let documentsDir = PlaygroundSupport.playgroundSharedDataDirectory
let fileManager = FileManager()
extension String {
subscript (bounds: CountableClosedRange<Int>) -> String {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return String(self[start...end])
}
subscript (bounds: CountableRange<Int>) -> String {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return String(self[start..<end])
}
}
enum BlockType {
static let regex = try! NSRegularExpression(pattern: "(.+?)(?=\n\\})", options: .dotMatchesLineSeparators)
case anExtension(String)
case aStruct(String)
case anEnum(String)
case aClass(String)
static var regexPairs: [(BlockType, NSRegularExpression)] {
return [
(BlockType.aStruct(""), try! NSRegularExpression(pattern: "struct (.+):", options: [])),
(BlockType.aClass(""), try! NSRegularExpression(pattern: "class (.+):", options: [])),
(BlockType.anExtension(""), try! NSRegularExpression(pattern: "extension (.+?)[: ]", options: [])),
(BlockType.anEnum(""), try! NSRegularExpression(pattern: "enum (.+?)[: ]", options: []))
]
}
var name: String {
switch self {
case .anExtension(let name):
return name
case .aStruct(let name):
return name
case .anEnum(let name):
return name
case .aClass(let name):
return name
}
}
var shouldHaveNewFile: Bool {
switch self {
case .anExtension(_):
return false
default:
return true
}
}
private func changeName(to name: String) -> BlockType {
switch self {
case .anExtension(_):
return .anExtension(name)
case .aStruct(_):
return .aStruct(name)
case .anEnum(_):
return .anEnum(name)
case .aClass(_):
return .aClass(name)
}
}
init?(block: String) {
var selfType: BlockType?
for (blockType, regex) in BlockType.regexPairs {
if let match = regex.matches(in: block, options: [], range: NSRange(location: 0, length: block.count)).first {
let range = match.range(at: 1)
selfType = blockType.changeName(to: (block[range.lowerBound..<range.upperBound]))
break
}
}
guard let type = selfType else { return nil }
self = type
}
}
func processBlock(_ block: String, folder: URL) {
if let blockType = BlockType(block: block) {
addText(text: makeEverythingPublicIn(block: block), toFileName: "\(blockType.name).swift", createFile: blockType.shouldHaveNewFile, folder: folder)
}
}
func makeEverythingPublicIn(block: String) -> String {
let lines = block.components(separatedBy: "\n")
let publicTypes = ["struct ", "class ", "enum ", "let ", "var ", "func "]
let ignoreKeywords = ["public ", "private ", "if ", "guard ", " try"]
let outputLines: [String] = lines.map { line in
for type in publicTypes where line.contains(type) {
if ignoreKeywords.filter({ keyword in line.contains(keyword)}).count == 0 {
return line.replacingOccurrences(of: type, with: "public \(type)")
}
}
return line
}
return outputLines.joined(separator: "\n")
}
func addText(text: String, toFileName: String, createFile: Bool, folder: URL) {
var data: Data?
let fileUrl = folder.appendingPathComponent(toFileName)
if let existingText = try? String(contentsOf: fileUrl, encoding: .utf8), !createFile {
data = Data((existingText + "\n" + text).utf8)
} else {
data = Data(("import Foundation" + text).utf8)
}
try? data?.write(to: fileUrl)
}
do {
let fileName = "LoyaltyCheckoutOffer.swift"
let fileUrl = documentsDir.appendingPathComponent(fileName)
let folder = documentsDir.appendingPathComponent(fileName.replacingOccurrences(of: ".swift", with: "")).appendingPathComponent("Models")
try fileManager.createDirectory(at: folder, withIntermediateDirectories: true, attributes: nil)
let text = try String(contentsOf: fileUrl, encoding: .utf8)
let matches = BlockType.regex.matches(in: text, options: [], range: NSRange(location: 0, length: text.count))
for match in matches {
let range = match.range(at: 0)
processBlock(text[(range.lowerBound + 2)..<range.upperBound] + "\n}", folder: folder)
}
} catch {
print(error)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment