CoffeeScript — это язык, создающий абстракцию над JavaScript (как предполагает подобное имя). Это абстракция над синтаксисом JavaScript, а не над его концепциями: язык по-прежнему основан на функциях как объектах, которые могут связываться с другими объектами, и прототипах. наследование.
CoffeeScript поддерживает лучшие практики JavaScript, превращая абстракции, которые вы в любом случае написали бы или позаимствовали из фреймворка, в концепции языка для максимальной краткости. Он имеет этап компиляции — как и любой язык, который должен компилироваться в более низкий уровень, такой как C или Java.
Поскольку ковбойское кодирование не является моим предпочтительным способом работы, я подготовил пример разработки через тестирование с помощью jsTestDriver . В этой статье вы получите две вещи: введение в CoffeeScript и инструменты для его модульного тестирования (и, следовательно, как использовать TDD с CoffeeScript).
Инфраструктура
Базовая структура состоит из двух папок: src / и lib /; помните шаг компиляции. Мы поместим файлы .coffee в src / и скомпилируем их в эквиваленты .js в симметричном дереве в lib /.
Мы также добавляем файл jsTestDriver.conf, чтобы сообщить инфраструктуре модульного тестирования все загружаемые файлы, которые являются только «двоичными» сценариями .js:
server: http://localhost:4224 load: - lib/*.js
составление
Это первая версия теста, которую мне удалось написать, fizzbuzztest.coffee. Это тавтология, которая всегда должна проходить:
mytest = () -> assertEquals(1, 1) tests = { "test1is1": mytest } TestCase("tests for fizzbuzz kata", tests)
Здесь вы видите, что функции все еще являются объектами первого класса, но поддерживаются только анонимные функции. CoffeeScript — это Python / Ruby-подобный язык без точек с запятой, и с последним языком есть некоторые сходства и общие черты.
Я до сих пор использую старый синтаксис для вызова функций, хотя во многих случаях скобки могут быть опущены. CoffeeScript консервативен и даже принимает точки с запятой, если вы хотите написать их.
Я скомпилировал этот скрипт с кофе -o lib / -c src /. fizzbuzztest.js является результатом:
(function(){ var mytest, tests; mytest = function() { return assertEquals(1, 1); }; tests = { "test1is1": mytest }; TestCase("tests for fizzbuzz kata", tests); })();
По умолчанию глобальное пространство имен не затрагивается, и
ключевые слова var автоматически вводятся для его сохранения. Когда мне позже понадобилось глобальное пространство имен, я написал:
this.fizzbuzz = /* ... function definition ... */
это в данном случае является объект окна или другим глобальным объектом , где вы исполняете код.
Бег
Чтобы запустить тест, мы должны инициализировать тестовый драйвер (только один раз):
jsTestDriver java -jar JsTestDriver-1.3.2.jar --port 4224
jsTestDriver теперь будет слушать на локальном хосте: 4224. Загрузите этот URL в ваш браузер и перехватите его, нажав на ссылку. По запросу тесты будут выполняться внутри браузера: более подробную информацию см. В соответствующей статье .
Каждый раз, когда вы хотите запустить тесты, выполняйте из командной строки:
java -jar JsTestDriver-1.3.2.jar --tests all
Это полная история моего ката . Вот окончательная версия кода (предупреждение о спойлере!), С поддержкой добавления других факторов, кроме 3 или 5. Код, вероятно, уродливее среднего, но он компилируется:
tests = { "test ordinary numbers are unchanged": -> assertEquals(1, fizzbuzz(1)) assertEquals(2, fizzbuzz(2)) assertEquals(4, fizzbuzz(4)) assertEquals(142, fizzbuzz(142)) "test multiples of 3 become fizz": -> assertEquals("Fizz", fizzbuzz(3)) assertEquals("Fizz", fizzbuzz(6)) assertEquals("Fizz", fizzbuzz(9)) "test multiples of 5 become buzz": -> assertEquals("Buzz", fizzbuzz(5)) assertEquals("Buzz", fizzbuzz(10)) "test multiples of 3 and 5 become fizzbuzz": -> assertEquals("FizzBuzz", fizzbuzz(15)) assertEquals("FizzBuzz", fizzbuzz(45)) } TestCase("tests for fizzbuzz kata", tests)
newRule = (word, divisor) -> (number) -> return word if number % divisor == 0 "" newFizzBuzz = (rules) -> (number) -> result = "" concatenation = (rule) -> result = result + rule(number) concatenation rule for rule in rules return result if result number fizzRule = newRule("Fizz", 3) buzzRule = newRule("Buzz", 5) this.fizzbuzz = newFizzBuzz([fizzRule, buzzRule])
Комментарии к опыту
CoffeeScript предлагает более короткий синтаксис , который представляет собой некоторую кривую обучения, но не крутой . Я прошел весь пример за 1 час (однако я уже знал, как использовать jsTestDriver.)
Синтаксис формирует способ написания кода, упрощая некоторые вещи: я обнаружил, что использую функцию более высокого порядка, которая чаще создает другие , поскольку создание функции сейчас — это просто вопрос -> перед некоторыми строками кода.
Присвоение имен переменным также проще, поскольку вам нужно думать только об имени, а не о var или загрязнении области видимости. Больше времени уделять дизайну, а не языковым проблемам. Некоторые из них, такие как инструкция, если выражение удобны, но не обязательны, и есть благодаря вдохновению Ruby.
В CoffeeScript есть еще кое-что, например, опции для связывания функций, которые помогают не потерять ссылку на это. Однако вопрос заключается в том, имеет ли все это удобство большую ценность, чем время, затрачиваемое на изучение нового языка и добавление инфраструктуры для его работы — компилятор, хуки сборки и параллельное дерево, которое нужно игнорировать в вашей системе управления версиями.