Unix and Me

Dmitry's blog

Instalando LaTeX "manualmente"

2014-09-13 21:59:00 -0300

Usei Arch Linux para estes testes, mas acredito que funcione em qualquer outra distribuição.

Na verdade deveria ser: "Instalando o LaTeX sem usar o gerenciador de pacotes da distribuição" :P.

Baixe o arquivo install-tl-unx.tar.gz de http://www.tug.org/texlive/acquire-netinstall.html.

Para iniciar a instalação basta extrair o tar.gz e executar o script install-tl:

% tar xfz install-tl-unx.tar.gz
% cd install-tl-20140911
% ./install-tl

Será extraido um diretório nesse padrão: install-tl-YYYYMMDD, para mim é o diretório acima, para você pode ser que mude.

O script install-tl, vai mostrar um menu com algumas opções, você pode escolher a opção I para iniciar a instalação, mas eu gosto de instalar apenas o pacote básico e no meu espaço de usuário.

Para instalar somente o básico escolha a opção S e depois escolha:

e [X] minimal scheme (plain only)

Tecle R para voltar ao menu anterior.

Agora vou configurar para instalar no meu espaço de usuário, escolha a opção D, depois a opção 1 e por fim digite o caminho de instalação, normalmente eu coloco:

~/local/texlive/2014

R para voltar ao menu anterior. E depois I para iniciar a instalação.

Adicione ao seu $PATH o caminho ~/local/texlive/2014/bin/x86_64-linux.

Pacotes extras

Para completar a instalação do LaTeX eu instalo ainda esses pacotes

% tlmgr install latex latex-bin latexconfig latex-fonts amsmath babel \
carlisle ec geometry graphics hyperref lm marvosym oberdiek parskip \
pdftex-def url babel babel-portuges mathtools tools

Basicamente todo arquivo que crio usam esses pacotes.

Se tiver algum problema em rodar o comando para gerar o PDF tente pesquisar usando o tlmgr:

% tlmgr search --global PKG

Para procurar por um arquivo:

% tlmgr search --global --file ARQUIVO.EXT

Após todos esses passos minha instalação do LaTeX ficou em cerca de 228M.

Fonte

“LaTeX/Installation - Wikibooks, Open Books for an Open World.” Accessed September 12, 2014. https://en.wikibooks.org/wiki/LaTeX/Installation

Aprendendo Python com testes automatizados

2014-07-02 18:19:00 -0300

Estou aprendendo ainda Python, então se o código puder ser melhorado, pode comentar ;)

Então… Eu estava assistindo as aulas do Python for Zumbies e me deparei com alguns códigos para fazer. Porém quando se inicia o aprendizado de alguma linguagem você quer ver seu código funcionando, para mim existem duas forma de ver meu software funcionando:

  • Automatizar os testes com o software;
  • Entregar o projeto para o usuário (que pode até mesmo ser eu).

Eu como usuário gosto de usar software apenas "funcional", i. e., para que que eu vou usar uma Sequência de Fibonacci ou um software que contabiliza médias de notas se eu não estou tendo aulas?

Então a melhor forma que resolvi testar foi criando testes automatizados.

Sequência de Fibonacci

Primeiro vou criar o arquivo de teste:

Após estudar um pouco cheguei no seguinte código:

import unittest
from fib import fib

class FibTestCase(unittest.TestCase):
  def test_fib1(self):
    self.assertEqual(fib(1), 1)

  def test_fib0(self):
    self.assertEqual(fib(0), 0)

  def test_fib6(self):
    self.assertEqual(fib(6), 8)

  def test_fib6_again(self):
    self.assertTrue(fib(6) == 8)

unittest.main()

Se esse código for executado gera o seguinte erro:

% python fib_test.py
Traceback (most recent call last):
  File "fib_test.py", line 2, in <module>
    from fib import fib
ImportError: No module named 'fib'

Até aí tudo bem, eu ainda não criei o código fibonacci, vamos criar então:

# fib.py
def fib(n):
  if n < 2:
    return(n)

  a = fib(n-1)
  b = fib(n-2)

  return(a+b)

