Skip to content

Repository files navigation

Swift GitHub license Twitter

MauriUtils

A tiny, zero-dependency Swift package of the helpers you end up rewriting in every project: file decoding, collection math, and a lightweight MVVM binding primitive.

  • Platforms: iOS 18+ / macOS 10.15+
  • Swift tools: 6.0+

Installation

Swift Package Manager. Add it in Xcode via File → Add Packages… with https://github.com/mchirino89/MauriUtils, or in your Package.swift:

dependencies: [
    .package(url: "https://github.com/mchirino89/MauriUtils", from: "2.0.0")
]

What's inside

File reading & decoding

FileReader reads bundled or on-disk files and decodes JSON/plist straight into your Decodable models.

let reader = FileReader()

// Raw data from the app bundle (defaults to .json)
let data = reader.read(from: "config")

// Decode a bundled JSON file in one call
let user: User = try reader.decodeJSON(from: "user")

// Decode a bundled plist
let settings: Settings = try reader.decodePlist(from: "Settings")

// Read a UTF-8 text file at an absolute path
let raw = reader.readText(atPath: "/tmp/interview.csv")

Need finer control? JSONDecodable.map and PlistDecodable.map decode raw Data with custom key/date strategies:

let model: Model = try JSONDecodable.map(input: data,
                                         with: .convertFromSnakeCase,
                                         dateDecoding: .iso8601)

Both throw DecodeException (.notFound / .unparseable) so failures are explicit.

Delimited text (CSV & friends)

DelimitedText splits plain-text datasets into lines or trimmed field rows.

DelimitedText.lines(raw)              // non-empty lines
DelimitedText.rows(raw)               // comma-separated fields
DelimitedText.rows(raw, separator: "\t")

Naive splitter — no quoted-field/embedded-delimiter handling. Fine for clean datasets; reach for a real RFC-4180 parser if your cells contain quoted commas.

Sequence & Array helpers

[3.0, 4.0, 5.0].average             // 4.0
[1, 2, 2, 3].numberOfOccurrences(of: 2)   // 2
[1, 2, 3, 4].count(where: { $0 > 2 })     // 2
[1, 2, 3].sum                       // 6

[Int].generateRandomElements(arraySize: 5)

var list = [1, 2, 3]
list.rearrange(from: 0, to: 2)      // [2, 3, 1]
list.mergeElements(newElements: [3, 4])   // [2, 3, 1, 4] (dedupes)
list.removing(2)                    // returns a copy without 2
list.isSingleElement                // false

MVVM binding

Dynamic<T> is a minimal observable box; DataSource<T> wraps a dynamic array for table/collection views.

let name = Dynamic("")
name.update { print("changed to \($0)") }
name.value = "Mauricio"   // fires the listener

let source = DataSource<Row>()
source.data.update { rows in /* reload UI */ }

Main-thread helper

executeMainThreadUpdate {
    // runs now if already on main, otherwise dispatched to it
}

Contributing

Pull requests welcome — I'll happily review them. Thanks!

About

Includes some of the most basic and used commonly written features in everyday Swift development

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages