Посты с тэгом «code complete»

  • Веб-разработка в Eclipse: JavaScript

    Как отмечалось ранее, для работы JS вместо Spket IDE я теперь использую Eclipse JSDT, который входит в состав Eclipse Web Tools Project. Причины для такого перехода вполне естественные: проекты, с которыми я работаю, становятся всё сложнее и больше, нужно больше удобства и контроля над ситуацией.

    В JSDT меня больше всего привлекло следующее:

    • Рефакторинг: переименование объектов, выделение блока в отдельную переменную, объединение определения переменной и присваивания и т.д. Некоторые вещи вроде выделения в метод пока толком не работают, но, надеюсь, в ближайшее время это будет исправлено.
    • Валидация кода. Помимо обычной проверки синтаксиса, можно настроить более сложные проверки вроде поиска неиспользованных переменных, недостижимый код, переопределение переменной из внешней области видимости и т.д.
    • Выделение фрагментов camelCase-переменных с помощью Shift+Alt+← и Shift+Alt+→
    • Поддержка JSDoc.
    • Удобный Outline/Quick outline; дополнительные окна, в которых показывается документация и код определения текущего объекта.
    • Автоматическая отбивка кода при его перемещении из/в блок.
    • Подключение внешних библиотек.
    • Встроенный дебаггер.

    Лучше всего будет, если читатель поставит Eclipse for JavaScript Web Developers и изучит все настройки и менюшки — в том числе контекстные — JSDT (лучше включить перспективу JavaScript), потому что возможностей действительно очень много и их сложно описать в одной статье.

    Однако при всей «крутости» этой среды разработки, в ней есть ряд проблем, с которыми пришлось столкнуться прежде, чем окончательно перейти на JSDT.

    Начинаем работу

    Для того, чтобы полноценно использовать все возможности JSDT, обязательно нужно создать проект с JavaScript-природой. Делается очень легко: вызываем File > New > Project… и в появившемся окошке выбираем JavaScript Project. В появившемся диалоговом окне вводим название проекта и жмём Finish. По умолчанию создаётся веб-проект с поддержкой DOM, папкой с JS-исходниками является сам проект. Когда вы лучше освоитесь с JSDT, то сможете более тонко настраивать проект: указывать подключаемые библиотеки, исключать ненужные файлы и папки из индекса. Пока оставим как есть.

    Module pattern

    Главным преимуществом для меня в Spket IDE была поддержка современных паттернов, в том числе и модуля:

    var module = (function() {
    	return {
    		method: function() {}
    	};
    })();
    

    В Spket такая конструкция без проблем отображается в outline и по ней работает code complete, но в JSDT ни то, ни другое не работает:

    ss011

    Небольшой JSDoc исправит ситуацию:

    /**
     * @type module
     */
    var module = (function() {
    	return {
    		/**
    		 * @memberOf module
    		 */
    		method: function() {}
    	};
    })();
    

    Теперь работает как надо:

    ss021

    Но есть ещё одна проблема: приватные переменные и методы модуля не отображаются в Outline, а очень хотелось бы. Это можно исправить, описав самовызывающуюся функцию как конструктор несуществующего класса:

    /**
     * @memberOf __module
     * @type module
     */
    var module = (/** @constructor */ function() {
    
    	function myPrivateMethod() {
    
    	}
    
    	return {
    		/**
    		 * @memberOf module
    		 */
    		method: function() {}
    	};
    })();
    

    ss031

    Как видно из примера, я описал несуществующий класс __module, двойное подчёркивание я использую в качестве своеобразного соглашения об именовании объектов. Проблема в том, что этот несуществующий класс попадёт в code complete всего проекта, и использование двойного подчёркивания — простой и понятный способ отфильтровать ненужные данные при вызове code complete. Однако этот недостаток очень легко можно превратить в достоинство: таким образом можно описывать структуры объектов, доступ к описанию которых затруднён из-за отсутствия строгой типизации в JS:

    ss041

    Поддержка популярных библиотек

    Базовый набор библиотек для JSDT довольно невелик: это стандартные объекты JavaScript (Array, String и прочее) и стандартный DOM (HTMLElement, document и так далее). То есть если мы напишем, например, document. и вызовем code complete, то увидем список свойств и методов объекта document, экземпляра класса Document. Но современная веб-разработка немыслима без использования популярных библиотек вроде jQuery.

    Имея в своём распоряжении JSDoc, можно создать описание практически любого популярно фреймворка и использовать его для подсказок в коде. Так как таких описаний в интернете найдено не было, я воспользовался своим любимым принципом «если хочешь, чтобы что-то было сделано хорошо, сделай это сам» и запустил проект, в котором создаю описания популярных библиотек и фреймворков, с которыми работаю:

    jsdt-docs — JSDoc для популярных библиотек

    В этом проекте сейчас есть следующие библиотеки:

    • Modernizr 2
    • Browser Addons — разные методы и свойства, которые почему-то отсутствуют в стандартном описании DOM в JSDT.
    • console — небольшое описание объекта console, который присутствует в современных браузерах.
    • CSS2Properties — список CSS-свойств для свойства style DOM-элементов. Несмотря на то, что он называется CSS2, в нём присутствуют и CSS3-свойства: такое название выбрано потому, что в стандартном описании Element.prototype.style является объектом класса CSS2Properties.
    • JS SIgnals
    • Node.JS
    • Socket.IO
    • Underscore.js.
    • Zepto.js

    Добавить библиотеку довольно просто:

    1. Идём в настройки: Preferences > JavaScript > Include Path > User Libraries.
    2. Создаём новую библиотеку: нажимаем кнопку New…
    3. Вводим название библиотеки в появившемся окне и жмём ОК.
    4. Выделив только что добавленную библиотеку, нажимаем на кнопку Add .js file… и выбираем один или несколько файлов, относящихся к данной библиотеке.

    После того, как библиотека была создана, нужно добавить её в проект:

    1. Идём в настройки проекта: Project > Properties > JavaScript > Include Path > Libraries.
    2. Жмём кнопку Add JavaScript Library, выбираем User Library, а затем и библиотеки, которые хотим добавить.

    Теперь у вас в проекте будет работать code complete для указанных библиотек:

    ss051

    Поддержка jQuery

    Добавление поддержки своего любимого фреймворка оказалась не такой уж и простой задачей. Во-первых, он довольно большой и содержит внушительных объемов документацию. Во-вторых — многие методы в нём «перегружены»: например, val() возвращает текстовое значение поля, а val(str) — записывает его и возвращает уже jQuery-объект.

    К счастью, у документации к jQuery есть публичный API, который выдаёт описание всех методов в XML. Я написал парсер на node.js, который опрашивает API и преобразует XML в JSDoc, понятный для JSDT (и, надеюсь, другим IDE). Так что в случае выхода новой версии jQuery можно быстро перегенерировать всё документацию. Парсер я писал для себя и по-простому, он не поддерживает передачу параметров через командную строку, всё настраивается в main.js:

    • Можно сгенерировать документацию для определённой версии jQuery (TARGET_VERSION).
    • Можно сгенерировать описание в виде нескольких файлов. Это связано с особенностью JSDT. Как уже отмечалось ранее, в jQuery много «перегруженных» методов, и если их описать в одном JS-файле, то JSDT будет использовать только одно (самое последнее) описание. Однако если сохранить описание методов с одинаковым названием в разных файлах, то JSDT вполне неплохо покажет по ним code complete и документацию. Так что у вас есть выбор: при создании библиотеки jQuery добавить все файлы вида jquery-jsdoc-N.js (Eclipse JSDT) или же только jquery-jsdoс.js если ваша IDE способна прочитать описание с перегруженными методами.
    • Можно переписать некоторые определения для более удобной работы с code complete (class_map, prefix_map). Например, так переписываются описания для Deferred и Promise объектов, чтобы можно было использовать их описание в JSDoc:

    ss06

    В описании есть ряд классов, которые можно использовать в JSDoc: __jQueryDeferred, __jQueryPromise и __jQueryEvent.

    Пишем плагины к jQuery

    Собственно, как писать плагины рассказывать нет смысла, это подробно описано в документации. Покажу лишь как сделать так, чтобы ваш плагин появился в code complete. А сделать это очень просто, достаточно методу плагина указать, что он является членом класса jQuery:

    jQuery.extend(jQuery.fn, {
    	/** @memberOf jQuery */
    	myPlugin: function() {
    
    	}
    });
    
    $('div').m // тут можно вызвать code complete
    

    Поддержка Node.JS

    Отдельно стоит упомянуть Node.JS, так как к модулям нужно обращаться не напрямую, а через функцию require():

    var http = require('http');
    http.createServer(function() {
    
    });
    

    То есть подсказки для модуля должны зависеть от того, какой аргумент передали в функцию require(). В целом, в JSDT эта ситуация решаема: нужно написать отдельный плагин в виде подключаемой библиотеки, который будет находить вызовы функции require(), смотреть на аргумент и возвращать виртуальный объект с необходимыми методами, и может быть я когда-нибудь напишу такую библиотеку. А пока будем довольствоваться малым: указывать тип модуля через JSDoc.

    Все модули в моей документации описаны в виде классов Node{Name}Module, например: httpNodeHttpModule, utilNodeUtilModule. Поэтому для переменной, в которую записывается модуль, указываем через JSDoc нужный тип:

    /** @type NodeHttpModule */
    var http = require('http');
    http. // вызываем code complete
    

    Советы

    В качестве заключения дам несколько советов, которые помогут вам в работе с JSDT:

    • Не используйте фигурные скобки при указании типа переменной с помощью тэга @type — в некоторых случаях JSDT не сможет подцепить тип переменной. Лучше писать так: @type Array (вместо @type {Array}).
    • При описании модуля тэг @memberOf moduleName достаточно указать только у одного свойства/метода в литерале, все остальные подцепятся автоматически.
    • Если у вас в проекте есть непосредственно код библиотек (например, jQuery), то его лучше исключать из индекса, чтобы он не мешал работе code complete. Делается это так: заходите в настройки проекта Project > Properties > JavaScript > Include Path > Source. Разворачиваете папку с исходниками, двойной клик по фильтру Excluded и в диалоговом окне в секцию Exclusion patterns добавляете файлы, которые надо исключить.