Fernando Guillén

un Desarrollador Web Freelance

cabecera decorativa

nada por aquí y nada por allá ó el desarrollo de software como expresión artística.

Archive for the ‘nota mental’ Category

Thursday, September 4th, 2008

Ruby, sustituyendo matches de una regex en un String con matches de la misma regex

Madre mía que título bueno me ha quedado :)

Esto es una nota mental y puede que si no sabes de que hablo no te interese y si sabes de que hablo ya lo sepas.

Intento sustituir una parte de un String por otra parte que se encuentra en el mismo String.

Es decir, tengo esto “me gusta el heavy y no me gusta el country” y quiero obtener esto otro “me gusta el country y no me gusta el heavy”.

Se puede hacer así:

>> "me gusta el heavy y no me gusta el country".gsub( /me gusta (.*) y no me gusta el (.*)/, 'me gusta \2 y no me gusta el \1' )
=> "me gusta country y no me gusta el el heavy"

Donde \1 y \2 son las ocurrencias de los (.*).

El ejemplo puede parecer un poco tonto, pero esta utilidad me ha venido muy bien para quedarme con el contenido de una etiqueta html:

>> "<body>contenido</body>".gsub( /.*<body[^>]*>(.*)<\/body>.*/mix, '\1' ).strip
=> "contenido"

Que se puede solucionar de muchas otras maneras pero esta me ha parecido la más sencilla.

Escribo esta nota mental por lo poco intuitivo que es el uso de ‘\1′ como cadena sustitutiva pues se supone que las cadenas entre comillas simples no se interpretan…

Otra cosa es que google siempre me llevaba a soluciones como esta:

>> "me gusta el heavy y no me gusta el country".gsub( /me gusta (.*) y no me gusta el (.*)/, "me gusta #{$2} y no me gusta el #{$1}" )
=> "me gusta country y no me gusta el el heavy"

Y aunque parece que funciona no es así porque los contenidos de $1 y $2 los ha cogido del gsub anterior y no de éste:

>> "me gusta el musical y no me gusta el flamenco".gsub( /me gusta (.*) y no me gusta el (.*)/, "me gusta #{$2} y no me gusta el #{$1}" )
=> "me gusta country y no me gusta el el heavy"
>> "me gusta el musical y no me gusta el flamenco".gsub( /me gusta (.*) y no me gusta el (.*)/, "me gusta #{$2} y no me gusta el #{$1}" )
=> "me gusta flamenco y no me gusta el el musical"
Wednesday, August 27th, 2008

Ruby, uso de caracteres no ASCII en la consola IRB del Mac OS X

Mis versiones:

  • Mac OS X 10.5.4
  • Ruby 1.8.6 patchlevel 114
  • Rails 2.1.0

Tengo problemas para introducir caracteres no ASCII ( caracteres especiales, acentos y ñs ) en la consola IRB de Ruby así como también en la consola script/console de Rails.

Gracias a las lista ror-es lo he podido solucionar.

Resumo aquí a mi manera el post con la solución:

Instalamos la versión universal de la librería readline mediante MacPorts:

$ sudo port install readline +universal

Si te dá error de:

-bash: port: command not found

Asegúrate que tienes instalados los MacPorts y que tienes esto en tu .bash_profile:

export PATH=$PATH:/opt/local/bin
export MANPATH=$MANPATH:/opt/local/share/man
export INFOPATH=$INFOPATH:/opt/local/share/info

Instalamos la extesión Ruby para readline. Vigila la versión que te bajas, debe coincidir con tu versión de Ruby exactamente:

$ ruby --version
ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]

v1_8_6_114

$ cd /tmp
$ svn co http://svn.ruby-lang.org/repos/ruby/tags/v1_8_6_114/ext/readline/ readline

Aplicamos un parchecito:

$ curl http://pastie.textmate.org/pastes/168767/download | patch readline/extconf.rb

Y compilamos, necesitarás tener instaladas las OS X developer tools:

