понедельник, 30 марта 2015 г.

JavaScript charset в браузере

Согласно стандарту HTML5, стандартная кодировка страницы - UTF-8. А вот с JavaScript всё сложнее.

Пусть у нас есть какой-то JSON. Напишем функцию, которая его возвращает:

function getOutlineJson() {
  return {
      "title" : "Элемент1"
  };
}

Сохраняем в отдельный файл, привязываем через <script>. Пытаемся вывести в консоль:


document.addEventListener('DOMContentLoaded', function() {
  console.log(getOutlineJson());
});

В консоли будет JSON с полями на неведомом языке. Хотя, как подтверждает view.encoding() в консоли Sublime, все файлы - в UTF-8.

А если добавить вывод чего-то кириллического прямо на экран?

document.addEventListener('DOMContentLoaded', function() {
  console.log("проверка консоли");
  console.log(getOutlineJson());
});

Внезапно, кодировка починилась. Видимо, кодировка выставляется по первому вызову.

Лечится мета-тегом:

<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />

Проверено в Firefox и Chrome.

"case folding collision between" в Mercurial под Windows

У Mercurial под Windows есть неприятная особенность - если переименовать файл проекта, изменив в нём только регистр одного из символов, то рухнет всё. Mercurial, как дитя Unix-а, считает, что разные регистры - это разные файлы, а вот для Windows это параллельно. В результате - ошибка "case folding collision between" и полный обвал репозитория: даже если удалить зловредный файл, чтобы сделать push, надо сначала сделать pull, а pull не проходит из-за конфликта имён.

Можно посмотреть, что советуют на официальном сайте. Но эти советы не всегда помогают (мне не помогли).

В конце концов, нашёлся хакерский вариант. Только не забудьте сделать резервную копию.

hg pull
# ревизия из репозитория, можно посмотреть в Tortoise
hg debugsetparents <bad revision>
hg debugrebuildstate
hg rm -A -f WeatherTimeMachine-Info.plist
hg ci -m "fixed collision-folding issue"
hg debugsetparents tip
hg debugrebuildstate
hg ci -m "fixed head"
hg push

среда, 25 марта 2015 г.

eval в JavaScript

eval в JavaScript с отложенным выполнением:

var JsEvaluator = (function(){
  var errors = {
    WRONG_SYNTAX : "Синтаксическая ошибка в выражении \"%SOURCE%\"",
    NON_SYNTAX : "Ошибка %ERROR_TITLE% при разборе выражения \"%SOURCE%\""
  };

  function null_func() { return null; }

  return {
    checkedEval : function(str_to_eval){
      if(!str_to_eval)
        return null_func;
      var trimmed_str = str_to_eval.trim();
      if(!trimmed_str)
        return null_func;
      try {
        var result = eval(trimmed_str);
        if(result === undefined)
          return null_func;
      } catch(e) {
        var error_text = (!(e instanceof SyntaxError)) ?
                          errors.WRONG_SYNTAX.replace(/%SOURCE%/, trimmed_str) :
                          errors.NON_SYNTAX.replace(/%ERROR_TITLE%/, e.name).replace(/%SOURCE%/, trimmed_str);
        console.error(error_text);
        return null_func;
      }
      return function() { return eval(trimmed_str); };
    }
  };
})();

Возвращать именно функцию может быть полезно, если выражение в eval завязано на какую-то внешнюю переменную. Например, в str_to_eval у нас условие: "Param1 > 10". Понятно, что его надо выполнить в момент проверки, а не инициализации. Поэтому выполнение в примере отложено.

Для eval выполняется правило последней строки, пришедшее в Ruby и R из Fortran - eval возвращает значение, которое вернула последняя выполненная строка переданного ему выражения. Это может быть в т.ч. строка с числом:
eval("1;2;4")
> 4

или даже со строковой константой:

eval("'boo'")
> "boo"

