ofxJsonUtilsというaddon

手前味噌ですが, 最近[ofxJsonUtils](https://github.com/2bbb/ofxJsonUtils)というaddonを書いてまして, それの紹介.


## ofxJsonUtilsとは

今後ofxXmlSettingが無くなってofXmlになりそうなのですがこれがまた非常に使いづらい.
そもそもXMLの閉じタグが嫌いだしjs大好き勢としてはjson最高って言いたい.
でもofのaddonでjsonの決定打がなかなか出ないのですが, 多分0.10.0から[nlohmann/json](nlohmann json)というC++11なモダンなjsonライブラリがusing ofJson = nlohmann::json; として使えるようになります.

で, それを先取りしてofxJsonUtilsというのを書いてまして, nlohmann::jsonが無い場合はofJsonとして読み込んでしまったりとかして今後も互換性を保てるjson使いが出来る, と.

そんで, nlohmann::json はなかなかイケてるんですが痒いところに手が届かないのでラッパーライブラリ的なのも書いている状況です.

### ofxJsonUtils::loadFromFile

毎回ファイルからテキスト読み込んでパースしてっていう数行のことですが, 大体定型文なので関数にしてます.

```cpp
  ofJson json = ofxJsonUtils::loadFromFile("hoge.json");
```

### toJson, loadJson

例えば, 

```cpp
struct my_struct {
  ofVec3f point;
  int radius;
};
```

のようなクラス/構造体をjsonにシリアライズしたい場合に

```cpp
struct my_struct {
  ofVec3f point;
  int radius;
  ofJson toJson() const {
    ofJson json;
    json["point"] = ofxJsonUtils::convert(point);
    json["raidus"] = radius;
    return json;
  }
  void loadJson(const ofJson &json) {
    ofxJsonUtils::parse(json["point"], point);
    ofxJsonUtils::parse(json["radius"], radius);
  }
};
```

と `toJson`, `loadJson` を定義しておくと今度は

```cpp
struct other_struct {
  std::vector<my_struct> objs;
  ofJson toJson() const {
    ofJson json;
    json["objs"] = ofxJsonUtils::convert(objs);
    return json;
  };
  void loadJson(const ofJson &json) {
    ofxJsonUtils::parse(json["objs"], objs);
  }
};
```

と再帰的に使っていくことが出来ます.

既に存在する自分が手を入れれないクラスに関しても

```cpp

struct not_my_struct { ... };

ofJson convert(const not_my_struct &value) {
  return {
    {"x", value.x},
    {"y", value.y}
  };
}

void parse(const ofJson &json, not_my_struct &value) {
  value.x = json["x"];
  value.y = json["y"];
}

```

と関数を定義することで外部からでも対応させることが出来ます.

### `ofxJsonify`

また, `ofxJsonify` というtemplateクラスを使うと

```cpp
  struct other_struct : public ofxJsonify<other_struct> {
    std::vector<my_struct> objs;
    ofJson toJson() const {
      ofJson json;
      json["objs"] = ofxJsonUtils::convert(objs);
      return json;
    };
    void loadJson(const ofJson &json) {
      ofxJsonUtils::parse(json["objs"], objs);
    }
  }
```

とするだけで

```cpp
  other_struct s;
  s.loadFromJsonFile("hoge.json");
  s.loadFromJsonString("{\"objs\":[]}");

  s.writeToJsonFile("bar.json");
  std::string str = s.toJsonString();

  ofJson json = s;
```

といったファイルへの書き込み/読み込み, 文字列の書き出し/読み込み, オペレーターオーバーロードを裏で実装してくれます.

### `create`, `load`

最初の例の

```cpp
struct my_struct {
  ofVec3f point;
  int radius;
  ofJson toJson() const {
    ofJson json;
    json["point"] = ofxJsonUtils::convert(point);
    json["raidus"] = radius;
    return json;
  }
  void loadJson(const ofJson &json) {
    ofxJsonUtils::parse(json["point"], point);
    ofxJsonUtils::parse(json["radius"], radius);
  }
};
```

は, `create` / `load` を使うと次のようにも書けます.

```cpp
struct my_struct {
  ofVec3f point;
  int radius;
  ofJson toJson() const {
    return ofxJsonUtils::create("point", point, "radius", radius);
  }
  void loadJson(const ofJson &json) {
    ofxJsonUtils::load(json, "point", point, "radius", radius);
  }
};
```

更に, `kv` マクロを使うと

```cpp
struct my_struct {
  ofVec3f point;
  int radius;
  ofJson toJson() const {
    return ofxJsonUtils::create(kv(point), kv(radius));
  }
  void loadJson(const ofJson &json) {
    ofxJsonUtils ::load(json, kv(point), kv(radius));
  }
};
```

と書けます.

### oFクラスの対応状況

現状は

* `ofVec2f`: `{"x": 0.0, "y": 0.0}`
* `ofVec3f`: `{"x": 0.0, "y": 0.0, "z": 0.0}`
* `ofVec4f`: `{"x": 0.0, "y": 0.0, "z": 0.0, "w": 0.0}`
* `ofRectangle`: `{"x": 0.0, "y": 0.0, "width": 0.0, "height": 0.0}`
* `ofMatrix4x4`: `{"value0": (ofVec4f), "value1": (ofVec4f), "value2": (ofVec4f), "value3": (ofVec4f)}`
* `ofColor_<Type>`: `{"r": (Type), "g": (Type), "b": (Type), "a": (Type)}`
* `std::vector<Type>`, `std::deque<Type>`, `std::array<Type>` : `[(Type) ...]`
* `std::map<std::string, Type>`: `{key: (Type)}`

といった感じで対応しています.

### 最後に

まだ書き始めたばかりなので欲しい機能があった場合はissue立ててもらえると有難いです.
もちろん, 機能追加やバグフィクスのPRもお待ちしております.

以上, 宣伝でした.