React is the one of most famous JavaScript-frameworks. A lot of developers uses it in everyday development. Since its release, I saw a lot of different posts and articles about it. Different people leave theirs reviews and impressions. So, I tried to learn this framework and give to it some respect or discontent. In this article, I’ll look at React as a noob because I really the noob and doesn’t know this framework. You can say “Yet another article about React”, but it’s not. Let’s go!
Firstly, React is different from others frameworks like Angular or Backbone. It has its ideology, idea and style of development. Great example — mixing JavaScript and HTML markup inside one source file. Do you know others examples with this innovation? I’m not. React uses a brand new architecture — Flux which consists of following components — action, dispatcher, store and controller view. Do you remember that I’m the novice (yeah, noob) in React so I’ll dive into Flux soon.
The major advantage of the framework is the virtual DOM. Oops, I didn’t say — React is not MVC framework, the React is UI framework. Briefly, it’s use fake DOM that will be rendered only if you change something in your object (DOM element, view, component etc). I’ll show it in an example below. Virtual DOM makes React very fast and reactive, different benchmarks proves it.
Okay, it was the preface and now we can to start working with “Hello World”.
What do you need when working with React? You can start with this little starter kit or this JSFiddle. It contains JSX transformer that can help you turn JSX into valid JavaScript that can be used everywhere.
I created this HTML file and include all necessary scripts:
|
|
As you can see, the file has a script section with type “text/jsx”, so we can write all code here.
At first step, we should render “Hello World” in our HTML:
|
|
It’s easy, isn’t it?
If you would like clear JavaScript way, you can:
|
|
But this way is not perfect as the JSX :)
<h1>
is the built-in component. Base (or backbone) of the React is the components — headers, widgets, blocks etc. We can easily create own component:
|
|
And now we can use this component:
|
|
Cool, really cool!
Every component can have own state — it’s like a model for view in MVC. And here (I already said about it) every change of state cause re-render of the component and virtual DOM goes to real DOM:
|
|
We can update state with setState()
function:
|
|
Note, that in the example above I wrapped elements into div
block and use events. Events create something like two-way data binding. List of supported events you can read here.
Instead of states
you can use props
and pass some data into component outside itself:
|
|
Not sure that I should go deeper because it’s just review from the developer who never working with React.
React is great, although it’s UI framework, it can give huge abilities for a developer (fake DOM, components etc). React can work both on server and client, so you can preprocess JSX on server and then to give ready-to-work JavaScript to client.
In one evening, I’ve created a small project that can manage accounts, show them in list, filter and insert them (but it’s looking too ugly so I can’t show result here). It was just one hundred lines of code and I spent about four or five hours learning the framework. When I started to reading about React, I was fully zero. I’ve reading a couple of tutorials and watched screencasts before I started to understand it (it all happened in one evening). Now I can work with it, maybe as a noob or novice, but I can.
You can say that this article is not professional and you will be right. Every developer, good developer or not, should study new things, and they should share their knowledge between each other. New knowledge gives new opportunities and lets brain thinking brand new way.
Originally, post was published at Medium.
]]>React is the one of most famous JavaScript-frameworks. A lot of developers uses it in everyday development. Since its release, I saw a lot of different posts and articles about it. Different people leave theirs reviews and impressions. So, I tried to learn this framework and give to it some respect or discontent. In this article, I’ll look at React as a noob because I really the noob and doesn’t know this framework. You can say “Yet another article about React”, but it’s not. Let’s go!
]]>I tried to execute another examples:
Okay, it seems fantastic, because it’s not valid JavaScript expression. Let’s look deeper. I’ve put “console.trace()
” in executed expressions and tried to figure out how it works:
|
|
Now we can go through every stack trace item. First, “(anonymous function) @ VM336:2
”. This call on the top of the stack trace that has following code:
|
|
As we can see, Chrome wraps executed script. He does it because:
Only install command line api object for the time of evaluation. Surround the expression in with statements to inject our command line API so that the window object properties still take more precedent than our API functions.
Wrapping occurs on the next function call of the stack trace — on “InjectedScript._evaluateOn @ VM118:895
”.
If we will take a look on the last two functions, we’ll find that they do “wrapping-result-exceptions” operations:
|
|
After it we can a little better understand what happening inside this useful and necessary in development process tool.
Originally, post was published at Medium.
]]>localForage может быть установлен двумя способами - при помощи bower либо напрямую, скачав непосредственно минифицированную версию скрипта:
Вообще говоря, localForage позволяет хранить данные любого типа, будь то строки, числа, массивы, либо бинарные объекты. Список хранимых типов представлен ниже:
Для добавления и получения информации по некоторому ключу мы можем воспользоваться интуитивными методами setItem
и getItem
:
Также легко мы можем удалить элементы по ключу:
Помимо того мы можем очистить все хранилище, получить его размер, ключи, а также провести итерацию по всем ключам/значениям.
Простейшим образом мы можем указать список предпочитаемых хранилищ, используемых библиотекой:
Также мы можем указать название хранилища, его размер, версию и описание, воспользовавшись функцией localgorage.config( ... )
Если вас не устраивают хранилища, предлагаемые по умолчанию, вы можете добавить свой драйвер:
Таким образом localForage является удобной оберткой над хранилищами WebSQL, IndexedDB и localStorage, отделяя работу с хранилищами от непосредственной работой с данными, хранимыми offline.
]]>Валидация входных данных - это проверка этих самых данных на соответствие некоторым условиям. “Невалидные” данные, не удовлетворяющие определённым ограничениям или условиям, могут вызывать сбой в программе, порою весьма критичный. Давайте представим, что в каком-то месте выстреливает исключение, например, в момент когда программа пытается преобразовать строку некорректного формата в число. Если это исключение не обрабатывается где-то в программе, то есть вероятность, что произойдет аварийное завершение программы.
И падение программы - это только одна из неприятностей, которые могут произойти. Мы можем перехватывать исключение и восстанавливаться после сбоев. Однако это связанно с накладными расходами, что может ощутимо снизить производительность программы, что тоже не всегда является плюсом.
Кроме того, падения может вообще не произойти, но последствия от этого будут не менее плачевными. Если данные недостаточно проверяются, то это открытая дверь для внешних инъекций. Злоумышленник может получить несанкционированный доступ к данным или некоторым возможностям программы, либо способен вообще разрушить данные или программу.
Когда где-то внутри программы происходит исключительная ситуация, то не всегда есть возможность проследить причины ее возникновения. И даже если это возможно, то нужно как-то объяснить пользователю, что сбой вызван данными, которыми он ввел.
Все это и является причинами, по которым люди придумали валидировать данные, и в случае ошибочных данных немедленно сообщать об этом.
Этот пакет предоставляет простой интерфейс для проверки некоторых строковых данных на соответствие определенным условиям. У всех функций примерно одинаковый формат, вида func IsSomething(str string) bool
, причем таких функций достаточно много, почти на все случаи жизни.
Чтобы начать пользоваться пакетом, его нужно установить в вашем рабочем окружении:
Теперь мы можем пользоваться подключить пакет govalidator
в своем проекте и использовать его.
Если длинное название пакета вас не устраивает, можно заменить его на более краткое, например так:
Функций, доступных к использованию, очень много, большинство из них имеют сигнатуру IsSomething(str string) bool
. Кроме того, пакет имеет функции конвертации данных, например преобразование строк в числа и анонимные структуры.
Мы можем валидировать данные по отдельности:
либо валидировать сразу целую структуру. Для этого удобно использовать теги valid
, указывая таким образом, как необходимо проверить структуру. Если вы хотите применить к одному полю более одного валидатора, то перечисляйте их через запятую. В случае когда вам нужно пропустить валидацию - используйте -
в теге valid
:
Соответствие тегов и методов валидации приведено в этом списке. Если вам чего-то не хватает, то можно добавить свой валидатор к общему списку, устройство пакета приветствует это:
Теперь можем проверить всю структуру сразу:
Заметим, что пакет проверяет структуры рекурсивно, что еще более упрощает жизнь разработчика.
Как видите, использование специализированных валидаторов упрощает работу с данными.
Основную роль в пакете govalidator
играют пакеты reflect
и regexp
. Регулярные выражения нам нужны для сравнения строковых данных с паттернами:
Все регулярные выражения в пакете сразу компилируются, уменьшая время работы каждого валидатора.
Пакет reflect
используется для работы с типами, а также валидации структур. Так же при помощи него мы можем разбирать теги структур, а это не возможно без пакета reflect
:
Одним из самых ближайших аналогов является пакет github.com/go-validator/validator. Этот пакет также может валидировать структуры целиком, однако его функционал значительно беднее.
Вероятно, если вы пишете веб приложение, то вам стоит обратить внимания на более веб-ориентированные решения, такие как github.com/absoludity/goforms. Преимущество таких пакетов в том, что они являются надстройкой над http.Request
и используются для удобной работы с формами, в том числе и валидации данных из этой формы. Конечно, это значительно менее универсальный подход, который ограничивает область валидации данных.
Проблема валидации данных не нова, уже существует достаточное множество решений, разработанных с учетом потребностей пользователей, а также языков реализации. Самым ближайшим “родственником” данного пакета является JavaScript пакет validator.js. В языке Java сходную задачу решает BeanValidation.
Естественно, всегда найдутся критики, которые не только укажут на недостаток, но и помогут его решить. К примеру, некоторые были удивлены тем, что некоторые функции пакета являются просто надстройкой над стандартными функциями Go. Некоторые были удивлены тем, что проверка email адресов производится на основе регулярного выражения. По их мнению, гораздо лучше послать сообщение конечному пользователю, убедившись таким образом не просто в корректности адреса, а в его реальности. Но в целом пакет принят комьюнити и активно им поддерживается, за полгода существования приняты и внесены десятки пулл-реквестов, улучшающих пакет в разы.
Валиция всегда была и остается очень важной проблемой, которая должна решаться в рамках любого приложения. К счастью, уже написано множество пакетов, которые выполняют за нас часть работы. Для внедрения максимально надежной, гибкой и универсальной валидации данных можно и нужно использовать пакет govalidator.
Данная статья была первоначально опубликована вот здесь, за что отдельное спасибо Артему Ковардину.
]]>Задача, мягко говоря, не совсем обычная, и возникает она у модмейкеров не слишком часто, однако после изучения API я обнаружил то, что мне нужно.
Данное событие вызывается системой, когда игрок наводит курсор на слот, заполенный некоторым предметом. Событие содержит три поля: ItemStack
, который вызвал это событие, список текстов для подсказки, а также флаг showAdvancedItemTooltips
, указывающий на то, что подсказка вызывается в режиме отображения дополнительной информации, которая, кстати говоря, активируется клавишами F3 + H
. Класс события расположен в пакете net.minecraftforge.event.entity.player
.
Подписка ничем не отличается от подписки на другие события. Создаем класс, в котором описываем некоторый метод, принимающий в качестве аргумента событие, а затем вешаем на метод аннотацию SubscribeEvent
:
После чего подключаем экземпляр к шине событий Forge:
Собственно, ничего сложного, достаем из события список текстов и добавляем в него свои тексты:
На примере выше мы добавим к подсказке нелокализованную версию имени блока.
Опционально мы можем сделать наши тексты более яркими. Воспользовавшись перечислением EnumChatFormatting
из пакета net.minecraft.util
мы можем сделать текст таким, как хотим этого мы. В качестве примера сделаем слова Unlocalized name:
из примера выше голубого цвета, а шрифт изменим на курсив:
Вот собственно и весь результат:
]]>В связи с этим хотелось бы рассмотреть, как же такие известные фреймворки внедряют поддержку Material Design. Рассмотрим это на примере Angular.js.
Установка ничем не отличается от установки большинства пакетов - нам достаточно иметь установленный bower:
Такой способ гораздо предпочтительнее, хотя есть вариант с использованием CDN. С ним мы можем попробовать поэкспериментировать прямо в CodePen или JSFiddle:
В данном случае разметка построена на современном flexbox’е, что, несомненно, является подспорьем в мире адаптивных сайтов. Фремворк вводит специальные теги и атрибуты, при помощи которых можно построить нужный нам интерфейс. Так, для разметки используется тег div
с различными атрибутами, например layout
или flex
.
Фреймворк предлагает к использованию различные компоненты - кнопки, поля ввода, радио-кнопки, вкладки, сайд-бары, подсказки и тому-подобное. В каждый из них мы вникать не будем, мы только рассмотрим общую структуру построения приложения с использованием Material Angular.
А попробуем мы вот что: мы напишем маленькое, но практичное приложение - простейшую анкету пользователей. Действовать она будет примерно так - две вкладки, в одной поля ввода отдельного человека, во второй вкладке список введенных пользователей.
Первым делом опишем две вкладки и основу приложения. Приложение мы создаем стандартно - ничего особенного в нем нету:
Теперь описываем div
, к которому будет привязано приложение и контроллер. Внутри него разместим вкладки md-tabs
, а также ng-switch
, который будет описывать содержимое каждой вкладки отдельно. Также сделаем привязку к модели data.selectedIndex
, чтобы иметь возможность контролировать текущую вкладку:
Я думаю, вы заметили, что элементы с префиксом md-
относятся к Material Design, а ng-
- стандартные элементы Angular.
Теперь опишем поля ввода для первой вкладки. Для этого воспользуемся тегом md-whiteframe
для создания пустого окна, а в нем разместим непосредственно поля ввода, как на примере ниже:
На самом деле кода получается гораздо больше, однако там везде все аналогично - создается контейнер, метка и поле ввода, создается привязка к модели и вуа-ля!
Легко добавить проверку данных. Так, например, мы легко можем добавить ограничение по длине вводимого текста:
Добавим кнопку сохранения данных:
Для этой кнопки нам необходимо описать в контроллере функцию save
, а также добавить прикрепить ее к самой кнопке:
|
|
Собственно теперь нам необходимо реализовать базовый функционал контроллера AppCtrl
. Все делается стандартно, ничего неожиданного тут нету. Мой контроллер выглядит примерно так:
После того, как мы реализовали контроллер на сохранение анкет, нам надо реализовать их вывод. Поддержка “материальных” списков реализуется при помощи тегов md-list
и md-item
, а сам Angular предлагает атрибут ng-repeat
, которым запросто можно пробежать по всем элементам некоторого списка. Реализуем вывод списка:
Теперь реализуем кнопку удаления отдельного элемента. Material Angular вводит поддержку специальных сервисов, таких как диалоги, подсказки. Реализуем диалог подтверждения удаления пользователя. С этим нам поможет сервис $mdDialog
, предлагающий несколько вариантов модальных окон. Помимо этого он позволяет нам реализовать свое модальное окно. Здорово, не правда ли? Подключим к кнопке удаления функцию delete
:
В функцию будет передаваться индекс выбираемого элемента и событие, которое мы отдадим сервису. Реализуем функцию delete
. Диалоговое окно создается весьма просто - создается объект и путем последовательного применения нужных команд этот самый объект настраивается:
После того,как объект был создан, его можно вызвать,указав колбэк-функции, которые будут вызваны в случае нажатия одной из кнопок.
Собственно теперь весь основной функционал реализован и можно заняться внедрением своих “фич” и стилизацией. Однако, если вы хотите, чтобы вся “материальность” была сохранена, то вам стоит почитать официальную спецификацию.
See the Pen myMyXx by Alex Saskevich (@asaskevich) on CodePen.
Собственно это все, что я хотел показать, весь код статьи расположен на CodePen вот тут: http://codepen.io/asaskevich/pen/myMyXx. Ну а сам Angular Material Design вместе с примерами и документацией расположен тут: https://material.angularjs.org.
Данная статья была первоначально опубликована вот здесь.
]]>В связи с этим хотелось бы рассмотреть, как же такие известные фреймворки внедряют поддержку Material Design. Рассмотрим это на примере Angular.js.
]]>Для использования библиотеки на стороне сервера нужно установить ее при помощи npm
или bower
:
Для использования на стороне клиента нужно скачать необходимые файлы и подключить их на вашу страницу.
Начнем с того, что научимся превращать текущее время в удобочитаемый вид. Библиотека поддерживает много локализаций, среди них русский и английский. Все делaется просто - получаем текущее время и дату и форматируем его вывод:
Moment.js поддерживает вывод локализированной информации о том, сколько времени прошло/осталось с какого-то события. Удобно, если нужно использовать, например, при выводе информации о времени создания публикации в блоге или личного сообщения, например User оставил вам сообщение 5 минут назад
:
Библиотека позволяет не только форматировать даты, а еще вычитать или изменять их:
Помимо всего прочего, библиотека имеет подмодуль Moment Timezone, позволяющий работать с часовыми поясами:
Прежде чем ставить Grunt, убедитесь, что у вас установлен Node.js. Если не установлен - следуйте данной ссылке, после чего можно перейти к процессу установки Grunt’a.
Следует заметить, что хоть данная команда подготавливает к использованию команду grunt
, сам Grunt еще не установлен.
Также я установил grunt-init
, который позволяет быстро и легко инициализировать проект по некоторому заданному шаблону:
Далее нужно перейти в папку .grunt-init
(На Windows у меня c:/Users/User/.grunt-init
), и там установить шаблон, например шаблон нового npm-модуля:
Так как я сразу поставил утилиту инициализации нового проекта, мне не придется руками прописывать всю информацию в Gruntfile.js
, я всего лишь выполню grunt-init node
. После чего мне будет создан проект со следующей структурой (может отличаться):
Как видим, всю работу мы проводим в File.js
, тесты пишем в File_test.js
, конфигурируем проект в package.json
, настраиваем Grunt в Gruntfile.js
и так далее.
В папке проекта сначала нужно выполнить локальную установку Grunt:
Затем уже можно выполнять grunt
. Если система сообщает об отсутствии каких-то компонентов, нужно их также установить, например:
Так как Grunt работает в первую очередь с задачами, стоит научиться их конфигурировать и создавать. В качестве примера добавим минификацию готового проекта. Данную задачу решает grunt-contrib-uglify
из примера выше. Так как командой из примера выше мы уже узнали, как ставить локально новые зависимости, мы можем перейти непосредственно к редактированию Gruntfile.js
. Добавим задачу:
Затем сконфигурируем:
Добавляем задачу в набор задач, выполняемых по умолчанию:
Если все сделано верно, при следующем запуске grunt
мы получим на выходе минифицированный файл проекта.
Если ваш проект еще не настроен для работы с средствами автоматической сборки, менеджерами задач, лучше это сделать сейчас. Таким образом получится сэкономить много времени, которое, вместо того, чтобы быть потраченым на ненужные мелочи, будет потрачено с толком и гораздо большей пользой.
GNU Compiler for Java (GCJ или gcj) — это свободный компилятор языка Java, являющийся частью GNU Compiler Collection. GCJ может компилировать исходный код Java в байткод виртуальной машины Java, либо непосредственно в машинный код многих процессорных архитектур. Он также может компилировать файлы классов, содержащие байткод, или целые JAR, содержащие такие файлы, в машинный код.
В unix-системах достаточно выполнить команду установки пакета apt-get
:
В результате будет скачано и установлено около десяти мегабайт ресурсов. После чего инструмент готов к использованию.
Пишем Java код, компилируем в бинарник и запускаем:
Строка --main=Test
говорит о том, что точка входа в приложение находится в классе Test
.
*.java *.jar *.class
*.class
файлаКонечно, плюсов и минусов может быть больше - я лишь поверхностно рассмотрел данный вопрос. Использовать JVM/JDK все же привычнее, но не стоит упускать из вида и данный инструмент - например, если вдруг придется писать приложение для устройства, ограниченного в ресурсах, а для этих целей хочется использовать язык, который знаешь лучше всего (в данном случае Java).
]]>GNU Compiler for Java (GCJ или gcj) — это свободный компилятор языка Java, являющийся частью GNU Compiler Collection. GCJ может компилировать исходный код Java в байткод виртуальной машины Java, либо непосредственно в машинный код многих процессорных архитектур. Он также может компилировать файлы классов, содержащие байткод, или целые JAR, содержащие такие файлы, в машинный код.
|
|
По сравнению с Jekyll, имеет улучшенную поддержку плагинов, тем, многие средства, которые в Jekyll отключены, здесь используются по умолчанию (например пагинация или “убирание” постов “под кат”).
Встроенная поддержка Markdown просто замечательна - набирать текст легко и удобно. Чаще всего, написав саму статью, достаточно потратить минуты три, дабы отформатировать содержимое. Естественно, это не единственный плюс Octopress, их вообще можно перечислять и перечислять, но этим я пока заниматься не собираюсь. Просто советую данный движок к использованию в своем блоге.
|
|
По сравнению с Jekyll, имеет улучшенную поддержку плагинов, тем, многие средства, которые в Jekyll отключены, здесь используются по умолчанию (например пагинация или “убирание” постов “под кат”).
]]>
Backbone.Router
Создавая свой маршрутизатор, нужно расширить Backbone.Router
, добавив в него описания маршрутов и действий:
|
|
Сами маршруты могут быть динамическими:
|
|
Используя функцию on
мы должны связать событие перехода по некоторому адресу с некоторым действием. Так, описав в списке маршрутов:
|
|
необходимо описать событие:
|
|
Это означает, что при переходе по адресу #/profile/10
будет генерироваться событие route:viewProfile
, которое будет обработано соответствующей функцией, принимающей в качестве аргументов id
маршрута.
Во время загрузки страницы, после того, как приложение создаст все необходимые ему маршрутизаторы, нужно вызвать Backbone.history.start()
или Backbone.history.start({pushState: true})
, чтобы задать начальное состояние приложения.
Как видим, достаточно просто описать все необходимые действия приложения, пользуясь только маршрутизаторами, не используя дополнительные страницы или скрипты.
username.github.com
|
|
|
|
Файл _config.yml
хранит в себе основные параметры: название сайта, адрес, активный плагин комментариев и аналитики, контакты владельца и прочая информация.
Следует данный файл настроить под себя, дабы не было неожиданных ошибок.
Дизайн блога легко настраивается. Если вас не устраивает исходный дизайн, всегда можно заменить его другим. Основные темы расположены тут
Для создания новой записи достаточно выполнить команду:
|
|
После ее выполнения вы найдете файл _posts\YYYY-MM-DD-title.md
- файл новой записи в блоге, которую после нужно подредактировать - оформить содержимое, теги, описание и категории. А в конце просто залить все на git.
Конечно, я рассказал максимально сжато, но надеюсь, что этой информации окажется достаточно, чтобы запустить свой блог на GitHub Pages. Я оформил этот блог буквально за один вечер, или около 3 часов (установка, настройка, редизайн, локализация, основной контент).
Java Native Interface (JNI) — стандартный механизм для запуска кода, который написан на языках С/С++ или Ассемблера, и скомпонован в виде динамических библиотек, позволяет не использовать статическое связывание. Это даёт возможность вызова функции С/С++ из программы на Java, и наоборот.
Если говорить кратко, JNI - механизм, связывающий Java и C/C++ в одно целое.
Со стороны Java нам нужно описать класс, загружающий динамическую библиотеку и имеющий в себе описание функций, расположенных в библиотеке:
|
|
Следующим этапом необходимо создать заголовочный файл библиотеки для дальнейшей работы с динамической библиотекой:
|
|
После выполнения данных команд в терминале мы получим файл Main.h
примерно такого содержания:
|
|
Как видим, в нашем заголовочном файле уже описана функция Java_Main_libraryFunc
, которая расположена в классе Main
и называется libraryFunc
. В динамической библиотеке функция принимает дополнительные аргументы - окружение и класс.
Переходим к файлу Main.c
, в котором опишем реализацию функции Java_Main_libraryFunc
:
|
|
Теперь этот небольшой модуль нужно скомпилировать в динамическую библиотеку:
|
|
Также нужно иметь ввиду, что разрядность библиотеки должна быть такой же, как и разрядность JVM.
После того, как библиотека скомпилирована, достаточно загрузить ее и вызвать нужную функцию:
|
|
JNI - отличное средство для более близкого взаимодействия с системой. Все, что нельзя сделать средствами чистой Java, можно сделать на С/С++ и вызвать из Java. Единственным вопросом остается производительность - в каких случаях стоит обратиться к нативному коду, а в каких достаточно воспользоваться стандартными средствами.
Про установку и настройку серверной части говорить не интересно, потому приведу команды, которые я выполнил в консоли (предварительно установив node.js и npm):
|
|
Обращу внимание на то, что я сделал в конце: я создал новое приложение todo
, sails любезно создал всю структуру файлов, затем я создал API: шаблон для модели Task
и соответствующий ему RESTful контроллер, а также контроллер Main
. Все это интересно и непонятно. Task
будет хранить информацию о задачах, а контроллер выводить страницу с их списком. Создав модель, sails так же любезно создал нам набор RESTful API с CRUD методами так, что уже сейчас, запустив приложение и перейдя по адресу localhost:1337/Task/
можем увидеть все модели Task
. Скажем, не модели, а объекты.
Task
Далее идем в api\models\Task.js
, где создаем все поля для модели. Нам хватит поля текста задачи и логического поля, выражающего завершенность задачи:
|
|
В принципе тут мы со всем разобрались. У нас есть два поля, мы определили их название и типы. Перейдем к контроллеру.
Main
Идем в api\controllers\MainController.js
. Там создаем следующее содержимое:
|
|
Теперь заглянем в confir\routes.js
. Здесь мы прописываем, что хотим вызывать функцию index
из нашего контроллера по запросу корня сайта (За нас конечно уже прописан шаблон homepage
, но ведь это не то, что мы хотим), потому делаем так:
|
|
Попробуем все это дело запустить. Выполняем sails lift
и получаем ошибку, что у нас не стоит адаптер sails-disk
для работы с локальной БД. Ставим и пробуем еще раз. Запустилось! Переходим на сайт и получаем ошибку - не задан шаблон для контроллера.
Создадим в папке view\main\
файл index.ejs
- файл нашего будущего шаблона. Собственно название шаблона мы могли прописать сразу в роутере, но через контроллер нагляднее и интереснее. Содержимое файла будет следующим:
|
|
Обратим внимание на <%= count %>
- это параметр, который мы передадим в контроллере вот так:
|
|
Где вместо пропуска будет получение общего количества записей.
Для начала подключим все необходимые библиотеки:
|
|
Создадим нашу модель, указав адрес, по которому она обрабатывается:
|
|
Далее нужно описать коллекцию, которая хранит все модели:
|
|
Проинициализируем коллекцию и загрузим ее с сервера:
|
|
Далее привяжем к нашей кнопке событие добавления записи:
|
|
Теперь осталось описать вид и рендер коллекции. Шаблон будет таким: {{ }}
, дабы не было конфликтов с шаблонами Sails.js:
|
|
Теперь осталось самую малость - описать вид:
undefinedВсе, создаем объект вида и тестируем: var mView = new TaskView({collection: tasks});
. Кнопка добавления добавляет новую запись сразу в коллекцию, а также синхронизируется с сервером, потому, если перезагрузить страницу, данные никуда не пропадут. Конечно, стоит позаботиться о серверной части, дабы в реальном приложении нельзя было удалить записи из базы, просто перейдя по нужной ссылке API.
Скажу просто - это круто. Никаких особых заморочек с БД, нету особых сложностей с клиентской частью, да и с серверной. По сути - описать контроллеры, модели, шаблоны, сделать их связку, описать работу моделей и коллекций в клиентской части - и все готово. Ради интереса гляну еще некоторые MVC фреймворки, не только для Node.js, но и для других языков.
Backbone.js придает структуру веб-приложениям с помощью моделей с биндингами по ключу и пользовательскими событиями, коллекций с богатым набором методов с перечислимыми сущностями, представлений с декларативной обработкой событий; и соединяет это все с вашим существующим REST-овым JSON API.
Что ж, было бы неплохо попробовать его в действии.
За HTML-основу один из сайтов предлагает следующее:
|
|
Все необходимое подключено и мы можем начать наши эксперименты.
Фреймворк позволяет назначать DOM элементам свои шаблоны, рендер и многое другое. Давайте попробуем.
Для начала создадим DOM элемент:
|
|
Перейдем к JS. Для начала создадим пустой вид:
|
|
Затем нам необходимо указать функцию рендера:
|
|
Но сама себя эта функция не вызовет, ее нужно вызвать, например при инициализации:
|
|
Осталось создать объект вида для дальнейшей работы:
|
|
Так как Backbone жестко завязан на underscore.js, мы можем воспользоваться множеством различных утилит и функций из нее. Так, например, мы можем использовать шаблоны. Синтаксис вызова такой: _.template(шаблон, [данные], [параметры])
.
Итак, добавим в наш вид поле шаблона:
|
|
Обратите внимание на <%= who %>
. Это параметр, который будет загружен из аргумента “данные”. Все, что нам нужно, вызвать шаблон в рендере. Например так:
|
|
Разницы между <%= %>
и <%- %>
нету. Однако при помощи <% %>
мы можем выполнять любой JS код.
Изначально кажется, что мы проделали слишком много действий лишь для того, чтобы вывести стандартную надпись Hello World
. Да, это так. Но продолжив изучение фреймворка и используя его в крупном веб-приложении, мы несомненно увидим, что мы сохранили много времени и сил, не пытаясь изобретать велосипед при создании динамического приложения. Далее в планах познакомится с фреймворком глубже, а также обратить внимание на Angular.js - фреймворк с похожей задачей - упростить создание динамических веб-приложений.
На примере небольшого приложения, авторизирующего пользователя и получающего его последние уведомления с данными профиля, мы рассмотрим, как пользоваться Stack Exchange API.
Прежде чем создавать свое приложение, необходимо зарегистрировать его в StackApps. Это необходимо, чтобы получить ключи доступа для него. Переходим по этой ссылке и заполняем все поля, не помеченные пунктом optional. Для своего туториала я заполнил поля так:
Не забываем поставить галочку в «Enable Client Side OAuth Flow»
. Это необходимо для OAuth — иначе пользователь просто не сможет войти в систему, пользуясь приложением. Когда все заполнили, жмем соответствующую кнопку, и переходим на страницу управления приложением. Там мы получим несколько ключей (Client Id
, Client Secret
, Key
). Из них для самого приложения нужны только ClientId
и Key
. Сохраняем их и на этом мы завершаем процесс регистрации и переходим непосредственно к написанию самого приложения.
Создадим новый чистый HTML файл и сразу подключим в нем скрипт:
|
|
Теперь мы можем воспользоваться базовыми функциями инициализации и авторизации для дальнейшей работы. Помимо key
и clientId
, для инициализации нам необходимо передать два дополнительных параметра - домен и callback-функция:
|
|
Если вы все сделали верно, то при загрузке страницы должен выскакивать alert :) Иначе проверьте вывод консоли — нет ли там чего подобного на Uncaught channelUrl must be under the current domain
? Если есть — перепроверьте channelUrl
. Иначе стоит проверить параметры приложения в панели управления на сайте.
Изменим предыдущий код, а именно: создадим прототип функции auth(data)
и укажем ее в SE.init
как функцию, вызываемую при успешной инициализации:
|
|
Теперь самое время писать авторизацию. Здесь тоже все просто:
|
|
Этот код я поместил в тело auth(data)
. Теперь, при первой загрузке страницы должно появиться всплывающее окно. В нем вам будут предложены две кнопки — на разрешение и запрет доступа для приложения:
Однако пока мы просто авторизируемся и ничего не делаем с полученными данными. А ведь в случае успеха нам будут отданы клиентские токены для дальнейшей работы. Давайте сохраним их где-нибудь. Например так — создадим некоторую глобальную переменную, которая будет хранить эти самые токены:
|
|
Теперь, когда мы умеем авторизировать пользователя, можно перейти к непосредственной работе с API.
API возвращает нам ответ на запросы в формате JSON. Это значит, что данные, загруженные посредством JS, легко будут переведены из строкового формата в некоторую структуру. Запросы будут кросс-доменные, и потому я воспользуюсь jQuery.
Данные о пользователе будем получать вот здесь:
|
|
Некоторые данные о пользователе (например рейтинг или значки) зависят от того, на каком сайте сети Stack Exchange запрашивается профиль. Данные, полученные с StackOverflow и с MathOverflow, могут различаться. Название сайта можно посмотреть в самой системе. Окей. Если просто запросить данные по ссылке, мы получим что-то вроде такого json’a:
|
|
Все возможные ошибки можно глянуть тут
А ведь же нам нужно указать токены доступа! Для этого к нашему адресу выше мы прицепим эти самые токены:https://api.stackexchange.com/2.2/me?site=[название сайта]&key=[ключ приложения key]&access_token=[tokens.accessToken]&callback=[method]
Здесь tokens.accessToken
как раз ранее полученный в процессе авторизации ключ пользователя, а method — колбэк, который будет вызван в конце загрузки. Ответ будет примерно таким:
|
|
С такими данными визуально сложно работать, и потому я создам callback функцию, которая будет рендерить полученную информацию в небольшую табличку:
|
|
Саму информацию я получал через GET запросы примерно так: $.get("https://api.stackexchange.com/2.2/me?site=stackoverflow&key=YoUrAwEsOmEKey&access_token=YoUrSecretToKEn&callback=profile");
В итоге у меня получился такой результат:
Для того, чтобы наше приложение могло получать информацию о непрочитанных сообщениях, уведомлениях, ему нужно предоставить определенные права доступа. В случае с уведомлениями это read_inbox
. Ставим его в блоке авторизации приложения:
|
|
Данные об уведомлениях мы получим вот тут: https://api.stackexchange.com//2.2/notifications?pagesize=[число последних уведомлений]&key=[ключ приложения]&access_token=[токен доступа пользователя]&callback=[callback-метод]
Мы можем не указывать число последних уведомлений, но тогда мы получим сразу все уведомления. Запрос выполняется аналогично предыдущему, ответ будет примерно таким:
|
|
Как видим, в данном случае система сразу отдает нам массив уведомлений. И с ними достаточно просто работать:
|
|
В итоге страничка моего маленького приложения приобрела вот такой окончательный вид:
А вот собственно фрейм, с которым можно “поиграть”:
API сети Stack Exchange позволяет нам не только получать уведомления или данные профиля. Мы также можем получить вопросы, комментарии, теги, причем мы сможем также взаимодействовать с ними (добавлять вопросы, редактировать свои комментарии). Мы можем работать с профилем пользователя, событиями и статистикой.
Кстати о статистике — в панели управления приложением можно просмотреть статистику авторизаций и запросов в виде графиков. И да, стоит иметь ввиду, что число запросов, которое может сделать приложение к отдельной функции, ограничено десятью тысячами. Оставшееся число запросов пересылается нам вместе с JSON ответом в поле «quota_remaining»
.
В документации также можно будет поэкспериментировать с запросами. Для этого StackExchange предлагает консоль, которую можно найти под описанием каждой функции.
В оргиниале данная запись была опубликована тут
]]>nil
(а еще логический тип)Как и в любом нормальном языке, в Clojure присутствует все необходимое для хранения информации. Начну с числовых типов.
|
|
Воспользуемся оператором class
, дабы узнать каждый тип:
|
|
Прекрасно, не правда ли? Теперь взглянем на логический тип. Ему соответствуют два значения: true false
. Однако существует один важный момент - nil
, о котором мы говорили ранее, также относится к false
.
Cтроки в языке мы рассматривали ранее. Это был некоторый текст, заключенный между двойными кавычками.
Немаловажным типом для нас является тип map
, позволяющий хранить пары ключ-значение. Ключем и значением может быть любой тип, будь то строка, другой map
или даже функция. Чтобы инициализировать карту, мы поступим следующим образом:
Пары ключ-значение можно разделять запятыми, это видно по последним двум примерам. Получать значения из карты можно функциями get
или get-in
. Единственное отличие второй функции от первой в том, что она позволяет получать значения из вложенных карт:
С векторами все просто - он очень похож на обычный массив с нулевой индексацией. Не буду долго тянуть, потому вот вполне понятные примеры:
|
|
О них тоже пока много сказать не могу. Скажу только вот что - как они объявляются и какие основные функции мы можем применять:
|
|
Думаю, вникнув в суть предыдущих структур данных, для множества хватит просто примеров:
|
|
Думаю, на этом пора заканчивать, все это вполне интересно, но следующей не менее крупной темой будет тема функций - создание, вызов, анонимные функции, макрофункции и прочие прелести.
Clojure: первое знакомство
.Структура оператора вполне привычна для других языков, за исключением того, что скобки располагаются не в зоне условия, а вокруг всего блока оператора:
|
|
Напишем маленький пример:
|
|
Единственное ограничение состоит в том, что здесь мы можем использовать только одно действие (написать сложную конструкцию из других операторов и функций не получится). Специально для этого в языке есть оператор do
do
Оператор служит для объединения вызова нескольких команд вместе:
|
|
Теперь мы можем переписать условие так, чтобы оно вывело, например результат умножения 5 * 5
и строку “Hi”:
|
|
Красота да и только!
when
Данный оператор как бы является комбинацией if
и do
, однако без формы else
:
|
|
Вообще, большинство переменных в языке не совсем переменные - они неизменяемые. Однако это не помешает нам переприсваивать новое значение старой переменной:
|
|
Мы объявили переменную x
, присвоили ей значение 10
, а потом изменили ее значение и тип на строку. Можно сделать и так:
|
|
Объявили переменную и увеличили ее значение на единицу. Не исключаю, что есть более элегантная форма решения этого действия.
Рассмотрели, всего-то, операторы if
, def
, do
, when
. В книге, ссылка которой указана в самом начале, следующей темой будут структуры данных. Тема весьма крупная, потому я выделю под нее отдельную статью.
Начну с самого простого и традиционного - “Hello, World!”. Так как Clojure имеет некоторый Lisp-синтаксис, нам придется свыкнуться с мыслью о том, что нас ожидает великое множество скобочек:
|
|
Что это за nil
? Как я понял, листая примеры, это значит, что функция println
ничего не вернула, а ничего - это nil
или null
в Java.
В целом, синтаксис вызова функции такой: (func arg1 arg2 .. argN)
. Так, выше func
это println
, а единственный аргумент представлен в виде строки "Hello, World"
После этого я решил глянуть, как обстоят дела с примитивной арифметикой - сложение, вычитание, деление, умножение. И тут меня ждал сюрприз:
|
|
Как видим, деление вернуло результат в виде рациональной дроби. А что, если попробовать так?
|
|
Если возможно провести целочисленное деление, язык делает это совершенно самостоятельно.
А как получить остаток от деления? В С или Java это %
, но тут это уже не работает. Мысленно перебирая варианты, пробую такие названия функций: mod
rem
. И каково мое удивление, эти оба варианта работают и выполняют одно и то же действие. Сказать, зачем это сделано, я не могу, потому просто будем использовать то, что первое придет в голову:
|
|
Строки в языке записываются также, как и в большинстве других языков - между двойных кавычек:
|
|
С поиском в строке вышло немного труднее - не имея представления о том, как нужно делать вызов функций из Java, я пытался получить indexOf
из java.lang.String
. Но, полазив по официальному сайту, нашел:
|
|
Давайте еще глянем на такие вещи, как списки, множества, вектора и карты:
|
|
Язык предлагает поддержку различных типов этих структур - сортированные, хеш-, неупорядоченные.
Для первого достаточно, позже я рассмотрю управляющие операторы, функции, переменные. Конечно, можно писать и писать, однако мне кажется, что уже размер статьи стал несколько большим, потому продолжу знакомство в следующей статье.
В компьютерных науках модель акторов представляет собой математическую модель параллельных вычислений, которая трактует понятие «актор» как универсальный примитив параллельного численного расчёта: в ответ на сообщения, которые он получает, актор может принимать локальные решения, создавать новые акторы, посылать свои сообщения, а также устанавливать, как следует реагировать на последующие сообщения.
Что ж, суть вполне понятна и проста. Попробуем написать набор из акторов, один из которых по запросу генерирует следующее число Фибоначчи, а другой запрашивает генерацию.
Для начала импортируем необходимые классы:
|
|
Затем опишем сообщения, которые могут пересылать акторы:
|
|
Generator
Данный актор будет вычислять новые числа Фибоначчи. Для того, чтобы это действительно был актор, нам нужно унаследовать его от scala.actors.Actor
и реализовать функцию def act() { .. }
. Внутри функция должна иметь конструкцию receive { .. }
, которая и займется обработкой сообщений:
|
|
Sender
Данный актор будет иметь схожую с предыдущим актором архитектуру, потому приведу просто его код с некоторыми пояснениями:
|
|
Для всего этого нам понадобится только несколько строчек:
|
|
Также я попробовал запускать акторы в другом порядке - сначала Sender
, а потом Generator
, но даже так все отработало прекрасно.
Все же Scala предлагает мощную поддержку многопоточности “из коробки”. Уже после того, как я “поиграл” с акторами, я выяснил, что текущая версия Scala имеет немного другую систему, которая разительно отличается от той, с которой я впервые познакомился. Также несомненно радует наличие таких вещей, как реакторы, расписания, каналы и др. В целом это во много раз лучше, чем создавать громоздкую конструкцию из потоков на чистой Java.