El concepto de plug-in es muy familiar para la mayoría de los usuarios de computadoras y dispositivos móviles. Aplicamos esta idea todos los días ¿quién no se ha molestado con su navegador porque quiere actualizar todo el tiempo el plug-in de Flash? Pero ¿realmente te has preguntado qué es un plug-in? Si sigues leyendo, lo sabrás.
En computación, un plug-in es un componente de software construido para conectarse a una aplicación preexistente y proporcionarle un conjunto de funcionalidades extra. Los programas capaces de gestionar y utilizar plug-ins son muy flexibles, porque optan por reducir su tamaño al evitar implementar características no esenciales, tarea que delegan a los plug-ins. Esto le permite al usuario adaptar el software para sus propios fines, escribiendo sus propios componentes o utilizando plug-ins desarrollados por un tercero.
¿Cómo funcionan?
Desde el punto de vista del usuario, es muy sencillo, por lo general lo único que se necesita para conectar un plug-in es instalarlo en el directorio adecuado y echar a andar la aplicación. Pero ¿cómo puede la aplicación saber que tiene disponible el nuevo plug-in y cómo comunicarse con este? Ese trabajo lo hace un subcomponente usualmente llamado "manejador de plug-ins", el cual se encarga de descubrir qué piezas de software nuevas están almacenadas en el directorio de plug-ins. Cuando encuentra al menos un archivo en esa ubicación, verifica que efectivamente se trate de un plug-in, y en ese caso, lo conecta al núcleo de la aplicación. A partir de ese momento, el plug-in está listo para utilizarse.
Un pequeño ejemplo
Para que quede más clara la idea de cómo se ve por dentro un programa cuando puede conectarse con plug-ins te presento el siguiente ejemplo, que consiste en una pequeña aplicación escrita en Python. Si quieres examinar a detalle el código fuente de este ejemplo, puedes descargar el repositorio desde aquí.
El archivo app
es nuestro programa principal, los plug-ins para este programa son módulos normales de Python. Si ejecutas app
desde la línea de comandos:
➜ app
Verás una ventana como esta:
Inútil al principio, pero esto se debe a que los plug-ins no están instalados. Para poder utilizar un plug-in, es necesario copiarlo en la carpeta plugins
(nota que inicialmente están guardados en la carpeta lib
).
➜ tree . ├── app ├── lib │ ├── calcula.py │ └── man.py ├── plugins └── ui.py 2 directorios, 6 archivos
Además de instalarlos, es necesario que tanto los plug-ins como el núcleo del programa compartan una interfaz. En nuestro ejemplo, la interfaz está definida por un conjunto de funciones en el caso de los plug-ins y métodos públicos en el caso del núcleo.
Del lado del núcleo se requieren al menos dos métodos, los cuales le permitirán al plug-in intercambiar información con este:
leer_entrada()
: para entregar los datos presentes en la entrada del programaescribir_salida()
: para que el núcleo reciba la salida producida por el plug-in
A su vez, cada plug-in válido necesita implementar su propia interfaz, que le permitirá registrarse dentro del programa y responder a las solicitudes que reciba desde el núcleo:
activo()
: cuando el núcleo descubra los plug-ins instalados, va a invocar esta función para saber si puede o no utilizar el plug-ininiciar()
: una vez que el núcleo sabe que está frente a un plug-in válido, lo conectará a través de esta función.hacer()
: es la función principal del plug-in, cada vez que el núcleo quiera utilizarlo, va a invocar esta función.
El programa consiste en dos entidades independientes: una es el núcleo, y la otra es una interfaz gráfica. Dentro del núcleo existe otro componente llamado manejador, que es el encargado de administrar los plug-ins. La estructura de nuestro ejemplo se ve más o menos así:
El código
La parte importante del programa está en el manejador de plug-ins, el cual está implementado en la clase app.Manejador
, teniendo como disparador el método app.Nucleo.carga_plugins()
.
El método carga_plugins()
descubre el contenido del directorio plugins
buscando archivos con extensión .py
y construyendo la lista correspondiente. Estos son los nombres de los plug-ins instalados. Si el plug-in se cargó correctamente, entonces lo agrega a la interfaz gráfica para que esta muestre el botón correspondiente.
class Nucleo: """ app.Nucleo Este componente se encarga de conectar la interfaz de usuario con cada uno de los plugins disponibles. """ def __init__(self): self.__ruta = os.path.join(os.path.realpath('.'), 'plugins') self.__interfaz = None self.__manejador = Manejador(self) def carga_plugins(self): """ app.Nucleo.carga_plugins() -------------------------- Lee el directorio donde se espera estén instalados los plugins y los carga en tiempo de ejecución. DEVUELVE * Nada """ # Revisa si el directorio de plugins existe, y lo crea si es necesario if not os.path.exists(self.__ruta): os.makedirs(self.__ruta) sys.path.append(self.__ruta) # Función para quitar la extensión del nombre del plugin # Se espera que cada plugin sea un módulo de python: *.py filtro = lambda plug: ".py" == plug[-3:] nombre = lambda plug: plug[:-3] plugins = map(nombre, filter(filtro, os.listdir(self.__ruta))) for nombre in plugins: plugin = self.__manejador.carga(nombre) if plugin: self.__interfaz.agrega(nombre, plugin.hacer)
El Manejador, importa el módulo. En caso de éxito configura el plug-in y lo registra en una tabla para futuras referencias; en caso contrario, avisa al núcleo devolviendo None
class Manejador: """ app.Manejador ------------- Componente encargado de gestionar los plugins instalados. """ def __init__(self, nucleo): self.nucleo = nucleo self.__plugins = dict() def carga(self, nombre): """ app.Manejador.carga() --------------------- Busca el plugin especificado, y carga el módulo correspondiente """ archivo, ruta, info = imp.find_module(nombre) plugin = imp.load_module(nombre, archivo, ruta, info) if plugin.activo(): plugin.iniciar(self.nucleo) self.__plugins[nombre] = plugin else: plugin = None return plugin
Mientras tanto, en un plug-in, además de implementar la interfaz que mencioné al inicio, se requiere mantener una conexión con el núcleo de la aplicación. Como este es un ejemplo sencillo, nuestra conexión simplemente es una variable que hace referencia al núcleo mismo y cuyo ámbito es todo el módulo.
# -*- encoding:utf-8 -*- """ man --- Plugin para consultar el manual en línea. """ import subprocess __nucleo = None __activo = True def hacer(): global __nucleo comando = __nucleo.leer_entrada() comando_man = ["man", "-P", "cat", comando ] manual = subprocess.check_output(comando_man) __nucleo.limpiar() __nucleo.escribir_salida(manual) def iniciar(nucleo): global __nucleo __nucleo = nucleo def activo(): global __activo return __activo == True
Y eso es todo. El resto del código en el repositorio es infraestructura para tener un programa completo para hacer esta demo:
Como te habrás dado cuenta, el concepto de plug-in es muy sencillo pero a la vez poderoso, porque nos permite ver a estas piezas de software como bloques para construir soluciones propias.
Hola
Te respondo en este artículo por que es el último que pusiste, pero me refiero al contenido en general de la web:
Por favor, cambia el tipo de letra, el color de la misma o el color de fondo. ¡¡ es un horror intentar leer algo !! Los artículos parecen interesantes pero son totalmente ilegibles.
Lo he probado desde dos ordenadores diferentes y diferentes navegadores, es totalmente ilegible.
Un saludo
Hola Juan Carlos.
Gracias por tu retroalimentación, de verdad nos ayuda mucho. Haremos pruebas para mejorar la legibilidad del sitio.
¡Muchas gracias por leernos!
Hola
Mucho mejora ahora. Ahora la letra es más oscura y se lee correctamente.
Un saludo
Hola Juan Carlos,
Muchas gracias por tu comentario y por leernos.
¡Saludos!
Buenas tardes. Muchas gracias por el artículo. Por el modo de explicar el tema, parece bien profesional y es lo mejor que he visto.
Debido a la gran confusión que hay sobre Add On, Plug In, complemento, extensión y aplicación Web, les pido, si fuera posible, una verdadera aclaración acerca de sus diferencias. Es increíble lo difícil que es dar con alguien que realmente sepa, y si sabe, en la explicación utiliza los mismos términos que trata de explicar…
Muchas gracias.
Saludos cordiales.
Hola Germán
Por supuesto, tendremos tu comentario en cuenta para próximas publicaciones.
Muchas gracias por tu aporte y por leernos.