E executando, temos:

% python fib_test.py
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

Orientação a objetos

Depois que aprendi a orientação a objetos em python eu fiz alguns exemplos, entre eles:

Primeiro o teste:

import unittest
from televisao import Televisao

class TelevisaoTestCase(unittest.TestCase):
  def setUp(self):
    self.tv_sala = Televisao('Sala')

  def test_uma_nova_televisao_deve_ser_desligada(self):
    self.assertFalse(self.tv_sala.ligada)

  def test_eu_posso_mudar_o_status_para_ligada(self):
    self.tv_sala.ligada = True
    self.assertTrue(self.tv_sala.ligada)

  def test_eu_posso_mudar_o_canal(self):
    self.tv_sala.canal_mais_um
    selft.assertEqual(self.tv_sala.canal, 2)

unittest.main()

Agora a classe:

class Televisao:
  def __init__(self, local):
    self.ligada = False
    self.canal = 1
    self.local = local

Esse exemplo da classe Televisao eu fiz ao estilo TDD, criava o teste e depois o código.

Ficou faltando um método na classe Televisao, se estiver estudando semelhante a mim, adiciona lá ;)

Confira o Python for Zumbies tem várias vídeo aula em português e diversos exercícios bem práticos!

Fontes

“26.3. Unittest — Unit Testing Framework — Python 3.4.1 Documentation.” Accessed September 1, 2014. https://docs.python.org/3/library/unittest.html.

“Python Para Zumbis Com Fernando Masanori.” Accessed September 2, 2014. http://pycursos.com/python-para-zumbis/.

Envio de e-mail com ssmtp

2014-05-20 12:19:00 -0300

Nota: Todos os comandos eu executei como root, caso não seja root use o sudo antes dos comandos.

Enviando e-mail de máquina unix usando o ssmtp.

No ubuntu instale com o apt-get:

# apt-get install ssmtp

Depois basta configurar para usar o Amazon SES no arquivo /etc/ssmtp/ssmtp.conf:

root=username@mydomain.com
mailhub=email-smtp.us-east-1.amazonaws.com:465
hostname=myserver.mydomain.com

FromLineOverride=YES

AuthUser=AAAAABBBBBCCCCCDDDDD
AuthPass=AAAAABBBBBCCCCCDDDDDEEEEEFFFFFGGGGGHHHHHIIII
UseTLS=YES
AuthMethod=LOGIN

Se for usando o Gmail1:

root=username@gmail.com
mailhub=smtp.gmail.com:587
hostname=myserver.mydomain.com

FromLineOverride=YES

UseSTARTTLS=YES
AuthUser=username@gmail.com
AuthPass=MyPassword

Depois de fazer a configuração tem ainda que deixar as permissões corretas:

# chmod 640 /etc/ssmtp/ssmtp.conf
# chown root:mail /etc/ssmtp/ssmtp.conf

Se quiser que algum usuário envie e-mail, basta adicioná-lo ao grupo mail, editando diretamente o /etc/group ou:

# gpasswd -a username mail

Enviando e-mail

Para testar (caso seu usuário não seja do grupo mail use o sudo antes do ssmtp):

# echo "Testing" | /usr/sbin/ssmtp username@gmail.com

Ou se quiser use um arquivo, por exemplo:

From: username@mydomain.com
Subject: This is Sparta!

Hi.

E chamando via linha de comando:

# ssmtp username@mydomain.com < /tmp/mail.txt

Rails

Para configurar no Rails basta usar algum arquivo de configuração no initializers semelhante a:

Rails.application.configure do
  config.action_mailer.delivery_method = :sendmail
  config.action_mailer.sendmail_settings = { :arguments => '-i' }
  config.action_mailer.default_url_options  = { :host => "mydomain.com" }
end

Ou então colocar em config/environments/production.rb.

Exemplo de scripting

O script abaixo eu coloquei num servidor para me enviar um e-mail com as atualizações que são necessárias, no meu caso coloquei uma vez por dia no crontab:

#!/bin/bash