Как вариант, можно отказаться от ошибок и понимать "неправильный" JavaScript как строковую константу:

var JsEvaluator = (function(){
  function null_func() { return null; }
  return {
    checkedEval : function(str_to_eval){
      if(!str_to_eval)
        return null_func;
      var trimmed_str = str_to_eval.trim();
      if(!trimmed_str)
        return null_func;
      try {
        var result = eval(trimmed_str);
        if(result === undefined)
          return null_func;
      } catch(e) {
        return function() { return str_to_eval; };
      }
      return function() { return eval(trimmed_str); };
    }
  };
})();

Подключаем JSON к Java-проекту

Очень долго JSON в Java читали и генерировали сторонними библиотеками вроде Jackson. Но прогресс не стоит на месте и начиная с Java 7 вроде как появилась стандартная сборка javax.json.

Но, к сожалению, если вставить банальное import javax.json.*, то работать ничего не будет. Java скажет, что не знает этого пространства имён.

Пользователи maven (вроде меня), идёт в Гугл и читают там, что надо подключить зависимость в pom.xml. Вот такую:

<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.json</artifactId>
   <version>1.0.4</version>
</dependency>

С ней проект действительно компилируется, запускается... и торжественно вылетает с ошибкой Provider org.glassfish.json.JsonProviderImpl not found.

Правильное Dependency выглядит так:

<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.json</artifactId>
   <version>1.0.4</version>
</dependency>

И теперь всё заработает.

И т.к. namespace - часть Glassfish, то чтобы он заработал в проекте без Maven, надо скачать и добавить к проекту JSON Processing RI jar.

вторник, 24 марта 2015 г.

Разница между isInstance() и instanceof в Java

В чём разница между instanceof из class.isInstance(item) в Java? На самом деле разницы почти нет, просто instanceof требует, чтобы класс, с которым сравнивают, был известен ещё на этапе компиляции.

А вот isInstance можно смело вызывать и от экземпляра: item1.getClass().isInstance(item2)

воскресенье, 22 марта 2015 г.

JavaFX Color в CSS

Внешний вид компонент JavaFX настраивается в CSS. Соответственно, должен быть какой-то конвертер стандартного javafx.scene.paint.Color в CSS-friendly формат.

Возможно, он и правда есть - но я его не нашёл. К тому же, внутри класс Color устроен немного по-другому: насыщенность цвета в свойствах getRed, getBlue и getGreen задаётся double-числом от 0.0 до 1.0.

И вот что получилось:

public static String colorToJson(Color color){
   return String.format("#%02X%02X%02X",
                 (int)(color.getRed() * 0xFF),
                 (int)(color.getBlue() * 0xFF),
                 (int)(color.getGreen() * 0xFF));
}

На выходе из COLOR.Red получается правильный #FF0000.

Выглядит симпатично и немного напоминает чистый C :).Правда, прозрачность потерялась.

А если заглянуть в стандарт CSS, то выясняется: уже давно можно задавать цвет как rgba(0, 0, 255, 1.0).

А значит, наш код можно переписать вот так (formatter нужен, чтобы вместо точки в десятичной дроби не завелась запятая):

public static String colorToJson(Color color){
  StringBuilder sb = new StringBuilder();
  Formatter formatter = new Formatter(sb, Locale.US);
  formatter.format("rgba(%.0f, %.0f, %.0f, %.1f)", color.getRed() * 0xFF, color.getBlue() * 0xFF, color.getGreen() * 0xFF, color.getOpacity());
  return sb.toString();
}

Callable в Java, который возвращает void

К сожалению, в Java пока не появилась аналога шаблонных Func<> и Action<> из C#. Приходится обходиться Callable, в котором указывать тип возвращаемого значения - обязательно.

А если нужно просто выполнить функцию, которая возвращает void, то пишут Callable<Void> и (для асинхронных) Future<Void>. В учебниках обычно не упоминают, что для void есть класс-обёртка.