Robert dice que usar StringBuffer puede ser un overkill en Java, y que cosas como estas no se deben hacer:
-
buffer.append("SELECT COL_A, COL_B, COL_C, COL_D, COL_E");
-
buffer.append(" FROM TABLA_A");
-
buffer.append(" WHERE COL_A> ?");
Tiendo a estar de acuerdo con el planteamiento de Robert, y al final quedaría algo así como esto:
En Ruby el código más parecido al original (usando en el StringBuffer) Java sería algo así como:
-
buffer = ""
-
buffer.<<("SELECT COL_A, COL_B, COL_C, COL_D, COL_E")
-
buffer.<<(" FROM TABLA_A")
-
buffer.<<(" WHERE COL_A> ?")
-
puts buffer
Que implica múltiples concatenaciones cada vez que se ejecuta. Veamos que podemos para que el código sea óptimo y además legible como SQL, tomando en cuenta que no se dispone de un compilador para Ruby.
Entiendo que para aquellos acostumbrados a Java de repente el uso del método << es un tanto inusual, así que hagamos este código más "verbose" y creémos un método alias llamado append
-
class String
-
alias append <<
-
end
(Todo este código lo pueden lanzar secuencial en un archivo de texto, o ejecutarlo en forma interactiva en irb) Sin ganar nada y sólo para impresionar a los nativos, el código quedaría:
-
buffer = ""
-
buffer.append("SELECT COL_A, COL_B, COL_C, COL_D, COL_E")
-
buffer.append(" FROM TABLA_A")
-
buffer.append(" WHERE COL_A> ?")
-
puts buffer
Pero esto es muy poco Ruby para muchos, y en general tenderían a no utilizar los parentesis dado que no hay ambiguedad en este caso trivial:
-
buffer = ""
-
buffer.append "SELECT COL_A, COL_B, COL_C, COL_D, COL_E"
-
buffer.append " FROM TABLA_A"
-
buffer.append " WHERE COL_A> ?"
-
puts buffer
Pero en Ruby el operador de la suma es en realidad un método, y está sobrecargado para concatenar y devolver un nuevo String, así que podríamos hacer el código un poco más limpio:
-
buffer =
-
"SELECT COL_A, COL_B, COL_C, COL_D, COL_E" +
-
" FROM TABLA_A" +
-
" WHERE COL_A> ?"
-
puts buffer
Sin embargo el intérprete de Ruby concatenará en forma automática Strings consecutivos, cosa que se agradece, y que podemos aprovechas para eliminar operadores innecesarios:
-
buffer =
-
"SELECT COL_A, COL_B, COL_C, COL_D, COL_E"
-
" FROM TABLA_A"
-
" WHERE COL_A> ?"
-
puts buffer
Lo que nos deja un código muuuucho más legible.
Pero si quisiéramos podríamos utilizar una sintaxis alterna que nos ofrece Ruby, y que sencillamente interpreta como String todo lo que encuentre entre delimitadores arbitrarios, que en este caso serán / (siempre es el caracter después de %q):
-
buffer = %q/
-
SELECT COL_A, COL_B, COL_C, COL_D, COL_E
-
FROM TABLA_A
-
WHERE COL_A> ?
-
/
-
puts buffer
Pero realmente me parece medio esotérico, y si bien me genera el String agradablemente formateado con sus saltos de línea e indentación (que antes no teníamos), mete un salto de línea inicial que me ofende el sentido estético. Y no quiero subir el String con el SELECT a la primera línea para no romper la indentación.
Así que usamos un HERE document, que me parece la forma más natural y elegante de escribir este String:
-
buffer = <<END
-
SELECT COL_A, COL_B, COL_C, COL_D, COL_E
-
FROM TABLA_A
-
WHERE COL_A> ?
-
END
-
puts buffer
Esto sencillamente crea un String a partir del texto entre los tokens END en este caso, ustedes pueden especificar el token que más les guste después del <<.
Para hacer la cosa más interesante, supongamos que existe una condición variable que quisieramos agregar en forma opcional al "PreparedStatement":
-
condicion = true
-
buffer = <<END
-
SELECT COL_A, COL_B, COL_C, COL_D, COL_E
-
FROM TABLA_A
-
WHERE COL_A> ?
-
END
-
if condicion
-
buffer <<"AND COL_B<?"
-
end
-
puts buffer
Nada muy interesante realmente, pero podemos hacer un poco más bonito usando la interpolación de Strings que ofrece Ruby para evaluar el condicional "inline". Sencillamente Ruby evaluará la expresión entre #{ y } y la reemplazará en el String por el resultado:
-
condicion = true
-
buffer = <<END
-
SELECT COL_A, COL_B, COL_C, COL_D, COL_E
-
FROM TABLA_A
-
WHERE COL_A> ?
-
#{ if condicion then "AND COL_B<?" end }
-
END
-
puts buffer
En este caso el intérprete de Ruby requiere del uso explícito del then que rara vez verán por ahí, pero aprovechemos uno de los edulcorantes sintácticos que ofrece Ruby para hacer eso definitivamente más legible como SQL:
-
condicion = true
-
buffer = <<END
-
SELECT COL_A, COL_B, COL_C, COL_D, COL_E
-
FROM TABLA_A
-
WHERE COL_A> ?
-
#{ "AND COL_B<?" if condicion }
-
END
-
puts buffer
Con seguridad los benchmarks darán como resultado que la versión Java de este código Ruby será más rápida, así que si les preocupa el rendimiento usen un buen compilador de lenguaje C ;-p
Muy elegante el uso de <<, me recuerda mucho al uso en scripts shell de "<< EOF". Lo que si me da miedo de Ruby es esa capacidad de cambiar una implementación de un método en runtime, me da miedo leer el código de alguien y derepente creer que por ejemplo + haga algo y de repente esta haciendo otra cosa porque se cambio por otro lado y yo confiado :-P
Yo cambiaria esta linea:
SELECT COL_A, COL_B, COL_C, COL_D, COL_E
por:
SELECT #{ ("COL_A".."COL_E").to_a * ", " }
Digo, por lo de DRY (Don't Repeat Yourself)
Mucha de la sintaxis prestada de Perl. Por cierto, Perl 6 (si es que sale algún día) tiene nuevos trucos sintacticos :)
Sencillamente Ruby es un lenguaje muy práctico y con Rails se lleva a mas de uno por los cachos.
Efectivamente en su momento Matz quería un "mejor Perl" y de ahí vienen muchas ideas ¿Buen linaje verdad?
Syntactic sugar ;-)
http://en.wikipedia.org/wiki/Syntactic_sugar