apt-get update >/dev/null 2>/dev/null
count=$(/usr/lib/update-notifier/apt-check --human-readable | grep -v ^0 | wc -l)

if [ $count -ne 0 ]
then
  file=/tmp/updates-notify-$$

  echo -e "To: username@mydomain.com
From: $(hostname)@mydomain.com
Subject: $(hostname -f) has updates

The server $(hostname -f) has updates:

$(/usr/lib/update-notifier/apt-check --human-readable)

$(apt-get -s -o Debug::NoLocking=true upgrade | grep 'Inst' | cut -d' ' -f2)
" >> $file

  ssmtp username@mydomain.com < $file
  rm $file
fi

Fontes

"SSMTP - ArchWiki". ArchWiki. Accessed May 19, 2014. https://wiki.archlinux.org/index.php/SSMTP.

"How to Use GMail as a Free SMTP Server and Overcome Captcha". Accessed May 19, 2014. http://stackoverflow.com/questions/1607828/how-to-use-gmail-as-a-free-smtp-server-and-overcome-captcha.

"Rails & Sendmail Recipients with -T Option Not Supported." Accessed May 31, 2014. http://stackoverflow.com/questions/6456205/rails-sendmail-recipients-with-t-option-not-supported.


1 Cuidado que o gmail tem um problema de autenticação, caso toda sua configuração esteja certa e mesmo assim receba erro de autenticação, visite: http://www.google.com/accounts/DisplayUnlockCaptcha ou https://www.google.com/a/yourdomain.com/UnlockCaptcha para autorizar o envio de e-mail pelo seu servidor.

Recomendação de Leitura: A Dança do Universo

2014-04-02 21:21:00 -0300

Livro de linguagem acessível sobre as teorias da criação do universo. Muito recomendado para quem gosta de ciência e teorias sobre a criação/existência do universo.

Antes de iniciar a leitura recomendo ouvir esses dois episódios do podcast Dragões de Garagem.

O primeiro fala claramente do livro, mas não achei que possar ter expoliers, até por que o livro fala de teorias científicas e querendo ou não você já ouviu falar de algumas delas, o que pode é não lembrar.

Foi até por causa do episódio #23 que iniciei a leitura.

Local para comprar:

Se gosta da série Cosmos recomendo o livro e o podcast.

Ip estático no Ubuntu/Debian

2013-12-30 14:07:00 -0300

O primeiro a fazer é editar o arquivo /etc/network/interfaces, inicialmente ele deve ser assim:

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

Modifique-o para que fique similar a:

# interfaces(5) file used by ifup(8) and ifdown(8)

auto lo eth0
iface lo inet loopback
iface eth0 inet static
    address 192.168.10.100
    netmask 255.255.255.0
    gateway 192.168.10.1

Substitua eth0 conforme sua máquina.

Agora basta reiniciar o serviço de rede:

# restart networking
networking start/running

E para as opções de DNS edite o arquivo /etc/resolvconf/resolv.conf.d/head adicionando o seguinte conteúdo ao final:

nameserver 8.8.8.8
nameserver 8.8.4.4

E reiniciar o serviço relacionado:

# restart resolvconf
resolvconf start/running

Fonte: Linux Basics - Set A Static IP On Ubuntu.

Rotina

2013-09-10 12:50:00 -0300

Eventualmente acordo as 6h para fazer cooper, mas não está na minha rotina ainda.

Costumo a "entrar para trabalhar" as 8h, então reservo de 7h até as 8h para alguma tarefa criativa, por exemplo:

  • Feed 0 (não tenho problema com inbox 0);
  • Aquela funcionalidade de software que não estou conseguindo fazer funcionar;
  • Entre outras…

Nesse ínterim procuro não ler e-mails. E durante o resto do dia configurei o software que me notifica de novos e-mails para verificar a cada 15min.

Inicio o trabalho para a empresa da qual presto serviço as 8h.

Como trabalho em home office eu gosto de me manter focado ao máximo, evito conversas em casa, evito sair para beber água e ficar de "convercê", pois se por um momento mínimo eu fizer isso as pessoas vão imaginar que isso é normal.

