Автор оригинала: Scott Robinson.
Одним из моих абсолютных любимых вещей о узле является насколько легко создавать простые инструменты интерфейса командной строки (CLI). Между аргументом расставания с Ярги Для управления инструментами с NPM узел просто позволяет легко.
Некоторые примеры видов инструментов, которым я имею в виду:
При установке (с помощью опции -g
) эти пакеты могут быть выполнены из любого места в командной строке и работать так же, как встроенные инструменты Unix.
Я создал несколько приложений Node.js для командной строки в последнее время и подумал, что может быть полезно написать сообщение, чтобы помочь вам начать. Поэтому на протяжении всей этой статьи я покажу вам, как создать инструмент командной строки, чтобы получить данные о местоположении для IP-адресов и URL.
Если вы видели статью злоупотребления стеком на Изучение Node.js , вы можете вспомнить, мы создали пакет под названием Двадцать
У этого была аналогичная функциональность. Мы будем строить этот проект и превратить его в соответствующий инструмент CLI с большим количеством функциональности.
Настройка проекта
Давайте начнем с создания нового каталога и настройки проекта с помощью NPM:
$ mkdir twenty $ npm init
Нажмите Enter для всех запросов в последней команде, и вы должны иметь Package.json
файл.
Обратите внимание, что, поскольку я уже взял имя пакета двадцать На NPM вам придется переименовать его на что-то еще, если вы действительно хотите опубликовать. Или вы могли бы также сфера Ваш проект.
Тогда создайте index.js
файл:
$ touch index.js
Это все, что нам действительно нужно начать начать сейчас, и мы будем добавлять в проект, когда мы двигаемся дальше.
Разборные аргументы
Большинство приложений CLI принимают аргументы от пользователя, что является наиболее распространенным способом ввода. Для большинства случаев анализ аргументов не слишком сложно, поскольку обычно есть только горсть команд и флагов. Но поскольку инструмент становится все более сложным, будут добавлены больше флагов и команд, а аргумент, разборка может стать удивительно сложным.
Чтобы помочь нам с этим, мы будем использовать пакет под названием Ярги
который является преемником популярным Оптимист упаковка.
Ярги
Был создан, чтобы помочь вам разобрать команды от пользователя, как это:
var argv = require('yargs').argv;
Теперь сложные оптимисты, такие как Узел index.js install -v -cde -x derp
можно легко добраться:
var argv = require('yargs').argv; argv._[0] // 'install' argv.v // true argv.a // 22 argv.c // true argv.d // true argv.e // true argv.x // 'derp'
Ярги
Будет ли даже помочь вам с указанием командного интерфейса, поэтому, если вход пользователя не соответствует определенным требованиям, он покажет им сообщение об ошибке. Так, например, мы можем сказать Ярги
Мы хотим как минимум 2 аргумента:
var argv = require('yargs') .demand(2) .argv
И если пользователь не предоставляет как минимум два, они увидят это сообщение об ошибке по умолчанию:
$ node index.js foo Not enough non-option arguments: got 1, need at least 2
Есть гораздо больше до Ярги
Чем просто это, так что проверим readme для получения дополнительной информации.
Для Двадцать
Мы будем принимать несколько необязательных аргументов, таких как IP-адрес и некоторые флаги. На данный момент мы будем использовать Ярги
как это:
var argv = require('yargs') .alias('d', 'distance') .alias('j', 'json') .alias('i', 'info') .usage('Usage: $0 [options]') .example('$0 -d 8.8.8.8', 'find the distance (km) between you and Google DNS') .describe('d', 'Get distance between IP addresses') .describe('j', 'Print location data as JSON') .describe('i', 'Print location data in human readable form') .help('h') .alias('h', 'help') .argv;
Поскольку ни один из наших аргументов не требуется, мы не будем использовать .demand ()
, но мы используем .ализа ()
, который рассказывает Ярги
что пользователь может использовать короткую или длинную форму каждого флага. Мы также добавили некоторую справочную документацию, чтобы показать пользователю, когда им это нужно.
Структурирование приложения
Теперь, когда мы можем получить вход от пользователя, как мы возьмем это ввод и переведу его в команду с дополнительными аргументами? Существует несколько модулей, предназначенных для того, чтобы помочь вам сделать это, в том числе:
Со многими из этих рамках анализ аргумента на самом деле сделан для вас, поэтому вам даже не нужно использовать Ярги
Отказ И в командир
Шейт, большая часть его функциональности очень похоже на Ярги
, хотя он предоставляет способы маршрута команд для функций.
Поскольку наше приложение довольно простое, мы просто будем придерживаться использования Ярги
пока что.
Добавление кода
Мы не будем тратить слишком много времени здесь, так как это специфично для простого приложения CLI, но вот код, специфичный для нашего приложения:
var dns = require('dns'); var request = require('request'); var ipRegex = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/; var toRad = function(num) { return num * (Math.PI / 180); }; var getIpInfo = function(server, callback) { var ipinfo = function(p, cb) { request('http://ipinfo.io/' + p, function(err, response, body) { var json = JSON.parse(body); cb(err, json); }); }; if (!server) { return ipinfo('json', callback); } else if (!server.match(ipRegex)) { return dns.lookup(server, function(err, data) { ipinfo(data, callback); }); } else { return ipinfo(server, callback); } }; var ipDistance = function(lat1, lon1, lat2, lon2) { // Earth radius in km var r = 6371; var dLat = toRad(lat2 - lat1); var dLon = toRad(lon2 - lon1); lat1 = toRad(lat1); lat2 = toRad(lat2); var a = Math.sin(dLat / 2.0) * Math.sin(dLat / 2.0) + Math.sin(dLon / 2.0) * Math.sin(dLon / 2.0) * Math.cos(lat1) * Math.cos(lat2); var c = 2.0 * Math.atan2(Math.sqrt(a), Math.sqrt(1.0 - a)); return r * c; }; var findLocation = function(server, callback) { getIpInfo(server, function(err, data) { callback(null, data.city + ', ' + data.region); }); }; var findDistance = function(ip1, ip2, callback) { var lat1, lon1, lat2, lon2; getIpInfo(ip1, function(err, data1) { var coords1 = data1.loc.split(','); lat1 = Number(coords1[0]); lon1 = Number(coords1[1]); getIpInfo(ip2, function(err, data2) { var coords2 = data2.loc.split(','); lat2 = Number(coords2[0]); lon2 = Number(coords2[1]); var dist = ipDistance(lat1, lon1, lat2, lon2); callback(null, dist); }); }); };
Для полного исходного кода вы можете найти репозиторий здесь Отказ
Единственное, что уехало, что мы должны сделать с кодом, подключите аргументы CLI с приложенным кодом выше. Чтобы облегчить, мы поставим все это в функции под названием CLI ()
, который мы будем использовать позже.
Инкапсулируя аргумент разборы и отображение команды внутри CLI ()
Помогает сохранить код приложения отдельным, что позволяет им импортировать этот код в качестве библиотеки с требовать ()
Отказ
var cli = function() { var argv = require('yargs') .alias('d', 'distance') .alias('j', 'json') .alias('i', 'info') .usage('Usage: $0 [IP | URL] [--d=IP | URL] [-ij]') .example('$0 -d 8.8.8.8', 'find the distance (km) between you and Google DNS') .describe('d', 'Get distance between IP addresses') .describe('j', 'Print location data as JSON') .describe('i', 'Print location data in human readable form') .help('h') .alias('h', 'help') .argv; var path = 'json'; if (argv._[0]) { path = argv._[0]; } if (argv.d) { findDistance(path, argv.d, function(err, distance) { console.log(distance); }); } else if (argv.j) { getIpInfo(path, function(err, data) { console.log(JSON.stringify(data, null, 4)); }); } else if (argv.i) { getIpInfo(path, function(err, data) { console.log('IP:', data.ip); console.log('Hostname:', data.hostname); console.log('City:', data.city); console.log('Region:', data.region); console.log('Postal:', data.postal); console.log('Country:', data.country); console.log('Coordinates:', data.loc); console.log('ISP:', data.org); }); } else { findLocation(path, function(err, location) { console.log(location); }); } }; exports.info = getIpInfo; exports.location = findLocation; exports.distance = findDistance; exports.cli = cli;
Здесь вы можете увидеть, как мы в основном просто используем Если ... еще
утверждения, чтобы определить, какую команду запустить. Вы можете получить много Fancier и использовать Flatiron, чтобы на карте строк Regeex в команды, но это немного изгонов на то, что мы здесь делаем.
Делает его исполняемым
Для того, чтобы мы могли иметь возможность выполнить приложение, нам нужно указать несколько вещей в наших Package.json
Файл, как там, где находится исполняемый файл. Но сначала давайте создадим исполняемый файл и его код. Создайте файл под названием Двадцать
В каталоге Двадцать/bin/
и добавьте это к нему:
#!/usr/bin/env node require('../index').cli();
Shebang ( #!/USR/Bin/Env Node
) сообщает Unix, как выполнить файл, позволяющий нам оставить Узел
приставка. Вторая строка просто загружает код сверху и вызывает CLI ()
функция.
В Package.json
Добавьте следующие JSON:
"bin": { "twenty": "./bin/twenty" }
Это просто говорит NPM, где найти исполняемый файл при установке пакета с помощью -G
(глобальный) флаг.
Так что теперь, если вы устанавливаете Двадцать
Как глобальный …
$ npm install -g twenty
… Затем вы можете получить местоположения серверов и IP-адресов:
$ twenty 198.41.209.141 #reddit San Francisco, California $ twenty rackspace.com San Antonio, Texas $ twenty usa.gov --j { "ip": "216.128.241.47", "hostname": "No Hostname", "city": "Phoenix", "region": "Arizona", "country": "US", "loc": "33.3413,-112.0598", "org": "AS40289 CGI TECHNOLOGIES AND SOLUTIONS INC.", "postal": "85044" } $ twenty stackabuse.com Ashburn, Virginia
И там у вас есть, сервер Stackabuse находится в Эшберне, Вирджинии. Интересно =)
Для полного исходного кода проверьте проект на Github Отказ