Страницы

Поиск по вопросам

пятница, 5 июля 2019 г.

Проверка синтаксиса rst-файла

У меня проблема с описанием (в формате rst, reStructuredText) пакета на pypi
README.rst прекрасно форматируется на github и readthedocs но в pypi rst не работает.
Есть ли способ решить эту проблему без копипаста README (в README.md например)?


Ответ

для проверки синтаксиса можно воспользоваться, например, программой rst2html (из пакета python-docutils). примерно так:
$ rst2html README.rst > /dev/null README.rst:35: (WARNING/2) Literal block expected; none found. README.rst:66: (WARNING/2) Literal block expected; none found. README.rst:91: (WARNING/2) Literal block expected; none found. README.rst:119: (WARNING/2) Literal block expected; none found. README.rst:133: (WARNING/2) Literal block expected; none found. README.rst:142: (WARNING/2) Literal block expected; none found.
из вывода видно, какие строки «не нравятся» парсеру.
насколько я понимаю, нужно лишь добавить по пробелу в начало этих строк (а потом ещё и в 134-й: про неё будет warning после исправления 133-й строки).

кстати, у этой программы есть и «основная» функция — генерация html
$ rst2html README.rst > readme.html
после этого readme.html можно просмотреть в браузере.

в том же пакете есть ещё ряд полезных программ, начинающихся с rst2 и делающих аналогичные преобразования в разные форматы:
rst2latex rst2man rst2odt rst2odt_prepstyles rst2pseudoxml rst2s5 rst2xetex rst2xml
и у каждой из этих программ есть множество опций. подробности смотрите, например, с помощью программы man
$ man rst2html

Разложение проекта по директориям

Как правильней разложить проектные файлы по директориям?
Некоторые ide генерируют папки source, headers, objects c абсолютно идентичной иерархией директорий, но находятся там файлы с разным расширением. Встречал когда одна иерархия директорий проекта, но h и cpp файлы вместе сложенны.
Какой способ правильней и чем?


Ответ

Для мелких проектов группировка по типам может быть удобна.
Но чем больше проект, тем менее удобной будет группировка по типу файлов. Всё время придётся держать несколько папок развёрнутыми. Например, ты меняешь что-то в cpp-файле, что требует внести изменения и в h-файл. И вот у тебя уже одновременно в solution explorer'е до одной и той же сущности развёрнуто два весьма жирных каталога. Поэтому лучше сгруппировать логически на основе сущностей, сложив всё, относящееся к одной сущности, в одну папку.

Создание git репозитория, состоящего из разных папок

Только осваиваю git, возник вопрос, на который я не могу найти в поисковике ответ. Возможно, я не правильно формулирую саму задачу.
Есть такая структура в папке моего локального веб-сервера
server_folder --my_project_logic --localhost ----my_project_webresource ----othersite1 ----othersite2 ----...
Мне надо создать один репозиторий с 2 папками my_project_logic и my_project_webresource, которые находятся на разных уровнях вложенности.
Подскажите, пожалуйста, где лучше инициализировать репозиторий?
Пока придумалось только одно решение - инициализировать репозиторий на папку server_folder, и в .gitignore прописать исключение на все, кроме этих двух папок. Есть ли решения поизящнее?


Ответ

Я правильно понимаю, что othersite1 - это совсем другой проект и мешать с Вашим его не нужно, а папка server_folder находиться в папке вебсервера? Это чревато проблемами в будущем. К примеру, захотите делать деплой через git (просто сделав pull), а это очень плохо - даже yandex на это натыкался.
Хорошо сделать так. В домашнем каталоге делается папка с проектом, где все хранится. В результате развернуть там git не будет проблем - все будет только от одного проекта. А дальше делается скрипт, который с помощью rsync или других утилит копирует файлы по местам. Понятно, что для разработчика все копировать постоянно - накладно, поэтому, можно просто создать две симлинки (собственно это скрипт также может делать).
Но если пойти ещё дальше, то лушче сделать так. Под проект заводиться виртуальное окружение (lxc, docker, rocket или просто virtualbox). В результате на одно окружение будет один проект и не будет никаких проблем.

Х без мыши, или mouse jail, или?.. подробности

