- TDD
- Как внутри выглядит модуль
- Типичный порядок действий при работе с библиотекой
- Особенности работы путей
- touch
- Выводы
У нас уже есть библиотека для работы с деревьями. Поэтому можно создать библиотеку для работы с файловой системой.
TDD
Начнем с тестов и попробуем определить дизайн нашей библиотеки. Для начала создадим instance — новую файловую систему. Сделаем это через new
. И у нас появляется const files
:
const files = new HexletFs();
// Убеждаемся, что у нас не существует директории внутри файловой системы, например, `etc`
// У нас получается интерфейс `files.isDirectory`
assert.ok(!files.isDirectory('/etc' ) ) ;
// Cоздаем эту директорию с помощью функции `mkdirSync`
files.mkdirSync ('/etc');
// Делаем проверку, которая была выше
// Только сейчас она должна вернуть истину — сказать, что директория была создана
assert.ok(files.isDirectory('/etc'));
// Создаем внутреннюю директорию
files.mkdirSync('/etc/nginx');
// Убеждаемся, что она есть
assert.ok(files.isDirectory('/etc/nginx'));
Сейчас тестов недостаточно, обычно необходимо больше. Но для начала этого хватит. Здесь видно характер интерфейса, который мы закладываем в эту библиотеку.
Команда mkdir
, которая используется в консоли, не создает директорию рекурсивно по умолчанию. То есть эта команда создает только директорию следующего уровня. Если передать ей на вход путь, который в себе содержит несколько несуществующих вложенных директорий, то они не будут созданы. Это одна из ошибочных ситуаций.
Как внутри выглядит модуль
Мы используем библиотеку, чтобы хранить деревья и работать с ними. Поэтому нам необходимо при создании записать в this.tree
новое дерево и передать туда слэш как корень:
// HexletFs.js
export default class {
constructor() {
this.tree = new Tree('/');
}
}
При этом когда мы создаем новый узел, например, используем mkdir
, то добавляем в дерево ребенка. В нем первым параметром идет имя — name
, а вторым — мета как дополнительная информация. Последнее нужно, так как у нас универсальная библиотека работы с деревьями. Например, мы можем передать тип:
// mkdir
subtree.addChild(name, { type: 'dir' });
То есть мы должны определять директория это или файл, так как hexlet trees внутри не ассоциирована с файловой системой. Поэтому без этого мы не сможем понять, с чем мы работаем.
Типичный порядок действий при работе с библиотекой
Разберем типичный порядок действий при работе с нашей библиотекой. Рассмотрим это на примере mkdir
.
Сначала у нас есть некий путь, который мы хотим создать:
const path = '/etc/nginx/conf.d';
mkdir
создает только вложенные директории, но на один уровень ниже. То есть мы не можем создать несколько директорий в глубину. Путь из примера может быть создан только при условии, что папки etc
и nginx
уже существуют. А нам нужно создать папку conf.d
.
Порядок действий будет таким:
- Разбиваем путь на массив имен
- С помощью
getDeepChild
извлекаем предпоследний элемент — достаемnginx
- Добавляем
nginx
нового ребенка —conf.d
Таким образом работает mkdir
и большинство других функций в работе с файловой системой.
Особенности работы путей
Есть некоторые особенности, которые касаются реальных файловых систем и того, как с ними работает API.
Мы используем слэши, чтобы отделять директории друг от друга. Подряд идущие слэши не влияют на глубину. Внутри API происходит нормализация, и дублирующиеся слэши убираются.
Например, мы создали такую директорию:
assert.ok(!files.isDirectory('/var//'));
В этом случае конечный слэш ни на что не влияет. Сама команда определяет, что это директория. Например, мы проверяем, что является для директории /var
или /var////
:
files.mkdirSync('/var/');
assert.ok(files.isDirectory('/var'));
assert.ok (files.isDirectory('/var////'));
В этом случае внутри происходит нормализация — слэши убираются и считается, что все хорошо.
Еще один пример, где создана директория с большим количеством слэшей:
files.mkdirSync('/var//log//////');
// Делаем проверку
assert.ok(files.isDirectory('/var/log'));
assert.ok(files.isDirectory('/var///log'));
Проверка говорит, что директория создана.
Получается, что нормализация происходит на всех уровнях. Это важный аспект, который делает задачу интересней, и его нужно соблюдать.
touch
Команда touch
тоже часто используется в файловых системах. Она изменяет время доступа к файлу. Также она дополнительно создает файл. Но так как она короткая и удобная, то обычно ее используют, когда создают пустые файлы.
При этом это не первостепенная задача команды touch
, но разработчики часто пользуются ею.
Как это работает:
// Проверяем, что файл не существует — убеждаемся, что эта функция правильно работает
assert.ok(!fileş.isFile('/file.txt'));
// Делаем `touch`
files.touchSync('/file.txt'); // Внутри записывается тип — файл. Потом это будет нужно при проверках
// Проверяем, что он существует:
assert.ok(files.isFile('/file.txt'));
Здесь важно помнить, что если мы передаем слэши, то они должны автоматически убираться — пути должны нормализовываться внутри.
Выводы
В этом уроке мы создали библиотеку для работы с файловой системой. Мы определили дизайн нашей библиотеки и создали новый узел, чтобы хранить деревья и работать с ними. Далее разобрали типичный порядок действий при работе с библиотекой, особенности работы путей и команду touch
, которая изменяет время доступа к файлу и дополнительно создает файл.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Вебинар «Как самостоятельно учиться»
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.