Путь продуктивиста

    Манифест Майка Варди
    в переводе Алекса Семёнова

    Pedro Moura Pinheiro (CC BY-NC-SA 2.0)

    ^. Введение

    Я придумал термин «продуктивист», потому что без него никак. Так много людей называют себя экспертами в продуктивности, но являются ими единицы. Я не эксперт в продуктивности. Зато я продуктивист.

    Да, я говорил об этом раньше, но стоит повторить: продуктивист — не эксперт в продуктивности. Продуктивист — не гуру. Продуктивист — энтузиаст в области продуктивности.

    Он изучает продуктивность с помощью инструментов или привычек. Он копает глубже многих. Продуктивист видит мир иначе, как комик, например. Он похож на энтузиастов в других областях; он расширяет границы своего ремесла. Он любит исследовать новые процессы, идеи, новые способы достижения целей.

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

    Я назвал это Путём Продуктивиста, и будь вы продуктивист или нет, попробуйте найти свой клад на этом пути.

    1. Не боритесь с внутренними часами.

    Совы способны быть продуктивными так же, как жаворонки. Иногда они такие же непродуктивные. Но ваш организм знает лучше внешних сил и обстоятельств, когда вам лечь раньше или встать позже. Он знает, когда вы на пике активности, а когда нет. Слушайте организм и соглашайтесь с ним. Как только вы перестанете сражаться с внутренними часами, вы сможете планировать своё расписание: и рабочее время, и отдых, чтобы выжать максимум из вашей повседневной жизни.

    2. Пробейтесь через срочное, чтобы добраться до важного.

    Мы всегда куда-то спешим. Кто-то всегда ждёт от вас чего-то ещё со вчера. Так займитесь этим. Если вы будете работать над чем-то, зная, что важное дело ждёт своего часа, а неделание срочной задачи только отложит ваши дальнейшие планы, вы выполните эту работу. И если у вас получится достаточно часто работать над важными вещами, вы сможете качественнее работать над всем, в том числе и над срочными задачами.

    3. Не старайтесь работать производительнее. Будьте производительнее.

    Работа, чтобы работать — не цель. Иначе вы никогда не прекратите эту работу. Вы должны прекращать работать время от времени, чтобы просто жить. И если вы производительны — вы будете делать правильные вещи, а не что попало. Независимо от того, какое сейчас время.

    4. Не беритесь за что попало. Беритесь за нужные вещи.

    Это соответствует всей концепции — жить или работать. Осознанно выбирайте то, что поможет вам добиться ваших целей с наименьшим сопротивлением (внутренним или любым другим). Иначе вы обнаружите, что это дела выбирают вас, а не вы их. И это, зачастую, не те дела, что вам нужны.

    5. Установите пределы. 