Этот вопрос гугленьем я не решил однозначно, поэтому прошу совета. Именно совета, а не прямого решения.
Есть Хvesa без оконного менеджера, в ней висит dosbox. Х почему-то всегда запускается с мышью, даже когда я намеренно убираю мышиные параметры из строки запуска в .xsession . И это мешает, потому что в Xvesa по умолчанию (без менеджера, очевидно) та забавная система фокусировки, когда регион получает фокус только когда курсор мыши находится в нем. Стоит отвести мышь в сторону от окна - и любое управление с клавиатуры замораживается. Можно ли заставить Xvesa использовать другой алгоритм фокусировки без использования менеджера, я тоже не нашел в гугле. Вдобавок y мыши два курсора: один снаружи "коробки", другой внутри. Когда один подходит к границе, то застывает рядом с ней, а второй "оживает" и продолжает движение. Залочить курсор внутри dosbox не получается, возможно, потому что это должен делать менеджер окон.
Вот и вопрос. Что лучше:
Использовать чей-то самописный скрипт или бинарник, реализующий принцип mouse jail, ограничивающий движение мыши в заданном регионе. Использовать более "официальный" xdotool Запустить Xvesa без мыши, чтобы она инициализировалась только в dosbox. Если да, то как?
Второму варианту я не доверяю, т.к. в голове почему-то отложилось, что xdotool делает вещи неоптимально и может давать слишком большую нагрузку для маленькой задачи. Не то, чтобы у меня может чего-то не хватить, но я потому и пытаюсь все сделать так, как делаю, чтобы ради собственного удовольствия обойтись наименьшими ресурсами. Сейчас система жрет 40 Мб ОЗУ, куда уж больше. xdotool, скорее, будет процессор нагружать, но это тоже нежелательно. Первому варианту по этим же причинам стоит не доверять еще больше, т.к. мало ли кто там как это писал. Может, там вообще утечка памяти будет. :) Ну а с третьим попросту не понятно, так как его-то я уже пробовал: удалил параметры -2button -mouse из аргументов Xvesa. А он все равно запускается с мышью.


Ответ

справедливо для «полноценного» xserver-а. как будет себя вести xvesa — не знаю. проще всего проверить.
1.
мышь можно «обездвижить» (и отключить кнопки), например, с помощью xinput. показываю на примере.
список устройств-pointer-ов (тут не мышь, а trackpad, что несущественно):
$ xinput --list | grep pointer | Virtual core pointer id=2 [master pointer (3)] | ↳ Virtual core XTEST pointer id=4 [slave pointer (2)] | ↳ Cypress APA Trackpad (cyapa) id=12 [slave pointer (2)]
id у нужного устройства — 12 (но надёжнее обращаться по имени Cypress APA Trackpad (cyapa): id может меняться). отключаем и включаем, по номеру и по имени:
$ xinput --disable 12 $ xinput --enable 'Cypress APA Trackpad (cyapa)'
2.
а курсор мыши можно скрыть, например, с помощью xsetroot

jQuery. Выход из click функции

У меня есть некоторое условие и click функция. И я не понимаю, почему, после того как он зашел в это условие и в функцию, он уже оттуда не выходит. По идее jQuery код выполнятся после каждого действия на странице, а он как будто вообще не выходит из этой функции. Пыталась писать return, break - не помогает.
Вот пример простого кода, где я не понимаю, почему он так работает.
if (parseInt($('#number').text()) > 0) { $('#throw').click(function() { var a = parseInt($('#number').text()); a -= 1; $('#number').text(a); alert(1); if (parseInt($('#number').text()) > 0) { return false; } }); } else { alert('end'); }


Ответ

Мне кажется, что вы хотите условие внутри функции, а не вне. Когда придется выкинуть функцию click, можно использовать $('#throw').off('click');
Вот пример:
$('#throw').click(function() { if (parseInt($('#number').text()) > 0) { var a = parseInt($('#number').text()); a -= 1; $('#number').text(a); alert(1); } else { $('#throw').off('click'); alert('end'); } }); 5

Связь между ViewModel в паттерне MVVM

Здравствуйте. Хотелось бы вашего совета. Только начинаю использовать MVVM. Допустим, есть окно MainWindow, в котором находится статус-бар и некоторая индикацию. В это окно помещается, к примеру, UserControl, где находится некоторое меню. По логике вещей, у окна и usercontrol'a свои ViewModel. Вопрос: как тогда обратиться из одной viewmodel в другую? Например, после выполнения некоторого действия из меню, мне нужно изменить текст в статус-баре. Конечно передавать объект одной viewmodel'и в другой нельзя. Нарушение инкапсуляции.


Ответ

В принципе, ничего страшного нету в том, чтобы одна VM знала о другой. Например, корневая VM обычно имеет ссылки на вложенные VM, и образует таким образом дерево.
С другой стороны, для сценария, который вы описываете, сообщение проходит из меню к статус-бару, должно работать не так. Для развязки точки, где генерируется событие, и точки где происходит реакция на него, используются команды. Я бы воспользовался такой архитектурой:
Пункт меню привязан к команде (RoutedUICommand). Например, одной из ApplicationCommands, или вы можете определить свою команду тоже¹. Вам нужно будет зарегистрировать обработчики для команд при помощи CommandBinding, глобально через CommandManager.RegisterClassCommandBinding или локально через XAML (). Таким образом, VM, которая зарегистрировала обработчик команды, получит управление при выборе этой команды в меню. Если результат выполнения устанавливает статус, VM, которая выполняет команду, должна знать кому сообщить об изменении статуса. Поскольку статус один на приложение, вы можете сделать его глобально доступным (VM-синглтон или публичное свойство корневой VM), а можете и развязать эту зависимость при помощи ещё одной команды.
Заметьте, что есть более прямой путь работы с командами, когда вы просто определяете класс, имплементирующий интерфейс ICommand (CanExecute + Execute + CanExecuteChanged). Это скорее всего не то, что вам надо, потому что такую команду сложнее «отвязать»: вы должны будете как-то передать экземпляр команды в меню. Для случая RoutedUICommand меню знает только какую команду оно хочет выполнить, а подсоединение исполнителя к команде происходит отдельно и независимо.

