All Projects → leavez → Mappable

leavez / Mappable

Licence: MIT license
flexible JSON to Model converter, specially optimized for immutable properties

Programming Languages

swift
15916 projects
ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Mappable

Fasteasymapping
A tool for fast serializing & deserializing of JSON
Stars: ✭ 556 (+1959.26%)
Mutual labels:  mapping, deserialization
Handyjson
A handy swift json-object serialization/deserialization library
Stars: ✭ 3,913 (+14392.59%)
Mutual labels:  mapping, deserialization
CodableWrapper
@codec("encoder", "decoder") var cool: Bool = true
Stars: ✭ 143 (+429.63%)
Mutual labels:  mapping, deserialization
Static Frame
Immutable and grow-only Pandas-like DataFrames with a more explicit and consistent interface.
Stars: ✭ 217 (+703.7%)
Mutual labels:  immutable, mapping
nim-contra
Lightweight Self-Documenting Design by Contract Programming and Security Hardened mode.
Stars: ✭ 46 (+70.37%)
Mutual labels:  immutable
geemap-apps
Interactive web apps created using geemap and streamlit
Stars: ✭ 24 (-11.11%)
Mutual labels:  mapping
android
Where you can find everything Android from Mapzen
Stars: ✭ 106 (+292.59%)
Mutual labels:  mapping
parco
🏇🏻 generalist, fast and tiny binary parser and compiler generator, powered by Go 1.18+ Generics
Stars: ✭ 57 (+111.11%)
Mutual labels:  deserialization
keystore-go
A Go (golang) implementation of Java KeyStore encoder/decoder
Stars: ✭ 119 (+340.74%)
Mutual labels:  decoder
axmldec
Stand-alone binary AndroidManifest.xml decoder
Stars: ✭ 151 (+459.26%)
Mutual labels:  decoder
CesiumJs3DTileServer
cesiumgis.com/
Stars: ✭ 25 (-7.41%)
Mutual labels:  mapping
react-antd
基于react + redux + immutable + less + ES6/7 + webpack2.0 + fetch + react-router + antd实现的SPA后台管理系统模板
Stars: ✭ 320 (+1085.19%)
Mutual labels:  immutable
boutique
Immutable data storage
Stars: ✭ 44 (+62.96%)
Mutual labels:  immutable
readsb
ADS-B decoder swiss knife
Stars: ✭ 114 (+322.22%)
Mutual labels:  decoder
lazyjsonmapper
Advanced, intelligent & automatic object-oriented JSON containers for PHP.
Stars: ✭ 48 (+77.78%)
Mutual labels:  deserialization
babl
JSON templating on steroids
Stars: ✭ 29 (+7.41%)
Mutual labels:  immutable
qrcode-decoder
🤘Tool for decoding qrcode by image,video or camera.
Stars: ✭ 78 (+188.89%)
Mutual labels:  decoder
Accessors.jl
Update immutable data
Stars: ✭ 73 (+170.37%)
Mutual labels:  immutable
kirby-map-field
🗺 An easy way to use maps and location data in Kirby.
Stars: ✭ 41 (+51.85%)
Mutual labels:  mapping
alphabetical-sorter
VScode extension - For variable alphabetical re-order
Stars: ✭ 30 (+11.11%)
Mutual labels:  let

Mappable

Swift Swift Package Manager Build Status Codecov branch

Mappable is a lightweight, flexible, easy-to-use framework to convert JSON to model, specially optimized for immutable property initialization.

struct Flight: Mappable {
    let number: String
    let time: Date
    
    init(map: Mapper) throws {

        // with the help of @dynamicMemberLookup feature
        number = try map.id()
        time   = try map.time()

        // or use the old way
        // number = try map.from("id")
        // time   = try map.from("time")
    }
}
// Flight(JSONString: json)

A xcode plugin is also provided to genereate implementation automatically.

Features

  • JSON to object by just specifying mapping relationships
  • Optimized for immutable and optional
  • Flexible: easy to mix with manual initailization
  • Compatible types conversion : e.g. a Int property could be initialized with String value
  • Key path support

Why Another?

Most JSON to model libraries cannot handle immutable property initialization well. They require to declare properties with var and nullable types, which break the sprint of Swift and lead to bad code. Mappable was born for solving this problem.

