Skip to content

Commit

Permalink
release initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
robert-virkus committed Nov 2, 2020
1 parent 5439c41 commit 206743f
Show file tree
Hide file tree
Showing 11 changed files with 439 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .gitignore
@@ -0,0 +1,13 @@
# Files and directories created by pub
.dart_tool/
.packages

# Omit commiting pubspec.lock for library packages:
# https://dart.dev/guides/libraries/private-files#pubspeclock
pubspec.lock

# Conventional directory for build outputs
build/

# Directory created by dartdoc
doc/api/
13 changes: 13 additions & 0 deletions .vscode/launch.json
@@ -0,0 +1,13 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "enough_serialization",
"request": "launch",
"type": "dart"
}
]
}
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -0,0 +1,3 @@
## 1.0.0

- Initial version
90 changes: 90 additions & 0 deletions README.md
@@ -0,0 +1,90 @@

Serialize to and deserialize from JSON in runtime.
This pure Dart library does not depend on build time generation.

## Installation

## Installation
Add this dependency your pubspec.yaml file:

```
dependencies:
enough_serialization: ^1.0.0
```
The latest version or `enough_serialization` is [![enough_serialization version](https://img.shields.io/pub/v/enough_serialization.svg)](https://pub.dartlang.org/packages/enough_serialization).


## Usage

A simple usage example:

```dart
import 'package:enough_serialization/enough_serialization.dart';
enum MySerializableEnum { value1, value2, value3 }
class MySerializable extends SerializableObject {
MySerializable() {
deserializers['my-list'] = () => <String>[];
deserializers['my-serializable'] = () => MySerializable();
transformers['my-enum'] = (value) => value is MySerializableEnum
? value.index
: MySerializableEnum.values[value];
}
MySerializableEnum get myEnum => attributes['my-enum'];
set myEnum(MySerializableEnum value) => attributes['my-enum'] = value;
int get myNumber => attributes['my-number'];
set myNumber(int value) => attributes['my-number'] = value;
String get myText => attributes['my-text'];
set myText(String value) => attributes['my-text'] = value;
List<String> get myList => attributes['my-list'];
set myList(List<String> value) => attributes['my-list'] = value;
MySerializable get myChild => attributes['my-serializable'];
set myChild(MySerializable value) => attributes['my-serializable'] = value;
}
void main() {
final json = serialize();
print('seralized: $json');
final deserialized = deserialize(json);
print('deserialized: $deserialized');
}
String serialize() {
final child = MySerializable()
..myText = 'hi this is the child element'
..myNumber = 23
..myChild = null;
final parent = MySerializable()
..myNumber = 13
..myEnum = MySerializableEnum.value2
..myText = 'Hello "World"'
..myList = ['one', 'two', 'three']
..myChild = child;
final serializer = Serializer();
final json = serializer.serialize(parent);
return json;
}
MySerializable deserialize(String json) {
final serializer = Serializer();
final mySerializable = MySerializable();
serializer.deserialize(json, mySerializable);
return mySerializable;
}
```

## Features and bugs

Please file feature requests and bugs at the [issue tracker][tracker].

[tracker]: https://github.com/Enough-Software/enough_serialization/issues

## License

Licensed under the [MIT License](LICENSE).
14 changes: 14 additions & 0 deletions analysis_options.yaml
@@ -0,0 +1,14 @@
# Defines a default set of lint rules enforced for
# projects at Google. For details and rationale,
# see https://github.com/dart-lang/pedantic#enabled-lints.
include: package:pedantic/analysis_options.yaml

# For lint rules and documentation, see http://dart-lang.github.io/linter/lints.
# Uncomment to specify additional rules.
# linter:
# rules:
# - camel_case_types

analyzer:
# exclude:
# - path/to/excluded/files/**
58 changes: 58 additions & 0 deletions example/enough_serialization_example.dart
@@ -0,0 +1,58 @@
import 'package:enough_serialization/enough_serialization.dart';

enum MySerializableEnum { value1, value2, value3 }

class MySerializable extends SerializableObject {
MySerializable() {
deserializers['my-list'] = () => <String>[];
deserializers['my-serializable'] = () => MySerializable();
transformers['my-enum'] = (value) => value is MySerializableEnum
? value.index
: MySerializableEnum.values[value];
}

MySerializableEnum get myEnum => attributes['my-enum'];
set myEnum(MySerializableEnum value) => attributes['my-enum'] = value;

int get myNumber => attributes['my-number'];
set myNumber(int value) => attributes['my-number'] = value;

String get myText => attributes['my-text'];
set myText(String value) => attributes['my-text'] = value;

List<String> get myList => attributes['my-list'];
set myList(List<String> value) => attributes['my-list'] = value;

MySerializable get myChild => attributes['my-serializable'];
set myChild(MySerializable value) => attributes['my-serializable'] = value;
}

void main() {
final json = serialize();
print('seralized: $json');
final deserialized = deserialize(json);
print('deserialized: $deserialized');
}

String serialize() {
final child = MySerializable()
..myText = 'hi this is the child element'
..myNumber = 23
..myChild = null;
final parent = MySerializable()
..myNumber = 13
..myEnum = MySerializableEnum.value2
..myText = 'Hello "World"'
..myList = ['one', 'two', 'three']
..myChild = child;
final serializer = Serializer();
final json = serializer.serialize(parent);
return json;
}

MySerializable deserialize(String json) {
final serializer = Serializer();
final mySerializable = MySerializable();
serializer.deserialize(json, mySerializable);
return mySerializable;
}
8 changes: 8 additions & 0 deletions lib/enough_serialization.dart
@@ -0,0 +1,8 @@
/// Support for doing something awesome.
///
/// More dartdocs go here.
library enough_serialization;

export 'src/serializable.dart';

// TODO: Export any libraries intended for clients of this package.
6 changes: 6 additions & 0 deletions lib/src/enough_serialization_base.dart
@@ -0,0 +1,6 @@
// TODO: Put public facing types in this file.

/// Checks if you are awesome. Spoiler: you are.
class Awesome {
bool get isAwesome => true;
}
142 changes: 142 additions & 0 deletions lib/src/serializable.dart
@@ -0,0 +1,142 @@
// Problems:
// - how to create class for a nested objects when de-serializing?
// -> possible solution: create "Serializable Function creator(String name)"
// -> but what if there are several hierarchies of nested objects?

import 'dart:convert';

abstract class Serializable {
Map<String, dynamic> get attributes;
Map<String, dynamic Function(dynamic)> get transformers;
Map<String, dynamic Function()> get deserializers;
}

class SerializableObject implements Serializable {
final Map<String, dynamic> _attributes = {};
final Map<String, dynamic Function(dynamic)> _transformers = {};
final Map<String, dynamic Function()> _deserializers = {};

@override
Map<String, dynamic> get attributes => _attributes;

@override
Map<String, dynamic Function()> get deserializers => _deserializers;

@override
Map<String, dynamic Function(dynamic)> get transformers => _transformers;
}

class Serializer {
String serialize(Serializable serializable) {
final buffer = StringBuffer();
_serializeAttributes(serializable, serializable.attributes, buffer);
return buffer.toString();
}

void deserialize(String jsonText, Serializable object) {
final decoder = JsonDecoder();
final json = decoder.convert(jsonText) as Map<String, dynamic>;
_deserializeAttributes(json, object);
}

void _serializeAttributes(Serializable parent,
final Map<String, dynamic> attributes, final StringBuffer buffer) {
buffer.write('{');
var writeSeparator = false;
for (final key in attributes.keys) {
if (writeSeparator) {
buffer.write(', ');
}
buffer..write('"')..write(key)..write('": ');
final value = attributes[key];
_serializeValue(parent, key, value, buffer);
writeSeparator = true;
}
buffer.write('}');
}

void _serializeValue(Serializable parent, final String key,
final dynamic value, final StringBuffer buffer) {
if (value == null) {
buffer.write('null');
} else if (value is String) {
final text = value.replaceAll('"', r'\"');
buffer..write('"')..write(text)..write('"');
} else if (value is int) {
buffer.write(value);
} else if (value is double) {
buffer.write(value);
} else if (value is bool) {
buffer.write(value);
} else if (value is List) {
var writeSeparator = false;
buffer.write('[');
for (final child in value) {
if (writeSeparator) {
buffer.write(', ');
}
_serializeValue(parent, key, child, buffer);
writeSeparator = true;
}
buffer.write(']');
} else if (value is Serializable) {
_serializeAttributes(value, value.attributes, buffer);
} else {
final transform = parent.transformers[key];
if (transform == null) {
throw StateError(
'Invalid value encountered, unable to serialize: "$key": $value');
}
final transformedValue = transform(value);
_serializeValue(parent, key, transformedValue, buffer);
}
}

void _deserializeAttributes(
final Map<String, dynamic> json, final Serializable object,
[String parentKey]) {
for (final key in json.keys) {
final value = json[key];
object.attributes[key] = _deserializeValue(object, key, value);
}
}

dynamic _deserializeValue(
final Serializable parent, final String key, dynamic value) {
final transform = parent.transformers[key];
if (transform != null) {
return transform(value);
}
if (value is String || value is int || value is double || value is bool) {
return value;
} else if (value is List) {
final function = parent.deserializers[key];
if (function == null) {
throw StateError(
'Deserialization Warning: no deserializer for List "$key" defined.');
}
final listValue = function();
for (final subValue in value) {
listValue.add(_deserializeValue(parent, key, subValue));
}
return listValue;
} else if (value is Map<String, dynamic>) {
// this is a complex object
final function = parent.deserializers[key];
if (function == null) {
throw StateError(
'Deserialization Warning: no deserializer for object "$key" defined.');
}
final serializable = function() as Serializable;
if (serializable == null) {
throw StateError(
'Deserialization Warning: deserializer for object "$key" creates non-serializable object${function()}.');
}
_deserializeAttributes(value, serializable, key);
return serializable;
} else {
throw StateError(
'Unsupported type ${value.runtimeType} for element "$key".');
}
}
}
14 changes: 14 additions & 0 deletions pubspec.yaml
@@ -0,0 +1,14 @@
name: enough_serialization
description: Runtime solution for serializing and deserialzing JSON.
version: 1.0.0
homepage: https://www.github.com/enough-software/enough_serialization

environment:
sdk: '>=2.9.3 <3.0.0'

#dependencies:
# path: ^1.7.0

dev_dependencies:
pedantic: ^1.9.0
test: ^1.14.4

0 comments on commit 206743f

Please sign in to comment.