¹ Например, так:
static class ApplicationExtendedCommands { public static ApplicationExtendedCommands Kaboom = new RoutedUICommand() { Text = "Destroy the planet" }; public static ApplicationExtendedCommands About = new RoutedUICommand() { Text = "About application" }; }

Анимация в Android Canvas для minSdkVersion=“8”

В моей словесной игре типа "Эрудита" для Android отсутствует анимация -
Например, при выборе в меню "Вернуть буквы" фишки просто удаляются с игрового поля и потом (вдруг!) показываются внизу экрана.
Тоже самое с "Помешать буквы" - фишки просто рисуются на новых позициях внизу экрана:

Конечно, это выглядит не очень наглядно и мне хотелось бы добавить простые анимации для буквенных фишек - но при этом не терять совместимость с Android 2.2 - поэтому нельзя например использовать ValueAnimator
Кроме того, мне кажется, что можно обойтись без Runnable и создания дополнительных thread-ов - потому что я уже успешно анимирую flinging игрового поля (когда пользователь скроллит его энергичным движением пальца) в главном thread при помощи ScrollerCompat
Вот класс буквенных фишек:
public class Tile { public static int sWidth; public static int sHeight;
// этот прямоугольник содержит координаты и размер фишки private Rect mRect = new Rect();
Для анимации я решил добавить в этот класс конечные координаты и флаг, что движение фишки еще не закончилось:
private Point mTarget = new Point(); public boolean moving = false;
И два метода для перемещения фишки - без и с анимацией:
public void move(int x, int y) { mRect.left = x; mRect.top = y; mRect.right = x + sWidth; mRect.bottom = y + sHeight; }
public void moveAnimated(int x, int y) { moving = true; mTarget.x = x; mTarget.y = y; }
Потом, в методе отрисовки моего главного custom View я вызываю:
public class GameView extends View { private static final int DELAY = 30; private ArrayList mBarTiles = new ArrayList();
@Override protected void onDraw(Canvas canvas) { if (mGameBoard.isFlinging()) { postInvalidateDelayed(DELAY); } else { for (SmallTile tile: mBoardTiles) { if (tile.moving) { postInvalidateDelayed(DELAY); break; } } }
// нарисовать (с учетом scroll-а) игровое поле с фишками mGameBoard.draw(canvas, mBoardTiles);
// нарисовать до 7 фишек внизу экрана - с анимацией for (SmallTile tile: mBarTiles) tile.draw(canvas);
// нарисовать 1 фишку которую тащит пользователь mDraggedTile.draw(canvas); }
Как видите наверху, если одна из фишек еще в процессе движения (и ее флаг moving=true), то вызывается onDraw еще раз через 30 миллисекунд.
То же самое для анимации игрового поля - если оно еще движется (isFlinging() возвращает true) - но это уже работает без проблем.
Теперь собственно мой вопрос
В процедуре отрисовке фишки нужно учесть ее движение и выставить ее актуальные координаты:
public void draw(Canvas canvas) { if (moving) { int dx = mTarget.x - mRect.left; int dy = mTarget.y - mRect.top;
// ВОТ ЗДЕСЬ Я ЗАСТРЯЛ - КАКИЕ КООРДИНАТЫ ВЫСТАВИТЬ? move(XXX, YYY);
// ЕСЛИ ФИШКА ДОЛЕТЕЛА - НУЖНО ВЫСТАВИТЬ moving=false }
// нарисовать background фишки - желтый прямоугольник canvas.drawRect(mRect, mPaint);
// нарисовать Bitmap с буквой и ее числовым значением canvas.save(); canvas.translate(mRect.left, mRect.top); Drawable d = sLetters.get(mLetter); d.draw(canvas); canvas.restore(); }
К сожалению, я не знаю как правильно подсчитать координаты!
У меня есть актуальные координаты фишки: mRect.left и mRect.top
У меня есть координаты куда должна прилететь фишка: mTarget.x и mTarget.y
Пока moving==true, каждые 30 миллисекунд вызывается код отрисовки фишки, которому нужно дать новые координаты - но как их подсчитать?


Ответ

Тогда вам нужно выбрать время анимации, допустим 1 секунда = 1000 миллисек. Тогда поделив 1000 на 30 (fps по сути) получаем 33 - количество раз, которое мы вызовем метод draw для достижения цели. Получается, что наш путь dx и dy тоже нужно поделить на 33, тогда мы получим шаг, на который у нас будет сдвигаться фишка, при каждом вызове draw. Ну а дальше остается прибавлять этот шаг к текущим координатам и с ними вызывать метод move
move(mRect.left + (int) (dx / 33), mRect.top + (int) (dy / 33));