Pros Cons
Codable - Native in Swift
- Automatic (no mapping relationships)
- support 2-direction conversion
- Inflexible
- Doesn't support inherented class
HandyJSON - Automatic (no mapping relationships)
- 2-direction conversion
No immutable properties support
ObjectMapper 2-direction conversion - Immutable properties support is weak*
- Multiple partterns led to chaos
- Missing support for some combinations of types.
SwiftyJSON Not a JSON object convertor.
It's only a convenient tool to deal with JSON data.

* 1) Cannot handle optional conveniently. 2) Doesn't support of compatible types conversion, which fall the whole object for every small mal-format in JSON.

Mappable is highly inspired by ObjectMapper. You could tread Mappable as an improved version of ImmutableMappable in ObjectMapper.

Usage

The basics

To support mapping, a type should implement Mappable protocol, which have only an initializer method:

class Country: Mappable {
    let name: String
    let cities: [City]   // struct City: Mappable { ... }
    let atContinent: Continent // enum Continent: Mappable { ... }
    
    required init(map: Mapper) throws {
        name        = try map.from("name")
        cities      = try map.from("city")
        atContinent = try map.from("location.continent")
    }
}

You just need write the mapping relationship: a key path for a property. Although these lines are just normal assignment statements, types aren't needed to specified, so you could tread these lines as a special representation of mapping relationships. (You could read the line as "try (to) map (value) from XXX" 😆 )

Then you could initialize a object like this:

// NOTE: these initializer throw errors, you should do error handling
let c = try Country(JSON: jsonDict)
let d = try? Country(JSONString: jsonString)

Supported types

  • Primitive types: Int, Double, String, Bool, URL, Date ...
  • Container types: Array, Dictionary, Set
  • Optional type
  • Enum, Struct, Object
  • Any combination of the types above

Default value

// just use `??`
cities = try map.from("city") ?? []

Optional handling

Optional types won't throw an error even if there's no corresponding date in JSON or the date is in mal-format. A nil will be assigned in this situation.

If you declare a property as an optional, it may mean this data isn't strictly required in JSON. So you wish to get a nil value if there's no data actually.

struct User: Mappable {
    let ID: String
    let summary: String?
    
    init(map: Mapper) throws {
        ID      = try map.from("id")
        summary = try map.from("summary")
    }
}
let json = ["id": "a123"]
let user = try! User(JSONObject: json) // It won't crash.

Compatible types conversion

Convert from
Int, Double, Float, CGFloat String
Bool Int, "true", "True", "TRUE", "YES", "false", "False", "FALSE", "NO", "0", "1"
String Int, NSNumber
URL String
Date Double(secondsSince1970), String (RFC 3339, e.g. 2016-06-13T16:00:00+00:00)

More detail at here.

Custom conversion

The content in initializer is just plain assignment, so you could do anything with the data. Use map.getRootValue() and map.getValue(keyPath:) to the get the raw JSON value and do what you want.

For convenient date conversion, there's also a options property in Mapper to set custom date strategy. (More complex example here)

Enum

Enums conforming RawRepresentable have a default implementation of Mappable. You just need to declare the conforming of Mappable to your enum types, then it will work.

For enum with associated values, you could do the manual implementation:

enum EnumWithValues: Mappable {
    case a(Int)
    case b(String)
    
    init(map: Mapper) throws {
        // It could be initialized with a json date like:
        // {"type": "a", value: 123}
        let value = try map.getValue("type", as: String.self)
        switch value {
        case "a":
            self = .a(try map.from("value"))
        case "b":
            self = .b(try map.from("value"))
        default:
            throw ErrorType.JSONStructureNotMatchDesired(value, "string a/b")
        }
    }
}

Class inheritance

class ChildModel: BaseModel {
    let b : Int
    required init(map: Mapper) throws {
        b = try map.from("b")
        try super.init(map: map)
    }
}

Nested key path

Use key path "AAA.BBB" to map a multi-level path value in JSON:

// let json = """ {"AAA": {"BBB": 1}} """
b = try map.from("AAA.BBB")

// use `n` to get a n-th value in array
// let json = """ {"AAA": [11,22,33]} """
b = try map.from("AAA.`2`") // b = 33

If a normal key contains . naturally, you could use like map.from("a.file", keyPathIsNested: false), to treat the key as a single-level path.

Installation

  • for Swift 5 & 4.2 : v1.3+
  • for Swift 4.1 and below : v1.2.2

Cocoapods

pod 'Mappable'

Swift Package Manager

.Package(url: "https://github.com/leavez/Mappable.git", from: "1.5.0"),

Carthage

github "leavez/Mappable"

License

Mappable is available under the MIT license. See the LICENSE file for more info.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].