PageRenderTime 56ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/episodes/267/es.html

https://github.com/mrnbrkt/asciicasts.com-translations
HTML | 234 lines | 177 code | 57 blank | 0 comment | 0 complexity | 82727dd8a7af17128b9fc6021c55fb94 MD5 | raw file
  1. <p>CoffeScript es un lenguaje que genera JavaScript. Viene incluido por defecto con Rails 3.1 por lo que pronto muchos desarrolladores de Rails van a tener que echarle un vistazo por primera vez. Para empezar a aprenderlo en este episodio veremos c&oacute;mo convertir c&oacute;digo JavaScript ya existente a CoffeScript. El c&oacute;digo que vamos a convertir es el que escribimos en el episodio 261 [<a href="http://railscasts.com/episodes/261-testing-javascript-with-jasmine">verlo</a>, <a href="http://es.asciicasts.com/episodes/261-tests-de-javascript-con-jasmine">leerlo</a>] que validaba n&uacute;meros de tarjeta de cr&eacute;dito.</p>
  2. <p>Para aquellos que no hayan usado nunca CoffeeScript la <a href="http://jashkenas.github.com/coffee-script/">web oficial</a> es el mejor sitio por donde empezar. All&iacute; encontraremos varios ejemplos de CoffeeScript as&iacute; como el JavaScript en que se convierten. Tambi&eacute;n hay una p&aacute;gina donde podemos escribir c&oacute;digo CoffeeScript y verlo convertido en JavaScript que luego podremos ejecutar en el navegador y todo mediante c&oacute;digo en el cliente sin realizar llamadas AJAX al servidor.</p>
  3. <p>El c&oacute;digo JavaScript que vamos a convertir es el de la siguiente p&aacute;gina, que se activa cuando un usuario sale del campo de n&uacute;mero de tarjeta de cr&eacute;dito y que emplea la t&eacute;cnica de calcular el resto de dividir por 10 como validaci&oacute;n b&aacute;sica del n&uacute;mero introducido, mostr&aacute;ndose un mensaje de error junto al campo de texto si detecta que el n&uacute;mero no es correcto.</p>
  4. <div class="imageWrapper">
  5. <img src="/system/photos/662/original/E267I01.png" width="808" height="375" alt="Página de validación de tarjeta de crédito."/>
  6. </div>
  7. <p>A continuaci&oacute;n mostramos el c&oacute;digo JavaScript:</p>
  8. <pre class="javascript">var CreditCard = {
  9. cleanNumber: function(number) {
  10. return number.replace(/[- ]/g, &quot;&quot;);
  11. },
  12. validNumber: function(number) {
  13. var total = 0;
  14. number = this.cleanNumber(number);
  15. for (var i=number.length-1; i &gt;= 0; i--) {
  16. var n = +number[i];
  17. if ((i+number.length) % 2 == 0) {
  18. n = n*2 &gt; 9 ? n*2 - 9 : n*2;
  19. }
  20. total += n;
  21. };
  22. return total % 10 == 0;
  23. }
  24. };
  25. $(function() {
  26. $(&quot;#order_credit_card_number&quot;).blur(function() {
  27. if (CreditCard.validNumber(this.value)) {
  28. $(&quot;#credit_card_number_error&quot;).text(&quot;&quot;);
  29. } else {
  30. $(&quot;#credit_card_number_error&quot;).text(&quot;Invalid credit card number.&quot;);
  31. }
  32. });
  33. });</pre>
  34. <p>La versi&oacute;n de Rails de esta aplicaci&oacute;n es la 3.1 Release Candidate 1, que se anunci&oacute; en el momento de escribir este episodio. Podemos actualizarnos a ella con <code>gem install rails --pre</code>.</p>
  35. <h3>Los primeros cambios</h3>
  36. <p>Para cambiar un fichero JavaScript a CoffeeScript tan s&oacute;lo tenemos que ponerle la extensi&oacute;n <code>.coffee</code> al nombre de archivo. Por supuesto podemos seguir usando ficheros JavaScript normales con Rails 3.1 usando la extensi&oacute;n habitual <code>.js</code>, el uso de CoffeeScript es completamente opcional.</p>
  37. <p>Podemos empezar comentando todo el c&oacute;digo JavaScript y cambiarlo paso a paso por su equivalente CoffeeScript. En la primera secci&oacute;n convertiremos la funci&oacute;n <code>cleanNumber</code> que limpiaba el n&uacute;mero de tarjeta de cr&eacute;dito recibido eliminando los espacios y los guiones que vinieran.</p>
  38. <p class="codeFilePath">/app/assets/javascripts/orders.js.coffee</p>
  39. <pre class="javascript">var CreditCard = {
  40. cleanNumber: function(number) {
  41. return number.replace(/[- ]/g, &quot;&quot;);
  42. }
  43. }</pre>
  44. <p>El c&oacute;digo CoffeeScript equivalente es:</p>
  45. <p class="codeFilePath">/app/assets/javascripts/orders.js.coffee</p>
  46. <pre class="javascript">CreditCard =
  47. cleanNumber: (number) -&gt;
  48. number.replace /[- ]/g, &quot;&quot;</pre>
  49. <p>Con CoffeeScript nos ahorramos buena parte de la sintaxis de JavaScript. Al usar la tabulaci&oacute;n para definir los niveles de bloque nos libramos de todas las llaves pero, eso s&iacute;, deberemos ser consistentes con el uso de los espacios en blanco.</p>
  50. <p>Tambi&eacute;n podemos dejar de utilizar la palabra clave <code>var</code> y al final de una funci&oacute;n no tenemos por qu&eacute; usar <code>return</code>: el &uacute;ltimo valor evaluado en la funci&oacute;n se devuelve autom&aacute;ticamente, igual que en Ruby. No hace falta tampoco usar puntos y comas.</p>
  51. <p>No hay tampoco que rodear con par&eacute;ntesis los argumentos en las llamadas a funci&oacute;n. La &uacute;nica excepci&oacute;n a esto es cuando se invoca una funci&oacute;n sin argumentos, en cuyo caso CoffeeScript necesita los par&eacute;ntesis para saber que se est&aacute; invocando una funci&oacute;n.</p>
  52. <p>Por &uacute;ltimo cambia la forma en la que se invocan las funciones; hay que eliminar la palabra clave <code>function</code> y cambiarla por <code>-&gt;</code> tras los argumentos de la funci&oacute;n. Cuesta un poco acostumbrarse a esta forma tan concisa de definir funciones.</p>
  53. <p>Con este fragmento de c&oacute;digo ya convertido a CoffeeScript podemos compilarlo para ver qu&eacute; JavaScript se genera. La salida se parece mucho a nuestro c&oacute;digo original:</p>
  54. <pre class="javascript">var CreditCard;
  55. CreditCard = {
  56. cleanNumber: function(number) {
  57. return number.replace(/[- ]/g, &quot;&quot;);
  58. }
  59. };</pre>
  60. <p>Ech&eacute;mosle un vistazo ahora a la funci&oacute;n <code>validNumber</code> de nuestro c&oacute;digo JavaScript.</p>
  61. <p class="codeFilePath">/app/assets/javascripts/orders.js.coffee</p>
  62. <pre class="javascript">validNumber: function(number) {
  63. var total = 0;
  64. number = this.cleanNumber(number);
  65. for (var i=number.length-1; i &gt;= 0; i--) {
  66. var n = +number[i];
  67. if ((i+number.length) % 2 == 0) {
  68. n = n*2 &gt; 9 ? n*2 - 9 : n*2;
  69. }
  70. total += n;
  71. };
  72. return total % 10 == 0;
  73. }</pre>
  74. <p>Sigamos los mismos pasos para convertir este c&oacute;digo a CoffeeScript.</p>
  75. <p class="codeFilePath">/app/assets/javascripts/orders.js.coffee</p>
  76. <pre class="javascript">validNumber: (number) -&gt;
  77. total = 0
  78. number = @cleanNumber(number)
  79. for i in [(number.length-1)..0]
  80. n = +number[i]
  81. if (i+number.length) % 2 == 0
  82. n = if n*2 &gt; 9 then n*2 - 9 else n*2
  83. total += n
  84. total % 10 == 0</pre>
  85. <p>De nuevo hemos quitado las llaves y los punto y coma as&iacute; como las palabras clave <code>var</code> y <code>return</code>, y por &uacute;ltimo hemos cambiado <code>function</code> por <code>-&gt;</code>. Tambi&eacute;n hemos hecho otros cambios para limpiar un poco el c&oacute;digo.</p>
  86. <p>Donde aparezca <code>this</code> podemos poner el signo <code>@</code>, de forma que <code>this.cleanNumber</code> se convierte en <code>@number</code>. Podemos tambi&eacute;n quitar las llaves de la sentencia <code>if</code> porque tampoco hacen falta. El operador ternario tambi&eacute;n ha cambiado, por lo que podemos cambiar la interrogaci&oacute;n y los dos puntos al estilo de C por una sentencia <code>if then else</code>.</p>
  87. <p>El resto del c&oacute;digo tiene buen aspecto; s&oacute;lo nos queda cambiar el bucle <code>for</code>. En CoffeeScript los iteradores funcionan de forma distinta a JavaScript: podemos iterar sobre un <em>array</em> con c&oacute;digo como este:</p>
  88. <pre class="javascript">for number in [1,2,3]
  89. alert number</pre>
  90. <p>Esto genera el siguiente JavaScript:</p>
  91. <pre class="javascript">var number, _i, _len, _ref;
  92. _ref = [1, 2, 3];
  93. for (_i = 0, _len = _ref.length; _i &lt; _len; _i++) {
  94. number = _ref[_i];
  95. alert(number);
  96. }</pre>
  97. <p>Alternativamente podemos escribir el c&oacute;digo de la siguiente manera y se traducir&aacute; al mismo JavaScript:</p>
  98. <pre class="javascript">alert number for number in [1,2,3]</pre>
  99. <p>Para una secuencia de n&uacute;meros podemos usar un rango en lugar de un <em>array</em>:</p>
  100. <pre class="javascript">for number in [1..3]
  101. alert number</pre>
  102. <p>Con esto el JavaScript generado se simplifica:</p>
  103. <pre class="javascript">var number;
  104. for (number = 1; number &lt;= 3; number++) {
  105. alert(number);
  106. }</pre>
  107. <p>Si queremos que el bucle cuente hacia atr&aacute;s tan s&oacute;lo tenemos que darle la vuelta a los n&uacute;meros del rango.</p>
  108. <pre class="javascript">for number in [3..1]
  109. alert number</pre>
  110. <p>Esto se parece mucho a lo que hace el bucle <code>for</code> de nuestro c&oacute;digo, as&iacute; que lo podemos reemplazar por una cuenta regresiva similar.</p>
  111. <p>Ya s&oacute;lo nos queda el &uacute;ltimo fragmento de c&oacute;digo JavaScript.</p>
  112. <p class="codeFilePath">/app/assets/javascripts/orders.js.coffee</p>
  113. <pre class="javascript">$(function() {
  114. $(&quot;#order_credit_card_number&quot;).blur(function() {
  115. if (CreditCard.validNumber(this.value)) {
  116. $(&quot;#credit_card_number_error&quot;).text(&quot;&quot;);
  117. } else {
  118. $(&quot;#credit_card_number_error&quot;).text(&quot;Invalid credit &crarr;
  119. card number.&quot;);
  120. }
  121. });
  122. });</pre>
  123. <p>Este fragmento de jQuery adjunto el c&oacute;digo de validaci&oacute;n al evento <code>blur</code> del campo correspondiente al n&uacute;mero de tarjeta de cr&eacute;dito. No hay que hacer nada especial para gestionar el c&oacute;digo jQuery en CoffeeScript, el c&oacute;digo equivalente es:</p>
  124. <p class="codeFilePath">/app/assets/javascripts/orders.js.coffee</p>
  125. <pre class="javascript">jQuery -&gt;
  126. $(&quot;#order_credit_card_number&quot;).blur -&gt;
  127. if CreditCard.validNumber(@value)
  128. $(&quot;#credit_card_number_error&quot;).text(&quot;&quot;)
  129. else
  130. $(&quot;#credit_card_number_error&quot;).text(&quot;Invalid credit &crarr;
  131. card number.&quot;)</pre>
  132. <p>Igual que antes hemos cambiado las llaves y punto y coma, cambiado <code>function</code> por <code>-&gt;</code> y las referencias a <code>this</code> las hemos pasado a <code>@</code>. Queda una &uacute;ltima modificaci&oacute;n que es cambiar la primera llamada a <code>$</code> por <code>jQuery</code>, que no surte ning&uacute;n efecto a nivel de funcionalidad pero pone m&aacute;s de manifiesto que estamos usando jQuery.</p>
  133. <p>Con todo el JavaScript cambiado a CoffeeScript recargamos la p&aacute;gina en el navegador para ver si todo funciona igual que antes.</p>
  134. <div class="imageWrapper">
  135. <img src="/system/photos/663/original/E267I02.png" width="808" height="375" alt="El código CoffeeScript se comporta igual que el JavaScript que sustituye."/>
  136. </div>
  137. <p>Y lo hace. Si introducimos un c&oacute;digo incorrecto de tarjeta de cr&eacute;dito veremos el mensaje de error que desaparece tan pronto como introduzcamos un n&uacute;mero v&aacute;lido. Al final del fichero JavaScript de nuestra aplicaci&oacute;n veremos el c&oacute;digo JavaScript que ha sido compilado a partir del fichero CoffeeScript.</p>
  138. <p class="codeFilePath">http://localhost:3000/assets/application.js</p>
  139. <pre class="javascript">(function() {
  140. var CreditCard;
  141. CreditCard = {
  142. cleanNumber: function(number) {
  143. return number.replace(/[- ]/g, &quot;&quot;);
  144. },
  145. validNumber: function(number) {
  146. var i, n, total, _ref;
  147. total = 0;
  148. number = this.cleanNumber(number);
  149. for (i = _ref = number.length - 1; _ref &lt;= 0 ? i &lt;= 0 : &crarr;
  150. i &gt;= 0; _ref &lt;= 0 ? i++ : i--) {
  151. n = +number[i];
  152. if ((i + number.length) % 2 === 0) {
  153. n = n * 2 &gt; 9 ? n * 2 - 9 : n * 2;
  154. }
  155. total += n;
  156. }
  157. return total % 10 === 0;
  158. }
  159. };
  160. jQuery(function() {
  161. return $(&quot;#order_credit_card_number&quot;).blur(function() {
  162. if (CreditCard.validNumber(this.value)) {
  163. return $(&quot;#credit_card_number_error&quot;).text(&quot;&quot;);
  164. } else {
  165. return $(&quot;#credit_card_number_error&quot;).text(&quot;Invalid &crarr;
  166. credit card number.&quot;);
  167. }
  168. });
  169. });
  170. }).call(this);</pre>
  171. <h3>Depuraci&oacute;n</h3>
  172. <p>&iquest;Qu&eacute; ocurre si tenemos un error de sintaxis en nuestro c&oacute;digo CofeeScript? Si cambiamos el fichero CoffeeScript para que tenga un error y recargamos la p&aacute;gina en el naveador no veremos nada, porque la petici&oacute;n de JavaScript va aparte. Sin embargo si vemos en la consola de desarrollo veremos que el error s&iacute; aparece.</p>
  173. <div class="imageWrapper">
  174. <img src="/system/photos/664/original/E267I03.png" width="814" height="594" alt="El error en CoffeeScript aparece en la consola de desarrollo del navegador."/>
  175. </div>
  176. <p>Aparece suficiente informaci&oacute;n en el mensaje de error como para indicar qu&eacute; es lo que ha ido mal y qu&eacute; l&iacute;nea de c&oacute;digo debemos mirar para empezar a depurar el c&oacute;digo.</p>
  177. <p>Con esto cerramos este episodio. Todav&iacute;a nos queda mucho por ver de CofeeScript, se recomienda visitar el sitio oficial de CofeeScript para leer m&aacute;s de este peque&ntilde;o y divertido lenguaje.</p>