Skip to content
mayorovp edited this page Jun 18, 2014 · 1 revision

Эта библиотека - реализация расширения JSON, предложенного dimsmol в статье http://habrahabr.ru/post/224261/

Упор сделан на компактность и использование стандартных механизмов работы с JSON, поэтому используется описанное в статье преобразование синтаксиса.

Способы настройки парсера

Вариант 1. Добавление глобальных функций-обработчиков расширения

JSONEX.functions.Date = function(str) {
  return new Date(str)
}

JSONEX.parse('{"?": ["Date", "2014-01-01"]}') // Wed Jan 01 2014 00:00:00

Вариант 2. Передача функций-обработчиков расширения локально

var options = { 
  functions: { 
    Date: function(str) {
      return new Date(str)
    }
  }
};

JSONEX.parse('{"?": ["Date", "2014-01-01"]}', options) // Wed Jan 01 2014 00:00:00

Вариант 3. Создание нового парсера с указанными настройками

var parser = new JSONEX.parser ({ 
  functions: { 
    Date: function(str) {
      return new Date(str)
    }
  }
});

parser.parse('{"?": ["Date", "2014-01-01"]}', options) // Wed Jan 01 2014 00:00:00

Асинхронные обработчики

Асинхронность включается параметром allow_async: true. Библиотека совместима с любыми A+ promise. Если хотя бы один из обработчиков вернет promise - то результат parse тоже будет promise.

JSONEX.allow_async = true;
JSONEX.functions.Delay = function(value) {
  var d = $.Deferred();
  setTimeout(function() { d.resolve(value); }, 1000);
  return d.promise();
};

JSONEX.parse('[ "Hello", {"?": ["Delay", "world"] } ]')
      .done(function(result) { console.log(result); }); // ["Hello", "world"]

Вложенные вызовы асинхронных обработчиков

Перед вызовом обработчика, библиотека дожидается получения значения всех его аргументов. Иными словами, обработчик никогда не получит на вход promise, это всегда будет значение.

JSONEX.allow_async = true;
JSONEX.functions.Date = function(str) {
  return new Date(str)
}
JSONEX.functions.Delay = function(value) {
  var d = $.Deferred();
  setTimeout(function() { d.resolve(value); }, 1000);
  return d.promise();
};

JSONEX.parse('{"?": ["Date", {"?": ["Delay", "2014-01-01"]}]}')
      .done(function(result) { console.log(result); }); // Wed Jan 01 2014 00:00:00

Если же по какой-то причине обработчику нужны на входе именно сырые promise - можно установить для него свойство allow_input_promises в true

Использование контекста

this внутри обработчика указывает на контекст - объект, создаваемый на каждый вызов parse. Его можно использовать для хранения словаря объектов (может потребоваться для передачи недревовидной структуры объектов):

JSONEX.functions.get = function(key) {
  return this[key];
};
JSONEX.functions.set = function(key, value) {
  return this[key] = value;
};
JSONEX.functions.set.allow_input_promises = true

Или для учета квот дорогих вызовов. Если требуется определенное начальное состояние контекста - его можно передать в функцию parse третьим аргументом.

Обратное преобразование

Обратное преобразование происходит так же, как и для JSON. Для правильной сериализации объектов, не являющихся словарями, можно использовать метод toJSONEX. Этот метод должен вернуть другой объект, который будет сериализован вместо заданного.

Чтобы получить вызов функции, надо вернуть объект JSONEX.FunctionCall:

Date.prototype.toJSONEX = function() {
  return JSONEX.FunctionCall("Date", [ this.toString() ]);
};