Follow-up sobre el portapapeles de Vim

Minientrada

Compartí por el Discord de mi comunidad de YouTube mi post del otro día en el que compartía un atajo para copiar y pegar de Vim al portapapeles. Aparentemente no a todo el mundo le funcionó a la primera.

Para poder utilizar compartir el portapapeles, Vim tiene que haber sido compilado con soporte para el mismo. Esto se puede saber ejecutando vim --version y comprobando que en la salida del comando aparece la opción +clipboard (tiene que ser un +, porque un -clipoboard precisamente avisa que no). Las versiones de Vim que trae Homebrew en macOS lo suelen tener. En otros UNIX y en GNU/Linux, es posible que haya que cambiar el paquete vim por vim-x11 o por una versión de Vim más completa.

Probando en mi instalación de FreeBSD con X11, funciona tanto para el portapapeles CLIPBOARD ("+) como para el portapapeles PRIMARY (el del botón central del ratón, "*).

En defensa de SQLite

Minientrada

Recientemente en Ruby on Rails incorporaron un cambio que genera un aviso al arrancar la aplicación en modo producción si el driver de base de datos que está configurado es el de SQLite. El aviso se puede desactivar cambiando un flag de configuración en el production.rb para confirmar que no es un accidente, sino una decisión.

You are running SQLite in production, this is generally not recommended.

Debo romper una lanza a favor de SQLite. Tiene sus issues, claro está, pero muchos de ellos pueden entenderse si se lee la documentación técnica.

Por ejemplo, si nunca te has leído su guía sobre tipos de datos y afinidad de columnas probablemente te sorprenda lo blando que es para validar los tipos de datos durante el INSERT (puedes guardar enteros en columnas creadas como VARCHAR, y viceversa).

No vale para todo, pero lo he visto muchas veces en producción en circunstancias en las que tiene sentido que esté en producción, y si está justificado, seguiré defendiéndolo con fuerza como alternativa ligera.

¿Qué hacemos cuando hay conflicto en el Gemfile.lock?

Minientrada

Pues esta es fácil pero como todo en Git nunca aparente. Va a pasar cuando haga cambios al Gemfile en dos ramas a la vez.

git checkout HEAD -- Gemfile.lock

Esto es para traerme el Gemfile.lock que había antes de obtener mi conflicto. Lo importante es que podemos confirmar con un git status que se preserva el Gemfile, así que los cambios en las versiones o librerías siguen ahí.

Si he metido o quitado una dependencia del Gemfile, ahora ejecuto bundle para que se descargue o se retire del lock por encima de la última versión que había en la rama en la que estoy intentando hacer el merge.

Si he actualizado la versión de una dependencia del Gemfile, ahora ejecuto bundle update para que se vuelva a reflejar ese cambio en el lock por encima de la última versión que había en la rama en la que estoy intentando hacer el merge.

Portapapeles del sistema y VIM

Minientrada

El registro de Vim + (PLUS) interactúa con el portapapeles del sistema operativo (el que te permite luego hacer Ctrl-V en otra aplicación).

Si hago un yank en Vim poniendo "+ primero (por ejemplo, "+yy para copiar una línea o una selección visual), luego puedo pegarlo en otra aplicación gráfica de macOS con Cmd+V. Es bidireccional, así que puedo pegar del portapapeles del sistema si he copiado de otra app con "+p.

Hasta ahora utilizaba el modo selección y luego ejecutaba !pbcopy para enviarle mi buffer a pbcopy (un comando de terminal de macOS que envía su stdin al portapapeles), pero esto es más cómodo y no me borra el buffer.

Case-sensitivity y HFS+ (macOS)

Minientrada

Un archivo TypeScript con el siguiente código fuente compila en mi ordenador:

import Member from "../../Member";

Sin embargo, mi código de CI de GitHub Actions falló con el siguiente mensaje de error:

Error: src/lib/http/middlewares/member.ts(6,20): error TS2307: Cannot find module '../../Member' or its corresponding type declarations.

Después de darle un par de vueltas, el veredicto es que, como por defecto el sistema de archivos de macOS no diferencia entre mayúsculas y minúsculas, en macOS, import Member from "../../member" e import Member from "../../Member" son equivalentes. GitHub Actions por defecto utiliza GNU/Linux, donde sí se diferencia por defecto entre mayúsculas y minúsculas, así que no lo tiene tan claro.

Ugh. Lo peor es que hay software para macOS que espera que el sistema operativo no sea case-sensitive y que puede dar problemas si el disco duro en el que se instala macOS se configura para sí diferenciar mayúsculas de minúsculas.

¿Alguna vez dejamos de estar en guerra con el Excel?

Estado

¿Alguna vez dejamos de estar en guerra con el Excel? Piénsalo. En muchas ocasiones, tu trabajo como desarrollador consiste en crear software que resuelva problemas mejor que lo que puede hacerlo una hoja llena de fórmulas en Microsoft Excel.

(Corolario: un sistema informático nunca está completo hasta que no tiene un botón para descargar una snapshot de los datos cargados en él como CSV.)

Organizar los e-mails de GitHub

Minientrada

Pude poner orden hoy en la carpeta de archivo en la que normalmente vuelco todos los e-mails de notificaciones de GitHub una vez los he procesado, y que estaba empezando a acumular un tamaño no poco considerable. (Sobre por qué archivo todo en vez de eliminar algunos tipos de notificaciones, es otro asunto.)

En las notificaciones que tienen que ver con un repositorio (como un issue, un PR o una release), GitHub rellena la cabecera List-Id con el identificador del repositorio del que procede. List-Id es una cabecera estandar que la mayoría de clientes de correo usa para reconocer listas. En el caso de GitHub, la List-Id de un repositorio es <repo>.<user>.github.com.