Para o almoço reservo apenas 1h, já notei que preciso apenas disso, não sei as outras pessoas, mas meu organismo funciona assim.

"Fico no trabalho" até as 17h.

Depois das 17h não tem rotina, faço as seguintes tarefas (as vezes apenas uma delas):

  • Leio feed;
  • Ouço podcast;
  • Leio livro(s) (descobri que ler dois livros por vez faz melhor para o cérebro);
  • Faço caça-palavras ou palavras cruzadas (do tipo diretas);
  • Assisto a séries;
  • Estudo assuntos diversos;

Rede social

Eu acompanhava 3 redes sociais: Twitter, Facebook e Google Plus, mas percebi no post Somos adultos, certo? A geração social media que eu não gero conteúdo apenas quero chamar atenção.

Assim eu acesso somente o Twitter e apenas duas vezes por dia.

Ao invés de querer chamar tanta atenção estou tentando gerar mais conteúdo (como este post por exemplo ;).

Exercício

Usando o software Workrave eu paro a cada uma hora para fazer alguns exercícios. Meu braço agradece.

Next?

Minhas aulas comecarão em Outubro então provavelmente minha rotiva vai mudar, se mudar muito crio um outro post caso contrário apenas atualizo este.

Dúvidas, sugestões e correções são bem-vindas.

Porque Prefiro Ebooks

2013-09-03 12:54:00 -0300

Motivo troll

O primeiro motivo e mais troll de todos:

Por que eu tenho um tablet.

Gosto de ler HQ no computador, mas só. Ler livros não é tão agradável.

Meu tablet está morrendo aos poucos então minha próxima compra vai ser um kobo. Escolhi o kobo pois ele aceita mais livros em formato aberto do que a Amazon. No kindle eu teria que converter a maioria dos que tenho e isso não me agrada muito.

Segundo motivo

O segundo é um motivo trágico:

As pessoas não cuidam tão bem dos livros quanto eu.

Não estou me gabando nem nada do tipo, apenas é um fato que comprovei: sempre que empresto um livro ele volta "modificado", com riscos, folhas amassadas, e nem preciso falar mais :|.

Terceiro motivo

O terceiro motivo é de logística:

Espaço para quardar.

Com livros em pdf/epub/mobi eu posso quardar num diretório no meu pc, enviar para "as nuvens" (no meu caso eu uso o dropbox) e catalogar (eu uso o calibre).

Ou seja: tenho meus ebooks em qualquer lugar do mundo (com internet) e organizados.

Catalogar meus livros sempre foi algo que eu quis fazer, mas com eles impressos não sei o porquê, mas nunca consegui.

DataMapper - Introdução

2013-07-31 07:15:00 -0300

Ultimamente tenho passado a usar cada vez menos MongoDb e voltado a usar banco de dados SQL.

Para usar SQL gosto do ActiveRecord ou o DataMapper. Já falei de ActiveRecord em posts como ActiveRecord sem Rails e hoje veremos um exemplo similar usando DataMapper.

Como de costume um Gemfile:

source 'http://rubygems.org'

gem 'data_mapper'
gem 'dm-sqlite-adapter'

Vamos criar nosso model de mensagem no arquivo message.rb:

class Message
  include DataMapper::Resource

  property :id, Serial
  property :content, String
  property :created_at, DateTime
end

Para se conectar ao banco de dados é necessário usar o DataMapper#setup:

DataMapper.setup(:default, "sqlite://#{File.expand_path('database.db')}")

Nesse caso vou usar um banco de dados sqlite, mas se for usar um PostgreSQL:

DataMapper.setup(:default, 'postgres://user:password@hostname/database')

Ao contrário do ActiveRecord não precisamos criar um arquivo de migration. Depois de fazer o require do model message.rb temos duas formas de levantar o banco de dados: DataMapper.auto_migrate! e o DataMapper.auto_upgrade!.

O DataMapper.auto_migrate! tem a característica de APAGAR as tabelas antes de tentar criá-las, já o DataMapper.auto_upgrade! apenas vai tentar fazer com que o schema "case" com o(s) model(s).