Они помогут вам не захлебнуться.

    Вы не можете сделать все. Перестаньте даже пытаться. Мы не машины, мы — существа, которым жизненно необходимы не только достижения и отметки успеха. Не бойтесь отказываться от вещей, которые вам сейчас не к месту. Лучше закрыть дверь сейчас, чем оказаться у закрытых дверей позже, когда уже не хватит сил добраться до того, что за ними. (Примечание: Три действительно волшебное число. Не пытайтесь делать больше, чем 3 вещи сразу. Никогда.)

    6. Потратьте время, чтобы обустроить удобное пространство для себя, и оно подарит вам больше времени для вас самих.

    В основном, это сводится к планированию. Настройтесь себя так, чтобы иметь пространство (психическое, эмоциональное, окружающую вас среду и т.д.), нужное чтобы выжать максимум из времени, которое у вас есть. Сделайте это, и вы сможете брать отпуск от дел в любой нужный вам момент и просто наслаждаться жизнью.

    7. Иногда бумага — лучший из инструментов.

    Не стоит недооценивать её силу. Бумага — реальный фактор личной продуктивности. Вам не нужно специальных устройств, чтобы пользоваться ею, не нужно подключение к интернету и она невероятно удобная для использования. Бумага и ручка всегда с собой у продуктивиста, поскольку они могут пригодиться в любой момент. Берите бумагу на свой вкус, будь это блокнот с ручкой из ближайшего киоска, модный Молескин, или навороченный Pilot Hi-Tec C. Только убедитесь, что не забыли их дома.

    8. Со списками «Что сделать?» покончено — выполняя их вы останетесь ни с чем. Список «Сделать, чтобы»? Вот этот список стоит выполнить.

    Ставить галочки — это всего лишь ставить галочки. Вычёркивать — это просто вычёркивать. В конце концов, если вы не проделали всё описанное выше, то выполненные вами задачи такие же пустые, как квадраты, в которые вы ставили галочки. В конце концов, если вы не проделали всё описанное выше, то вы просто вычеркнули своё время так же, как и задачи в списке. Зачем вы делаете всё это? Почему именно вы — тот, кто этим занят? Почему это вообще нужно сделать? Это принципы списка «Сделать, чтобы». Этот список расскажет вам меньше о том, чем заняться сегодня, но будет более полным — поскольку построен на более глубоких целях. Составьте этот список сейчас. Не важно выполнять задачи. Важно выполнять свои задачи.

    9. Чтобы стать более продуктивным в будущем, нужно потратить время на настройку себя в настоящем.

    Продуктивист знает об этом и готов к этому. Он знает, что входящие на почте и входящие в задачнике — разные вещи. Он знает, что настройка фильтров и правил в программах займёт какое-то время сейчас, но освободит гораздо больше времени потом. Потратьте время на создание вашей собственной системы — системы, которая будет работать для вас долгое время. Поскольку в системе с крепким фундаментом любая задача, цель или проект, за которые вы возьмётесь, будут обработаны гораздо эффективнее, чем в системе со слабым фундаментом или вовсе без него.

    10. Будьте жадным к своему времени, это сделает вас более щедрым со временем.

    Вам нужно найти время на себя. Вам нужны перерывы. Вам нужны перемены. Вы не можете постоянно упираться в одно и то же, или вы застряли. Вам нужно двигаться. Вы владеете временем, но оно скоротечно. Каждый момент вы проживёте лишь однажды, так сделайте это с умом. Если вы найдёте язык со своим временем, вы сможете помочь сделать это и другим людям.

    $. Вывод

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

    Спасибо за чтение.

    Оригинал: The Way of The Productivityist: A Manifesto, Mike Vardy

    Я-манифест

    Последние два года я всё чаще слышу, что следует использовать «я-высказывания» для упрощения коммуникации и снижения конфликтности ситуации. На мой субъективный взгляд, это — довольно успешный приём, применение которого действительно позволяет некоторым людям воспринимать информацию проще и приемлемее. Однако, с моей точки зрения, этот приём так же сильно усложняет жизнь и коммуникацию той стороны, которая хочет выразить свои чувства и эмоции, а так же вместо конкретной проблемы выделяет некую абстрактную проблему, которую собеседнику проще воспринять и/или проигнорировать.

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

    Я считаю, что «я-высказывания» не только усложняют коммуникацию, но и делают её более запутанной, более некомфортной для меня, желающего выразить собственное мнение, более сложной для восприятия моим собеседником (потому что вместо конкретной эмоции мне приходится превращать её в нечто абстрактное, удобное и комфортное для восприятия).

    Отныне и до тех пор, пока я прямо не заявлю иное, я заявляю, что:

    • всё, произносимое мною, является выражением моего личного субъективного мнения, основанного на моём личном опыте и моих личных эмоциях;

    • всё, что я произношу вслух, пишу в личной переписке или доношу иными способами передачи информации, является исключительно моим личным субъективным мнением;

    • в случае необходимости высказаться от лица некоей группы (будь то группа людей, находящихся рядом и участвующих в беседе, или организации, представителем которой я являюсь, или более общей группы, включающей в себя некоторое неопределённое количество людей), я обязан уточнить отдельно, от лица какой конкретно группы я пытаюсь сейчас говорить (напр. «как сотрудник ООО „Рога и Копыта“», «как мужчина», «как участник движения „за право на молодость“», «как гражданин Российской Федерации»);

    • в случае необходимости апеллировать к какому-то конкретному своду правил и или законов, я также обязан уточнить отдельно, на что я ссылаюсь (напр. «с точки зрения уголовного кодекса Российской Федерации», «исходя из Международной Классификации Болезней 10-го пересмотра»).

    В случае, когда я заявляю что-либо, не указывая свою принадлежность к группе и санкционированное представительство этой группы, либо не ссылаясь на конкретный свод законов или правил, я прошу считать все мои высказывания моим личным субъективным мнением.

    Я приведу конкретные примеры из личной практики:

    Если я говорю:

    • «ты неправ», то любителей «я-высказываний» я прошу воспринимать это выражение как «мне кажется неверным высказанное тобой мнение»;
    • «ты поступил неправильно» — «мне кажется, что поступать подобным образом неправильно»;
    • «ты делаешь мне неприятно» — «мне неприятно, когда люди поступают со мной подобным образом»;
    • «ты постоянно не слушаешь меня» — «я испытываю сильный дискомфорт от того, что ощущаю, что моя речь постоянно не воспринимается собеседником».

    Сравните, пожалуйста фразы слева и справа. Я слышал определение «я-высказываний», как «открытого выражения эмоций», но по факту я вижу, что то, что ощущается — то, что хочется высказать открыто — приходится завуалировать в формулу, которая позволяет моему собеседнику воспринять информацию, которую я хочу открыто донести до него, говоря от первого лица и выражая моё личное мнение, в удобной, комфортной, смягчённой и обобщённой форме. То есть вместо открытого выражения эмоций, я должен использовать специальную формулу, позволяющую моему собеседнику воспринять это сообщение:

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

    Поэтому отныне и впредь, пока не сказано иное, я буду выражать свои эмоции так, как я их чувствую, а не так, как будет проще воспринять моему собеседнику. И это будет открытое выражение моих личных субъективных эмоций, а не завуалированная и усложнённая по определённой формуле попытка показать что-то неконкретное, что, якобы, может быть вызвано кем угодно при общении со мной.

    Всё вышесказанное является моим личным субъективным мнением. Я прошу воспринимать все мои последующие высказывания в соответствии с этим манифестом, который я обозначу как «я-манифест».

    Ставим рубиновый типограф на Рельсы

    В продолжение вчерашней темы, добавил простой способ типографить избранные поля в модели ActiveRecord.

    Достаточно написать в нужной модели примерно следующее:

    class Article < ActiveRecord::Base
      typograf :title, use_p: false, use_br: false
      typograf :content, :teaser
    end
    

    И тогда каждый раз перед сохранением (конкретнее, перед проверкой правильности полей) будет проходить типографирование этих полей, посредством Типографа студии Артемия Лебедева.

    Поддерживается несколько возможных синтаксисов объявления моделей для типографирования:

    • для одного конкретного поля:

      typograf :content
      
    • можно указать параметры для типографирования этого поля:

      typograf :content, entity_type: AlsTypograf::NO_ENTITIES
      
    • для нескольких полей сразу (тоже с возможностью объявить параметры типографирования, общие для всех объявленных полей):

      typograf :skills, :achievements, :additional,
               use_br: false,
               use_p: true
      
    • для нескольких полей сразу (но с объявлением параметров для каждого конкретного поля):

      typograf foo: {entity_type: AlsTypograf::HTML_ENTITIES},
               bar: {use_p: true, use_br: false},
               baz: {max_nobr: 5},
               some_other_field_name: {}
      

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

    Типограф студии Артемия Лебедева с отблеском Рубина

    Понадобилось мне типографировать тексты, добавляемые в админке одного из приложений. Поиск в интернете ни одного годного типографа на Ruby не показал. Зато, я вспомнил, что студия Артемия Лебедева позволяет типографировать тексты с помощью их веб-сервиса. Поэтому, я написал маленькую обёртку к их сервису.

    Пользоваться очень просто.

    • Установите:

      gem install als_typograf
      
    • В коде приложения используйте метод process модуля AlsTypograf следующим образом:

      require 'als_typograf'
      AlsTypograf.process('- Это что, "Типограф"?') # "<p>— Это что, «Типограф»?</p>"
      

    Обёртка поддерживает несколько опций, предоставляемых веб-сервисом Студии, их можно подставлять как к конкретному запросу:

    AlsTypograf.process('- Это что, "Типограф"?', use_p: false, use_br: true)
    

    так и выставлять глобально, для всех запросов на типографирование:

    AlsTypograf.encoding = 'CP1251' # По-умолчанию используется кодировка UTF-8
    AlsTypograf.html_entities! # Заставляет использовать сущности HTML, такие как: &nbsp;, &mdash; &hellip;

    Документация для рубинового типографа хранится (и автоматически обновляется при любых изменениях) на сервисе rubydoc.info, который весьма рекомендую всем разработчикам.

    Метапрограммирование в Ruby

    Что такое метапрограммирование?

    Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime. In many cases, this allows programmers to get more done in the same amount of time as they would take to write all the code manually, or it gives programs greater flexibility to efficiently handle new situations without recompilation. (via Wikipedia)

    Это руководство перечисляет все стандартные методы Ruby, используемые для метапрограммирования, а так же приводит примеры их обычного употребления. В конце мы получим пример использования метапрограммирования для динамического создания классов, соответствующих таблицам в БД, включающих методы, соответствующие полям таблицы, на манер ActiveRecord.

    Инструментарий метапрограммиста

    Ruby содержит множество методов для динамического создания кода. Ознакомимся с ними:

    Получение, установка и удаление переменных

    Получение, установка и удаление констант (и классов)

    Объявление и удаление методов

    Выполнение кода, построенного «на лету»

    Методы интроспекции (рефлексии, отражения)

    Интроспекция — важная часть метапрограммирования, позволяющая изучать объекты, получая их структуру и данные

    Выполнение кода в строках и блоках

    Вы могли слышать о методе eval, позволяющем выполнять строку или блок как код на Ruby. Когда нужно выполнить код внутри контекста какого-то объекта, можно использовать методы instance_eval и module_eval (синоним class_eval).

    Метод instance_eval выполняет код в контексте существующего объекта.

    [1, 2, 3, 4].instance_eval('size') # вернёт 4
    

    В примере мы передали методу instance_eval строку 'size', что интерпретировалось как получение метода :size массивом. Это эквивалентно следующему вызову:

    [1, 2, 3, 4].size
    

    Кроме того, вы можете передавать методу instance_eval блок.

    # Получаем среднее арифметическое чисел в массиве
    [1, 2, 3, 4].instance_eval { inject(:+) / size.to_f } # вернёт 2.5
    

    Методы inject(:+) и size.to_f вроде бы «висят в воздухе» и не относятся ни к какому объекту, однако они выполняются в блоке, в контексте объекта, поэтому они интерпретируются как self.inject(:+) и self.size.to_f где self — наш массив.

    В то время как instance_eval выполняет код в контексте объекта, метод module_eval выполняет код в контексте модуля или класса.

    Fixnum.module_eval do
      def to_word
        if (0..3).include? self
          ['ничего', 'один', 'пара', 'несколько'][self]
        elsif self > 3
          'много'
        elsif self < 0
          'отрицательно'
        end
      end
    end
    1.to_word # вернёт 'один'
    2.to_word # вернёт 'пара'
    

    Мы видим, как module_eval заново открывает существующий класс Fixnum и добавляет в него новый метод. Само по себе это не очень интересно, и мы можем сделать это иначе:

    class Fixnum
      def to_word
        # ...
      end
    end
    

    Лучшее применение этому методу мы найдём при динамическом генерировании кода. Добавим метод create_multiplier, который позволит динамически генерировать методы-умножители с теми именами, которые вы захотите.

    class Fixnum
      def self.create_multiplier(name, num)
        module_eval "def #{name}; self * #{num}; end"
      end
    end
    
    Fixnum.create_multiplier('multiply_by_pi', Math::PI)
    4.multiply_by_pi # вернёт 12.5663706143592
    

    Пример выше создаёт метод класса (или «метод-синглетон») create_multiplier, с помощью которого мы сможем создавать методы, применимые к любому объекту класса Fixnum.

    Использование send

    Метод send работает почти как instance_eval, поскольку вызывает метод объекта, переданный в качестве параметра. Он удобен, когда мы динамически получаем имя необходимого метода в виде строки или символа.

    method_name = 'size'
    [1, 2, 3, 4].send(method_name) # вернёт 4
    

    Мы можем передать имя метода в виде строки 'size' или символа :size

    Полезное свойство метода send — возможность вызывать приватные методы, как например метод Module#define_method.

    Array.define_method(:ducky) { puts 'ducky' }
    # NoMethodError: private method `define_method' called for Array:Class
    

    Используя send получаем:

    Array.send(:define_method, :ducky) { puts 'ducky' }
    

    Создание методов

    Как мы видим в примере выше, мы можем создавать методы классов с помощью define_method.

    class Array
      define_method(:multiply) do |arg|
        collect { |i| i * arg }
      end
    end
    
    [1, 2, 3, 4].multiply(16) # returns [16, 32, 48, 64]
    

    method_missing

    Метод method_missing, объявленный в классе, вызывается в случае получения экземпляром класса несуществующего метода. Это может быть использовано для выполнения этих отсутвующих методов, вместо отправки ошибки NoMethodError.

    class Fixnum
      def method_missing(meth)
        method_name = meth.id2name
        if method_name =~ /^multiply_by_(\d+)$/
          self * $1.to_i
        else
          raise NoMethodError, "undefined method `#{method_name}' for #{self}:#{self.class}"
        end
      end
    end
    
    16.multiply_by_64 # вернёт 1024
    16.multiply_by_x # ошибка NoMethodError
    

    Как работает метод attr_accessor?

    Многие из нас используют attr_accessor в классах, однако не все понимают, какую работу он за нас выполняет. attr_accessor динамически генерирует getter и setter для переменной экземпляра. Давайте посмотрим на примере.

    class Person
      attr_accessor :first_name
    end
    
    john = Person.new
    john.first_name = 'John'
    john.instance_variables # вернёт ["@first_name"]
    john.methods.grep /first_name/ # вернёт ["first_name", "first_name="]
    

    Также мы видим, что attr_accessor создаёт переменную экземпляра @first_name и два метода: getter first_nameи setter first_name=.

    Реализация

    Все классы наследуют методы Module, поэтому мы поместим методы сюда.

    class Module
      # First using define_method
      def attr1(symbol)
        instance_var = ('@' + symbol.to_s)
        define_method(symbol) { instance_variable_get(instance_var) }
        define_method(symbol.to_s + "=") { |val| instance_variable_set(instance_var, val) }
      end
    
      # Second using module_eval
      def attr2(symbol)
        module_eval "def #{symbol}; @#{symbol}; end"
        module_eval "def #{symbol}=(val); @#{symbol} = val; end"
      end
    end
    
    class Person
      attr1 :name
      attr2 :phone
    end
    
    person = Person.new
    person.name = 'John Smith'
    person.phone = '555-2344'
    person # returns
    

    define_method и module_eval оба вернут один и тот же результат.

    Пример использования: Active Record для бедных

    Те, кто знаком с Ruby on Rails, уже догадываются, как можно реализовать класс ActiveRecord, который пройдётся по полям таблицы и добавит классу соответствующие методы getter и setter для полей таблицы.

    Мы можем пойти дальше и динамически создать классы, соответствующие таблицам.

    В этом примере мы создадим ActiveRecord для бедных. Этот класс соединится с базой данных MySQL, создаст динамически классы, соответствующие каждой таблице, а так же наполнит эти классы методами getter и setter, соответсвующими полям таблицы.

    require 'rubygems'
    require 'mysql'
    
    class PoorMan
      # сохраним список сгенерированных классов в переменной класса
      class << self; attr_reader :generated_classes; end
      @generated_classes = []
    
      def initialize(attributes = nil)
        if attributes
          attributes.each_pair do |key, value|
            instance_variable_set('@' + key, value)
          end
        end
      end
    
      def self.connect(host, user, password, database)
        @@db = Mysql.new(host, user, password, database)
    
        # пройдёмся по списку таблиц и создадим классы для них
        @@db.list_tables.each do |table_name|
          class_name = table_name.split('_').collect { |word| word.capitalize }.join
    
          # создаём класс для таблицы, используя Module#const_set
          @generated_classes << klass = Object.const_set(class_name, Class.new(PoorMan))
          klass.module_eval do
            @@fields = []
            @@table_name = table_name
    
            def fields; @@fields; end
          end
    
          # пройдёмся по списку полей таблицы и создадим методы getter и setter для них
          @@db.list_fields(table_name).fetch_fields.each do |field|
            # добавляем getter и setter
            klass.send :attr_accessor, field.name
    
            # добавляем имя поля в список полей
            klass.module_eval { @@fields << field.name }
          end
        end
      end
    
      # получаем строку таблицы по идентификатору
      def self.find(id)
        result = @@db.query("select * from #{@@table_name} where id = #{id} limit 1")
        attributes = result.fetch_hash
        new(attributes) if attributes
      end
    
      # получаем все строки
      def self.all
        result = @@db.query("select * from #{@@table_name}")
        found = []
        while(attributes = result.fetch_hash) do
          found << new(attributes)
        end
        found
      end
    end
    
    # соединяем класс PoorMan с базой данных, всё остальное он сделает самостоятельно
    PoorMan::connect('host', 'user', 'password', 'database')
    
    # печатаем список сгенерированных классов
    p PoorMan::generated_classes
    
    # получаем пользователя с идентификатором 1
    user = Users.find(1)
    
    # получаем всех пользователей
    Users.all
    

    Оригинал статьи: Ruby’s metaprogramming toolbox, автор — Corban Brook

    Некоторые примеры могут не работать на Ruby < 1.8.7

    Интеграция WYSiWYG-редактора TinyMCE в рельсовые приложения

    Вчера закончил работу (ну, её было не очень много) по переделыванию плагина TinyMCE для рельсов в полноценный gemТеперь редактировать текстовые данные в рельсовых приложениях ещё проще.

    Достаточно вставить в environment.rb:

    config.gem 'tiny_mce', source: 'http://gemcutter.org/'
    

    В нужный контроллер:

    uses_tiny_mce only: [:new, :create, :edit, :update]
    

    В обёртку:

    include_tiny_mce_if_needed
    

    А в представлении указать у нужного поля текста класс mceEditor:

     form_for @page do |f|
      f.text_area :content, class: 'mceEditor'
     end
    

    После этого остановите свой проект, наберите в командной строке rake gems:install, запустите проект снова — файлы для TinyMCE автоматически установятся в нужное место. Если вы обновите гем (например, в связи с обновлением кода TinyMCE его авторами) — удалите public/javascript/tiny_mce, перезапустите приложение и новые файлы лягут в нужное место.

    Всё, теперь пользователи вашего сайта смогут вытворять всякие ужасы с текстом, а так же рвать вашу вёрстку и делать прочие непотребности. Наслаждайтесь!

    Ссылки проекта:

    Удаление программ с помощью setup.py

    Некоторые программы написанные на Питоне (например, Lekhonee) поставляются с файликом setup.py, с помощью которого довольно просто устанавливаются

    python setup.py build
    sudo python setup.py install
    А вот удалить такую программу достаточно сложно, ибо команды sudo python setup.py uninstall нету. Ну, не предусмотрели его любители красивого кода на питоне. Красивое, ведь, лучше, чем некрасивое, ага? А код на Питоне, видимо, настолько красивый, что удалять его со своего компьютера — грех смертный.

    Тем не менее, способ удаления таких программ есть, и он довольно прост:

    sudo python setup.py install --record files.txt
    cat files.txt | sudo xargs rm -rf
    
    На самом деле, неприятно удивляет это питоновское стандартное средство установки программ. Но, оказывается, бывает и такое.

    А если подумать перед установкой…

    …то можно использовать уже упоминавшийся в блоге checkinstall:
    sudo checkinstall python setup.py install
    Тогда деинсталлировать это приложение можно будет как обычно, с помощью apt:
    sudo apt-get purge lekhonee

    Сколько стоит Ubuntu?

    Да, я знаю что Ubuntu распространяется бесплатно. Сегодня меня заинтересовало другое.

    Сколько стоила бы аналогичная система, построенная из платных аналогов.

    Посмотрим, что мы получаем в комплекте с Ubuntu:

    • операционную систему на базе ядра GNU/Linux;
    • приятную, расширяемую и настраиваемую графическую оболочку;
    • набор Офисных приложений:
      • редактор текстов (который в платных аналогах любят называть текстовым процессором);
      • приложение электронных таблиц;
      • редактор презентаций;
      • мощное приложение для ведения переписки, календаря и заметок + ещё одно, исключительно для заметок но более удобное;
    • два графических редактора: растровый и векторный;
    • кучу игрушек и прочих приятных мелочей.

    Внушительный список, не правда ли? Сколько вы готовы заплатить за такой набор? А теперь посчитаем, что нам предлагают производители коммерческого ПО:

    Тип ПО Ubuntu Windows OS X
    Ядро системы GNU/Linux $0,00 Windows Vista Home Premium $239,951 OS X 1.5.6 $129,00
    Офисный пакет OpenOffice, Evolution или KOffice, Kontact $0,00 Office Home and Student 2007 $149,952 iWork 09 $79,00
    Растровый графический редактор GIMP или Krita (из KOffice) $0,00 Adobe Photoshop CS4 $699,00 Adobe Photoshop CS4 $699,00
    Векторный графический редактор Draw (из OpenOffice), Inkscape или Karbon (из KOffice) $0,00 Adobe Illustrator CS4 $599,00 Adobe Illustrator CS4 $599,00
    Итого: $0,00 $1687,45 $1506,00

    Берём среднее арифметическое от стоимости комплектов под Windows и OS X и получаем $1596,725.

    Можно сколько угодно говорить о неточном соответствии возможностей тех или иных программ, представленных в сравнении, однако потребности большинства пользователей «ВКонтакте» и «Одноклассников» Ubuntu легко покрывает.

    У меня нету лишних полутора тысяч долларов, которые я отдал бы за ту толику функциональности, которая не предоставлена бесплатными аналогами. А вы?


    1. На русском сайте корпорации Microsoft найти цену на какие-либо продукты нереально

    2. См. 1 

    Совместное использование Cucumber и Factory_Girl или роковая ошибка create_time_zone_conversion_attribute?

    Недавно открыл для себя Cucumber — утилиту для описания поведения вашего приложения. Весьма хорошая штука, доложу вам. Но о ней конкретно я расскажу как-нибудь потом.

    Ещё я использую вместо стендовых данных (известных также как fixtures) замечательный гем от ThoughtBot под названием Factory Girl — он позволяет делать «заготовки» моделей и ваще очень крут (о нём — как вы, может быть, уже догадались — тоже в другой раз).

    Но вот соединить их при тестировании одного проекта оказалось не так-то просто! При тестировании функционала каждый сценарий, начиная со второго использования метода Factory.create вылетал с ошибкой. Как показал бэктрэйс — ошибка случалась в функции ActiveRecord::Base.create_time_zone_conversion_attribute? Гугл рассказал мне, что разработчики рельсов решают эту проблему уже очень долго, и хотя патч, решающий её, давно найден — всё никак не вольют его в основной код. И на то есть веские причины, а именно — утечка мозгов памяти в production-режиме.

    Тем не менее, при тестировании функционала эта утечка памяти не так критична, потому как тестовый сервер Cucumber'а запускается и останавливается регулярно — при каждом прогоне, а сервер приложения висит довольно долго и может отъесть довольно большой кусок памяти и подавиться им. Ну, надоели вступительные слова, вот…

    …решение проблемы:

    Необходимо поместить в директорию lib файл activerecord_reset_sublass_fix.rb, а так же добавить его вызов в файл config/environments/test.rb следующим образом:

Подпишитесь на статьи с помощью РСС или Атом .