De modo que con un poco de análisis, he podido organizar automáticamente por carpetas todas las notificaciones, para que las notificaciones de makigas/clank (cuya List-Id será clank.makigas.github.com) vayan a Archivo/github.com/makigas/clank, o las del repositorio danirod/rectball vayan a Archivo/github.com/danirod/rectball.

Un par de filtros automáticos se van a asegurar de que futuras notificaciones vayan directamente a esas carpetas, ya que normalmente las notificaciones llegan en momentos en los que no les puedo dedicar tiempo y luego es complicado escarbar mi bandeja de correo para localizar todos estos correos cuando sí tengo tiempo de ponerme con ello.

Pequeños detalles sobre los átomos en Erlang

La semana pasada empecé a publicar mi curso de Elixir en YouTube, y la recepción está siendo buena e incluso algo mejor de lo esperado. Intento ir lento para ponerlo fácil a quien nunca haya trabajado con este tipo de lenguajes, pero a la vez intento ir rápido para satisfacer a quien esté intentando seguirlo según lo subo (aunque casi sería mejor esperar un par de meses antes de verlo del tirón…)

Uno de los vídeos que subí ya habla sobre los átomos. Es un tipo de datos interesante para representar valores constantes que equivalen a su propio nombre. Al principio puede sonar raro. Al menos a mí me lo sonaba cuando vi por primera vez el concepto en Racket durante la universidad. En Racket, se les llama quotes, y se utiliza la tilde en vez de los dos puntos. Por ejemplo, 'banana, pero el principio es el mismo.

Una cosa que para no hacer un vídeo de nivel introductorio tan complejo no cuento, es que en la máquina virtual de Erlang, cada vez que se declara un átomo, se registra en una tabla de átomos (o Atom Table), que se comporta como un diccionario de átomos conocidos por la máquina virtual.

Si las operaciones que trabajan comparando átomos son rápidas (por ejemplo, x == :ok), lo es porque una vez que todos los átomos están indizados, a nivel interno la máquina virtual de Erlang no trata a un átomo como su valor, sino como su posición en la tabla, así que al final los átomos se gestionan también como números que representan posiciones, y sólo en el momento de comunicar un átomo al exterior es que vemos su representación alfanumérica.

Hablo siempre de alfanumérico porque un átomo contiene letras y caracteres del alfabeto, pero es importante distinguir que los identificadores en Elixir entienden de Unicode, y que por lo tanto, otros alfabetos diferentes también pueden ser codificados en átomos (:Βόρειος, mismamente).

Otra particularidad interesante es que el recolector de basura de Erlang nunca va a recolectar átomos que hayan caído en desuso. De modo que con el tiempo, la máquina virtual de Erlang va a tender a absorber todos aquellos átomos que hayan sido empleados. Dado que en Erlang ciertas construcciones como los propios nombres de los módulos o las listas de argumentos también se codifican con átomos, estas construcciones también van a tomar espacio.

Además, la tabla no es infinita. Los límites declarados por la máquina de Erlang avisan que, salvo que se modifique como parámetro al iniciar la máquina, como mucho se podrán declarar 1.048.576 átomos en la tabla. ¿Qué pasará cuando se alcance ese límite? Que la máquina fallará, como podemos probar rápidamente con este pequeño script:

for x <- 1..1048577, do: x |> Integer.to_string |> String.to_atom

Es una forma un poco fea y barata de generar 1.048.577 átomos a partir de cadenas de caracteres que generamos a su vez a partir de los números de un rango. Cuando ejecuto esto en mi máquina, la máquina de Erlang falla:

$ elixir foo.exs 
no more index entries in atom_tab (max=1048576)
Crash dump is being written to: erl_crash.dump…done

Homebrew Cask sin avisos de seguridad

Minientrada

Seguramente esto sea contrario a la política de seguridad de macOS, pero hoy no me ha quedado otra que instalar con Homebrew Cask una aplicación GUI que no está firmada y que por lo tanto no pasa la política de seguridad de macOS. Educadamente, macOS me invita a tirar el instalador a la papelera pero hace fallar a Cask, que no se espera esto.

Si hubiese descargado a mano el instalador, podría seguir las instrucciones habituales para abrir aplicaciones no firmadas: click derecho – Abrir, y olvidarme por hoy de este asunto. Pero, ¿click derecho en Homebrew? ¿Eh?

Bueno, mirando la página de ayuda del comando brew cask install, la opción que busco es --no-quarantine. Homebrew respeta las opciones de seguridad del sistema operativo y por defecto pone en cuarentena las descargas, igual que hacen los navegadores web, para que salte el sistema de seguridad de macOS al intentar usar el archivo y rechazarlo si no se puede identificar el origen de la aplicación.

% brew cask install foo --no-quarantine

Recomendaría usar con cautela esta opción, de todos modos, no sea que se instalen sorpresas en el ordenador por accidente.

Paso de parámetros al instalar gemas de Ruby

Minientrada

No se me ocurre otro lugar donde dejarlo, así que como no quiero volver a perder hora y media de mi vida reinstalando cosas la próxima vez que falle, lo voy a dejar aquí.

Cuando una gema de Ruby tenga extensiones nativas por debajo y se quiera parametrizar su compilación (por ejemplo, cambiar el CC o las CFLAGS), la manera correcta de hacer esto sería:

gem install ruby-debug-ide -- —-with-cflags=\”-Wno-implicit-function-declaration\”

Uso este ejemplo porque es este el culpable de haber estado una hora haciendo bundle install como un idiota sin entender por qué falla y falla y falla y falla.