Vou criar agora um arquivo chamado database.rb que terá a função de "levantar" e migrar o banco de dados:

require 'data_mapper'

DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, "sqlite://#{File.expand_path('database.db')}")

Dir['./models/*.rb'].entries.each do |model|
  require model
end

DataMapper.auto_upgrade!

Usando o irb como "console" podemos testar:

% irb -r ./database.rb
 ~ (0.000308) PRAGMA table_info("messages")
 ~ (0.000026) SELECT sqlite_version(*)
 ~ (0.109057) CREATE TABLE "messages" ("id" INTEGER NOT NULL PRIMARY KEY AU
TOINCREMENT, "content" VARCHAR(50), "created_at" TIMESTAMP)
irb(main):001:0> Message.count
 ~ (0.000055) SELECT COUNT(*) FROM "messages"
=> 0
irb(main):002:0> Message.create(:content => "Hello from DataMapper")
 ~ (0.111596) INSERT INTO "messages" ("content", "created_at") VALUES ('Hel
lo from DataMapper', '2013-07-31T07:39:21-03:00')
=> #<Message @id=1 @content="Hello from DataMapper" @created_at=#<DateTime:
 2013-07-31T07:39:21-03:00 ((2456505j,38361s,436990591n),-10800s,2299161j)>
>
irb(main):003:0> Message.first
 ~ (0.000085) SELECT "id", "content", "created_at" FROM "messages" ORDER BY
 "id" LIMIT 1
=> #<Message @id=1 @content="Hello from DataMapper" @created_at=#<DateTime:
 2013-07-31T07:39:21-03:00 ((2456505j,38361s,0n),-10800s,2299161j)>>

O código está disponível no github em: https://github.com/dmitrynix/data-mapper-intro.

Strong Parameters

2013-07-18 12:46:00 -0300

Como parte da migração do Rails 3 para o Rails 4 pode-se adicionar a gem strong_parameters para mudar a forma como os atributos são protegidos.

O que, ao meu ver, é melhor, pois pode-se controlar quais atributos são permitidos em que situação (controller) ao invés de apenas definir globalmente.

Configurando

É necessário desativar o config.active_record.whitelist_attributes da aplicação, normalmente essa configuração fica no config/application.rb:

config.active_record.whitelist_attributes = false

E fazer o include do ActiveModel::ForbiddenAttributesProtection em cada model. Uma configuração alternativa (e mais prática) é fazer esse include em todos os models, para isso basta criar um arquivo no config/initializers/ com o seguinte conteúdo:

ActiveRecord::Base.send(:include, ActiveModel::ForbiddenAttributesProtection)

Usos

Encontrei os seguintes comportamentos:

  • Não aceita passar o type (pode ser usando para trabalhar com herança no ActiveRecord);
  • Quando passa um relacionamento has and belongs to many tem que colocar um array como possível atributo, algo como: :author_ids => [];
  • Quando passa um nested form tem que colocar o :id e o :_destroy, se não passar o :id, quando for editar, será feito uma tentativa de criar um novo objeto e se não passar o :_destroy nenhum objeto poderá ser apagado;

Algo que precisei foi um formulário iniciar com valores provenientes de um link, por exemplo:

link_to 'Criar subitens', new_item_path(:item => { :parent_id => @item.id })

Para funcionar fiz algo semelhante a isso na action new do controller:

def new
  @item = Item.new(params[:item].present? ? item_params : {})
end

Blocos pending com Rspec

2013-01-05 07:39:00 -0300

O Rspec tem diferentes formas de colocar um bloco de código como pending, minhas formas de uso são:

  • Como TODO;
  • Colocar teste que quebra sem ainda saber o motivo como pendente;
  • Marcar o teste que quebra como certo, porém a interface não "preparada";

Como TODO

Vamos supor que está criando uma lib de criptografia (bem simples), como gosto de fazer é desenvolver pelo teste, normalmente, eu coloco todos os casos de uso que lembro, depois implemento cada teste e por fim o código:

require './lib/crypt'

describe Crypt do
  it 'encrypt'

  it 'decrypt'
end

O seu TODO pode ser visto no próprio rspec:

% rspec spec/crypt_spec.rb
**

Pending:
  Crypt encrypt
    # Not yet implemented
    # ./spec/crypt_spec.rb:4
  Crypt decrypt
    # Not yet implemented
    # ./spec/crypt_spec.rb:6

Finished in 0.0004 seconds
2 examples, 0 failures, 2 pending

Quando o teste está quebrando

Há vários motivos para um teste quebrar: pode ter mudado algo na interface/código, uma gem que você usa está quebrando, …

Mas e se seu teste estiver correto? Uma gem de terceiros pode estar quebrando, mas sua implementação de uso dela pode estar correta.

Basta colocar um pending no começo do teste, opcionalmente com um motivo.

Imagine que temos esse teste:

require './lib/crypt'

describe Crypt do
  it 'encrypt' do
    subject = Crypt.new('abc')

    expect(subject.encrypt).to eq 'bcd'
  end

  it 'decrypt'
end

Rodar ele vai resultar em:

% rspec spec/crypt_spec.rb
F*

Pending:
  Crypt decrypt
    # Not yet implemented
    # ./spec/crypt_spec.rb:10

Failures:

  1) Crypt encrypt
     Failure/Error: expect(subject.encrypt).to eq 'bcd'

       expected: "bcd"
            got: "zzz"

       (compared using ==)
     # ./spec/crypt_spec.rb:7:in `block (2 levels) in <top (required)>'