$ cd readline
$ ruby extconf.rb
$ make
$ sudo make install

Si el script/console te sigue dando problemas asegúrate de tener bien la $KCODE:

$ script/console
Loading development environment (Rails 2.1.0)
>> puts $KCODE
UTF8
=> nil

Gracias de nuevo a Daniel Rodriguez Troitiño por la solución.

Thursday, July 31st, 2008

Ruby: cliente Pop SSL ó como leer tu cuenta Gmail desde Ruby.

Cómo ya dicen en muchas partes, pero me repito aquí para parecer muy listo y por marcarlo como nota mental, para acceder a tu cuenta Pop en Gmail desde Ruby hay que hacer una ñapa porque la versión actual de Ruby (1.8.6) no admite conexiones Pop bajo SSL.

Si si.. la 1.9 ya tiene el soporte, y dicen por ahí que descargándote el pop.rb de esta versión desde el repositorio y haciéndole un require ya funciona.. pero no, por lo menos a mí no porque me salta alguna dependencia con OpenSSl:

NoMethodError: undefined method `set_params' for #<OpenSSL::SSL::SSLContext:0x210f4d0>;

Y no quería seguir tirando de el hilo.

El workarround que más me ha gustado ha sido el de montar un tunel ssh y hacer la petición desde el Net::POP3 al túnel y que el túnel se la haga llegar al pop de Gmail bajo SSL.

No voy a entrar en detalle porque ya lo hacen en muchos sitios.

Actualizado: acabo de ver un sitio dónde explican como usar la implementación pop.rb de la 1.9 sin el problema que me da a mí.

Wednesday, July 23rd, 2008

Texto vertical con javascript

Ni CSS3 ni SVG ni leches.

<script>document.write( "el texto".replace( /(.)/g, "$1<br />" ) ); </script>

Ya sé que no queda vertical y que es un seudo horizo-vertical.. pero por lo menos funciona. ;)

Saturday, July 19th, 2008

2 horas programando para 4 líneas

Es lo que tiene ruby.

Llevo un par de horas intentando sacar un Float en formato ‘d.ddd.ddd,dd’. Hay muchas cosas en internet para conseguirlo, pero no todas funcionaban bien, y otras funcionaban demasiado bien, con un montón de opciones.

El caso es que hay un helper del ActionView que tiene la función number_to_currency pero es un cabroncete de helper y no podía acceder desde el modelo. También teníamos la gema Currency pero era un pedazo monstruo para la tontada que yo quería.

Al final la gema Scruffy me ha dado la pista y esto es lo que tengo:

class Float
  def en_euros
    parts = sprintf("%01.#{2}f", self).split('.')
    parts[0].to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1.") + "," + parts[1].to_s
  end
end

Es un parchecito del Float para poder hacer esto:

>> 1234.566.en_euros
=> "1.234,57"
Friday, June 27th, 2008

Ruby on Rails, el plugin cache-test y la activación de la caché en los tests

Este es mi primer apunte seudo-técnico sobre RoR. No es muy profundo, en realidad lo dejo caer aquí como nota mental.

Resulta que cuando instalas el interesantísimo plugin para testear cachés y sweepers: cache-test, éste tiene en su configuración la activación de las cachés en modo test:

ActionController::Base.perform_caching = true

Tanto en el fragment_cache_test.rb como en el page_cache_test.rb.

Hasta ahora esto no me había causado ningún conflicto pues sólo hacía una llamada a una página get/post cacheada en cada test y con la misma llamada comprobaba todo.

Pero con Shoulda se hacen varias llamadas a la misma página en cada llamada se comprueba una cosa y si la página está cacheada hay varias cosas que pueden fallar como éstas:

context "on GET to :show" do
  setup do
    get( :show, :id => '1' )
  end
  should_assign_to :variable1
  should_assign_to :variable2
  should_assign_to :variable3
  should_render_template :show
end

Aquí se hace una llamada get para cada should_ , el primero funcionará pero los posteriores al estar activada la caché fallarán porque la variable o la vista buscada tendrá valor ‘nil‘.

Este no es un problema de Shoulda, simplemente no me había aparecido hasta ahora. Con los tests normales surgirá igual si tienes la caché activada y haces 2 llamadas a la misma página cacheada y esperas encontrar una variable asignada, la segunda en ejecutarse fallará.

Workarround

Lo único que he encontrado por ahora es poner esto en el setup de los tests:

ActionController::Base.fragment_cache_store.reset

Para mí me funciona, para mis tests y para la configuración de mis cachés, puede que a ti no te funcione.

Y lo que si puede ser es que tengas una solución mejor, plis coméntala.

Tuesday, April 8th, 2008

Poner una aplicación Rails en producción.

Esto no es un tutorial, es una nota mental.

Entorno
  • Ubuntu 7.10
  • MySql 5.0
Instalar capistrano

Tanto en cliente como en servidor.

$ gem install capistrano
Configurar aplicación rails para Capistrano

En cliente.

$ cd #{RAILS_ROOT}
$ capify .

Editar fichero /config/deploy.rb:

require 'mongrel_cluster/recipes'

set :user, "username"
set :runner, "username"

set :application, "miaplicacion"
set :repository,  "http://www.mirepositorio.com/svn/trunk/"
set :scm_username, "username"
set :scm_password, "userpass"

set :deploy_to, "/var/www/railsapps/#{application}"  # path en el servidor
set :mongrel_conf, "#{current_path}/config/mongrel_cluster.yml"  # no tocar

role :app, "miservidor.com"       # si quieres indicar puerto miservidor.com:puerto
role :web, "miservidor.com"       # si quieres indicar puerto miservidor.com:puerto
role :db,  "miservidor.com", :primary => true # si quieres indicar puerto miservidor.com:puerto

Tuve problemas con el username y el userpass y al final les puse el mismo username y pass al usuario del sistema como al usuario del svn.

Editar /config/mongrel_cluster.yml:

---
cwd: /var/www/railsapps/miaplicacion"  # path en el servidor
log_file: log/mongrel.log
port: "5000"
environment: production
address: 127.0.0.1
pid_file: tmp/pids/mongrel.pid
servers: 2      # puertos 5000 y 5001
Preparar servidor

En servidor.

Preparamos el directorio:

$ sudo mkdir -p /var/www/railsapps
$ sudo chown username /var/www/railsapps

Fichero configuración de VirtualHost /etc/apache/sites-available/miaplicacion.miservidor.com:

#we need this as on Ubuntu by default Proxy is not allowed
<Proxy *>
  Order allow,deny
  Allow from all
</Proxy>

#Proxy balancer section (create one for each ruby app cluster)
<Proxy balancer://miaplicacion.miservidor.com_cluster>
  BalancerMember http://127.0.0.1:5000
  BalancerMember http://127.0.0.1:5001
</Proxy>

#Virtual host section (create one for each ruby app you need to publish)
<VirtualHost *:80>
  ServerName miaplicacion.miservidor.com
  DocumentRoot /var/www/railsapps/miaplicacion/current/public/

  <Directory /var/www/railsapps/miaplicacion/current/public/ >
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    allow from all
  </Directory>

  ErrorLog /var/log/apache2/error_miaplicacion.miservidor.com_log
  CustomLog /var/log/apache2/access_miaplicacion.miservidor.com_log combined

  #Rewrite stuff
  RewriteEngine On

  # Check for maintenance file and redirect all requests
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$ /system/maintenance.html [L]

  # Rewrite index to check for static
  RewriteRule ^/$ /index.html [QSA]

  # Rewrite to check for Rails cached page
  RewriteRule ^([^.]+)$ $1.html [QSA]

  # Redirect all non-static requests to cluster
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
  RewriteRule ^/(.*)$ balancer://miaplicacion.miservidor.com_cluster%{REQUEST_URI} [P,QSA,L]
</VirtualHost>

Activamos el VirtualHost:

$ sudo a2ensite miaplicacion.miservidor.com

Recargamos Apache:

$ sudo /etc/init.d/apache reload
Subir primera versión a servidor

En cliente.

$ cap deploy:setup
Preparar BD en servidor

En servidor.

Esto seguro que se puede hacer desde Capistrano:

$ mysql> create database midatabase;
$ mysql> grant all privileges on midatabase.* to username@localhost identified by 'userpass';
$ rake db:migrate
Próximos despliegues

En cliente.

$ cap deploy

Y si hay migraciones entonces hay que ejecutarlas en el servidor (aunque seguro que se puede hacer con el Capistrano).

Tuesday, April 8th, 2008

Procedimiento almacenado con cursor en MySQL

Aquí dejo el código de un procedimiento almacenado de MySQL que usa un cursor.

Esto no es un tutorial es una nota mental.

DROP procedure IF EXISTS test_cursor
/
 
CREATE procedure test_cursor()
 
begin
 
--
-- variables
--
declare hasMoreRows bool DEFAULT true;
declare _field1 varchar(20);
declare _field2 varchar(20);
 
--
-- the cursor
--
declare cur cursor FOR
 
  SELECT
      cl.LIBRARY_NAME,
      cl.LIBRARY_DESCRIPTION
  FROM
      CAT_LIBRARIES AS cl
  ;
 
declare continue handler FOR SQLSTATE '02000'
    SET hasMoreRows = false;
 
--
-- create table test
--
DROP TABLE IF EXISTS test_cursor;
 
CREATE TABLE `test_cursor` (
  `field1`  varchar(20) NULL,
  `field2`  varchar(20) NULL
);
 
--
-- open the cursor
--
open cur;
 
fetch cur INTO
  _field1,
  _field2;
 
while hasMoreRows do
 
--
-- ####### WALK:INI ########
--
 
  INSERT INTO
      test_cursor
  SET
    field1 = _field1,
    field2 = _field2
  ;
 
--
-- ####### WALK:END ########
--
 
  fetch cur INTO
    _field1,
    _field2;
 
end while;
 
close cur;
 
end;
/

Aquí está el fichero con el código fuente.

Friday, March 14th, 2008

Crear otro repositorio subversion.

Esto no es un How-To, es una nota mental.

Creando el repositorio

$ sudo svnadmin create  /home/svn/mirepositorio
$ sudo chown www-data.svn -R /home/svn/mirepositorio

Configuración del apache para el nuevo repositorio:

$ sudo vim /etc/apache2/mods-available/dav_svn.conf
<Location /svn/mirepositorio>
  DAV svn
  SVNPath /home/svn/mirepositorio
  AuthType Basic
  AuthName "mirepositorio's Subversion Repository"
  AuthUserFile /etc/apache2/htpasswd
  Require valid-user
</Location>

Añadimos un usuario:

$ sudo htpasswd -b /etc/apache2/htpasswd usuario clave

Recargamos apache:

$ sudo /etc/init.d/apache2 reload

Comprobamos:

navegador: http://fernandoguillen.info/svn/mirepositorio/
consola:  $ svn checkout http://fernandoguillen.info/svn/mirepositorio

Crear las carpetas iniciales:

$ svn mkdir http://fernandoguillen.info/svn/mirepositorio/trunk
$ svn mkdir http://fernandoguillen.info/svn/mirepositorio/branches
$ svn mkdir http://fernandoguillen.info/svn/mirepositorio/tags

Primer import:

$ svn import http://fernandoguillen.info/svn/mirepositorio/trunk

Mi sistema:

Ubuntu Gutsy Gibon 7.10
Subversion version 1.4.4
Apache 2

un Desarrollador Web Freelance is proudly powered by WordPress
Entries (RSS) and Comments (RSS).