2013-07-30

IntelliJ Idea и автоматизация конвертации SCSS в CSS, а CSS в minify-версию

Для того, чтобы автоматизировать работу с определёнными категориями файлов, нужно установить плагин File Watchers. В нём есть несколько предустановленных механизмов, однако они требуют для своей работы сторонние скрипты. Например, чтобы автоматически конвертировать SCSS-файлы в CSS, нужно установить ruby-gem sass, а для сжатия CSS и JS нужен компрессор. В Ubuntu это всё можно сделать одной командой bash:

sudo apt-get install ruby-sass yui-compressor

Настройка File Watcher выглядит тривиально. Вот так:

2013-07-29

Неожиданное применение автоматического тестирования

У всех в работе бывают косяки. Я не исключение, поэтому однажды, при написании довольно сложной формы допустил очень неочевидную ошибку, в результате чего, прежде чем я успел этому помешать, несколько сотен раз пользователи сохранили неверные данные.

Когда форма была исправлена, встал вопрос: что делать? Вопрос "Кто виноват", понятное дело, не стоял. Исправление можно было произвести двумя путями: один - это писать скрипт, учитывающий все условия формы и прогонять сохранённые данные через него. Можно, но времени разбираться на этот момент не было (форма всё-таки и правда не тривиальная была). Второй способ - это заставить пользователей снова открывать форму для редактирования и пересохранить данные, т.е. просто открыть страницу с определённым URL и нажать кнопку "Сохранить". Конечно, они в этом не виноваты, и страдать не должны. Делать это мне? Ещё дольше, чем скрипт писать!

А почему бы не поручить это кому-нибудь, у кого много свободного времени, кто не будет возражать и способен делать рутинную работу без всякого ропота? Среди людей таких нет. Тогда обратимся к роботам.

Ну и тут, как вы догадались, Selenium спешит на помощь. Буквально несколько минут, и готов тестовый скрипт, который займётся всей работой. Запускаем Selenium server ...


java -jar selenium-server-standalone-2.33.0.jar

... и наш скрипт ...


python test.py

... и наблюдаем, как человек-невидимка открывает браузер, переходит по ссылкам и нажимает кнопки. Что нам и нужно было.

А вот, собственно, скрипт.


#!/usr/bin/env python
#coding:utf8

from selenium import webdriver
import unittest
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

class Wd(unittest.TestCase):
 def setUp(self):
  self.driver = webdriver.Remote(
   command_executor='http://0.0.0.0:4444/wd/hub',
   desired_capabilities=DesiredCapabilities.FIREFOX)
  self.driver.implicitly_wait(30)
  self.base_url = "http://my.address.ru"

 def test_saveButtonClick(self):
  driver = self.driver
  for id in [222706,426061,441101]:
   url = "%s/edit_page_%d" % (self.base_url,id)
   driver.get(url)
   driver.find_element_by_id("saveform").click()

 def tearDown(self):
  self.driver.quit()

if __name__ == "__main__":
 unittest.main()

2013-07-22

Использование оператора for в Twig: итератор

Некоторое время пользуюсь шаблонизатором Twig, где циклы в шаблонах задаются практически только с использованием оператора for:

{% for item in some_array %}
 {{ item }}
{% endfor %}

При обходе массива (что и делается в большинстве случаев) вопросов не возникало. Но тут приспичило мне сделать цикл типа while. То есть подразумевалось нечто вроде

{% while item = some_array.next() %}
 {{ item }}
{% endwhile %}
однако, while не реализован в Twig.

Недолгий гуглёж привёл меня (внезапно!) на страницу документации Twig, где черным по английскому написано: "A sequence can be either an array or an object implementing the Traversable interface." Итак, решается задачка таким образом: создаётся объект, имплементирующий методы стандартного PHP-интерфейса Iterator, подаётся в оператор for и всё работает. Как-то так:


class SomeItems implements Iterator{
 private $position = 0;
 private $items = [];

 public function add($item){
  $this->items[] = $item;
 }

 public function current() {
  return $this->items[$this->position];
 }
 public function key() {
  return $this->position;
 }
 public function valid() {
  return isset($this->items[$this->position]);
 }
 public function rewind() {
  $this->position = 0;
 }
 public function next(){
  ++$this->position;
 }
}

$items = new SomeItems();
$items->add('One');
$items->add('Two');
$twig->display('page.twig', ['items'=>$items]);

На странице page.twig используем обычную конструкцию:

{% for item in items %}
 {{ item }}
{% endfor %}
В результате на странице выведены слова "One" и "Two".