Finished in 0.00104 seconds
2 examples, 1 failure, 1 pending

Failed examples:

rspec ./spec/crypt_spec.rb:4 # Crypt encrypt

Vai falhar, mas e se colocar o pending com um bloco (o bloco e o motivo são opcionais) ele vai ser marcado como pendente:

require './lib/crypt'

describe Crypt do
  it 'encrypt' do
    pending "waiting to work right" do
      subject = Crypt.new('abc')

      expect(subject.encrypt).to eq 'bcd'
    end
  end

  it 'decrypt'
end

E executando o teste:

% rspec spec/crypt_spec.rb
**

Pending:
  Crypt encrypt
    # waiting to work right
    # ./spec/crypt_spec.rb:4
  Crypt decrypt
    # Not yet implemented
    # ./spec/crypt_spec.rb:12

Finished in 0.00107 seconds
2 examples, 0 failures, 2 pending

Se não mudarmos nada no teste, mas corrigir o código ele vai exibir a seguinte saída:

% rspec spec/crypt_spec.rb
F*

Pending:
  Crypt decrypt
    # Not yet implemented
    # ./spec/crypt_spec.rb:12

Failures:

  1) Crypt encrypt FIXED
     Expected pending 'waiting to work right' to fail. No Error was raised.
     # ./spec/crypt_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.00102 seconds
2 examples, 1 failure, 1 pending

Failed examples:

rspec ./spec/crypt_spec.rb:4 # Crypt encrypt

Note o FIXED.

Basicamente: "Você esperava que esse teste estivesse quebrando, MAS foi corrigido". Agora pode-se remover o pending.

Usando o xit

Outra forma de desativar o teste é usando o xit ao invés de it. Ele tem o mesmo efeito que usar o pending (sem bloco), mas sua saída é um pouco diferente.

No nosso exemplo:

require './lib/crypt'

describe Crypt do
  it 'encrypt' do
    pending
  end

  xit 'decrypt'
end

Executando:

% rspec spec/crypt_spec.rb
**

Pending:
  Crypt encrypt
    # No reason given
    # ./spec/todo_spec.rb:4
  Crypt decrypt
    # Temporarily disabled with xit
    # ./spec/todo_spec.rb:8

Finished in 0.00049 seconds
2 examples, 0 failures, 2 pending

No reason given é para o pending (sem bloco e sem motivo) e o Temporarily disabled with xit é para o uso do xit.

Existem muitas formas de desativar blocos de teste, poderiamos até mesmo comentar! Mas quando você entrega seu código para outro desenvolvedor é bom manter o mais claro possível o motivo de um teste estar pendente.