mundo-pepino 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,8 +1,19 @@
1
+ == 0.1.6 2009-11-13 ("Iria's half year old!" release)
2
+ * 1 new step definition w/ es_ES matcher:
3
+ * I fill field of a nested attribute
4
+ * 1 convention changed:
5
+ * 'name' is the literal to map for 'the name field' of a model ('nombre' is
6
+ now deprecated)
7
+ * README_es improvements:
8
+ * MundoPepino philosofy added,
9
+ * Sections swapping (to give more relevance to steps definitions than to
10
+ dependendies)
11
+
1
12
  == 0.1.5 2009-11-09
2
13
  * Fixed bug in children search if their name field it's not "name" (by Paco
3
14
  Guzman).
4
15
  * Dynamic load and refactoring of Matchers::Fragments delegation
5
- * X new step definitions in es_ES:
16
+ * 5 new step definitions in es_ES:
6
17
  * I press the following sequence of links and/or buttons + fit table
7
18
  * Given I am on _page_
8
19
  * Then I should be on _page_
data/README_es.markdown CHANGED
@@ -12,6 +12,15 @@ Al mismo tiempo existen expresiones que son de uso frecuente cuando describimos
12
12
 
13
13
  Por otro lado, cuando el idioma utilizado no es inglés es necesario evitar las posibles ambigüedades que genera la traducción de nuestra aplicación. Para posibilitar un lenguaje ubicuo, MundoPepino fuerza la vinculación de las distintas partes de la aplicación (modelos, atributos, acciones y rutas) con los términos con los que nos referimos a las mismas desde nuestras características/features.
14
14
 
15
+ ## Filosofía del MundoPepino
16
+ La aproximación que MundoPepino realiza para resolver su cometido se basa en tres conceptos principalmente:
17
+
18
+ * Definir **convenciones** generales **que reduzcan el número de posibilidades** de expresar un paso.
19
+ * Aprovechar toda la potencia de las **expresiones regulares** para que la definición de un paso capture el **mayor número de posible formas de expresarlo**.
20
+ * Uso indiscriminado de **metaprogramación** de cara a **reducir el código necesario** para implementar sus pasos.
21
+
22
+ El uso de expresiones regulares complejas dificulta notablemente la lectura y comprensión de las definiciones de los pasos. Algo similar ocurre con el uso de metaprogramación en su implementación. MundoPepino vive con ello y cree que merece la pena, pero comprende y respeta que OtrosMundos ataquen el problema con una visión completamente distinta.
23
+
15
24
  ## Recursos
16
25
 
17
26
  * **fuentes**: git://github.com/nando/mundo-pepino.git
@@ -31,206 +40,59 @@ Por otro lado, cuando el idioma utilizado no es inglés es necesario evitar las
31
40
  rake db:migrate
32
41
  rake caracteristicas
33
42
 
34
-
35
43
  En este punto deberíamos obtener dos errores, ambos debidos a que el *scaffold* genera las vistas en inglés y el generador de *caracteristica* los espera en castellano. El primero es el botón "Create" y el segundo el enlace "Destroy":
36
44
 
37
45
  $EDITOR app/views/orchards/index.html.erb # "Borrar" en lugar de "Destroy"
38
46
  $EDITOR app/views/orchards/new.html.erb # "Crear" en lugar de "Create"
39
47
  rake caracteristicas
40
48
 
41
- Ahora sí, los escenarios deberían ser válidos, sin errores ni definiciones pendientes. Para tener precargado el entorno utilizando Spork bastaría con añadir ''--spork'' al ''script/generate cucumber'' y meter la opción ''--drb'' dentro del profile y/o tarea de rake.
49
+ Ahora sí, los escenarios deberían ser válidos, sin errores ni definiciones pendientes. Para tener precargado el entorno utilizando Spork bastaría con añadir ''--spork'' al ''script/generate cucumber'' y meter la opción ''--drb'' dentro del profile y/o de la tarea de rake.
42
50
 
43
51
  El generador mundo_pepino nos prepara el entorno para utilizar las definiciones de MundoPepino sin copiarnos las mismas en ''features/steps_definitions'', cargándolas directemente desde su código. Existe otro generador equivalente llamado **mundo_pepino_steps** que hace lo mismo pero copiando dichas definiciones dentro de ''features/steps_definitions''.
44
52
 
45
- La intención del generador de características es más didáctica que pragmática. Ofrece un ejemplo simple que podemos toquetear para probar el plugin. Por otro lado se limita a hacer exactamente lo mismo que hace `generate feature` exceptuando el hecho de que no genera un fichero de **definiciones específicas** para la nueva *caracteristica* (ya que las utilizadas están comprendidas dentro de las **definiciones genéricas** ya implementadas en MundoPepino).
46
-
47
- Dentro del código de MundoPepino, en `features/support/app` está la aplicación que el MundoPepino utiliza para probarse a si mismo. En particular la característica `features/mundo-pepino.feature` pretente ser un compendio de escenarios que muestren las posibilidades que ofrece.
48
-
49
- ## Instalación
50
-
51
- Como gema:
52
-
53
- gem install mundo-pepino
54
-
55
- Como plugin (ver dependencias más abajo):
56
-
57
- script/plugin install git://github.com/nando/mundo-pepino.git
58
-
59
- ### Dependencias
60
- Si instalamos la gema junto con ella deberían quedar instaladas todas sus dependencias.
61
-
62
- Si instalamos mundo-pepino como plugin debemos tener instaladas las gemas o plugins de **cucumber**, **webrat**, **rspec** y **rspec-rails**. Por ejemplo, para instalar todas ellas como plugins:
63
-
64
- gem install term-ansicolor treetop diff-lcs nokogiri # dependencias de Cucumber
65
- script/plugin install git://github.com/aslakhellesoy/cucumber.git
66
- script/plugin install git://github.com/brynary/webrat.git
67
- script/plugin install git://github.com/dchelimsky/rspec.git
68
- script/plugin install git://github.com/dchelimsky/rspec-rails.git
69
-
70
- Además necesitamos instalar la gema o plugin StringMapper:
71
-
72
- gem install string-mapper
53
+ La intención del generador de características es más didáctica que pragmática. Ofrece un ejemplo simple que podemos toquetear para probar el MundoPepino. Por otro lado se limita a hacer exactamente lo mismo que hace `generate feature` de Cucumber, exceptuando el hecho de que no genera un fichero de **definiciones específicas** para la nueva *caracteristica* (ya que las utilizadas están comprendidas dentro de las **definiciones genéricas** ya implementadas en MundoPepino).
73
54
 
74
- o
55
+ El primer paso del primer escenario generado por ''caracteristica'' en el fichero ''features/gestion_de_huertos.feature'' es la siguiente:
75
56
 
76
- script/plugin install git://github.com/nando/string-mapper.git
57
+ Dado que visito la página de nuevo/a Huerto
77
58
 
78
- Si hacemos uso de alguno de los pasos que hacen referencia a la **selección de un mes** como parte de una fecha en un formulario necesitamos que el método ''strftime'' devuelva en nombre del mes en castellano cuando se utilice ''"%B"''. Para conseguirlo, tenemos entre otras las siguientes opciones (ver más abajo):
59
+ Para que MundoPepino sepa que cuando hablamos de //Huerto// nos estamos refiriendo al modelo //Orchard// es necesario realizar lo que llamamos un "mapeo de modelo". El generador de hecho nos lo ha metido en ''mundo_pepino_es_ES.rb'':
79
60
 
80
- * instalar el módulo ruby-locale,
81
- * o redefinir la función strftime para lograr dicho comportamiento.
82
-
83
- #### [FixtureReplacement](http://replacefixtures.rubyforge.org/)
84
-
85
- De fábrica MundoPepino utiliza ActiveRecord para incorporar a la BBDD los datos que soliciten los escenarios.
86
-
87
- Opcionalmente MundoPepino puede utilizar FixtureReplacement haciendo dicha tarea más simple y permitiéndo que los textos se centren en los objetivos de los escenarios sin preocuparse por el modelo de datos subyacente.
88
-
89
- Para ello por un lado tenemos que instalar el plugin:
90
-
91
- script/plugin install http://thmadb.com/public_svn/plugins/fixture_replacement2/
92
- script/generate fixture_replacement
93
-
94
- ...y por otro, al final de `env.rb` (que el generador de cucumber deja dentro del directorio ''features/support'') tenemos que incluir FixtureReplacement como módulo de nuestro *mundo pepino* (más sobre esto en [A Whole New World](http://wiki.github.com/aslakhellesoy/cucumber/a-whole-new-world)):
95
-
96
- class MiMundo < MundoPepino
97
- include FixtureReplacement
61
+ MundoPepino.configure do |config|
62
+ config.model_mappings = {
63
+ /^huertos?$/i => Orchard
64
+ }
65
+ config.field_mappings = { ... }
66
+ config.url_mappings = { ... }
98
67
  end
99
-
100
- World do
101
- MiMundo.new
102
- end
103
-
104
- #### [FactoryGirl](http://github.com/thoughtbot/factory_girl/)
105
-
106
- Otra opción es utilizar FactoryGirl
107
-
108
- Para ello por un lado tenemos que instalar la gema (para más información sobre FactoryGirl consultar (aquí)[http://github.com/thoughtbot/factory_girl/]):
109
-
110
- gem install thoughtbot-factory_girl --source http://gems.github.com
111
-
112
- ...y por otro, al final de `env.rb` (que el generador de cucumber deja dentro del directorio ''features/support'') tenemos que requerir la librería seguida de la definición de nuestras factorias:
113
-
114
- require 'factory_girl'
115
- require File.expand_path(File.dirname(__FILE__) + '/app/db/factories')
116
-
117
- También se debe incluir un fichero donde se definan las factories a utilizar en nuestro mundo-pepino, como ejemplo consultar el fichero de factories que se encuentra en el directorio ''features/support/app/db/factories''
118
-
119
- #### Selección de un mes en formularios
120
-
121
- Para los pasos que hacen referencia a la selección de un mes en una fecha la implementación actual (de Webrat) busca en nuestro HTML un mes cuyo nombre sea el devuelto por **strftime('%B')** en una instancia de Time creada a partir de la fecha facilitada. En Ruby, si no hacemos nada para remediarlo, esto es sinónimo del nombre del mes de dicha fecha en inglés.
122
-
123
- La opción más simple para resolver este problema es redefinir ''strftime'' para que devuelva el nombre del mes en el locale de la aplicación. Por ejemplo:
124
-
125
- class Time
126
- alias :strftime_nolocale :strftime
127
- def strftime(format)
128
- format = format.dup
129
- format.gsub!(/%B/, I18n.translate('date.month_names')[self.mon])
130
- self.strftime_nolocale(format)
131
- end
132
- end
133
-
134
- Otra opción sería instalar **ruby-locale**. **ruby-locale** es un (viejo) módulo que añade **soporte para locales en Ruby** al que se hace referencia [desde el wiki de Rails](http://wiki.rubyonrails.org/rails/pages/HowToOutputDatesInAnotherLanguage/). Instalándolo en el sistema tendremos la posibilidad de que strftime('%B') devuelva el nombre del mes en castellano.
135
-
136
- Para instalarlo nos bajamos [su código fuente](http://sourceforge.net/project/platformdownload.php?group_id=68254) y lo compilamos e instalamos en el sistema:
137
-
138
- ruby extconf.rb
139
- make
140
- sudo make install
141
- irb
142
- irb> require 'locale'
143
- => true
144
- irb> Time.now.strftime('%B')
145
- => "January"
146
- irb> Locale.setlocale(Locale::LC_TIME, "es_ES.UTF-8")
147
- => "es_ES"
148
- irb> Time.now.strftime('%B')
149
- => "enero"
150
68
 
151
- Por último, para que los helpers de Rails relacionados con la selección de fechas muestren los meses en castellano es necesario hacer uso de la opción **:use\_month\_names**, pasándole en la misma un array con los nombres de los doce meses que deseamos utilizar. Por ejemplo, en algún punto de nuestra aplicación definimos el array con los meses con:
69
+ De forma similar se pueden definir mapeos para los atributos (//field_mappings//, p.e ''/^usado$/i => :used'') y las rutas de la aplicación (//url_mappings//, p.e. ''/^la portada$/ => "/"'').
152
70
 
153
- Meses = %w(enero febrero marzo abril mayo junio julio agosto septiembre octubre noviembre diciembre)
154
-
155
- Y posteriormente en las vistas llamamos al helper con algo parecido a:
156
-
157
- <%= pepino.datetime_select :harvested_at, :use_month_names => Meses %>
158
-
159
- ## Uso
160
- ### generate mundo\_pepino
161
-
162
- rails_root$ script/generate mundo_pepino
163
- exists features/step_definitions
164
- create features/step_definitions/mundo_pepino_es_ES.rb
165
- exists lib/tasks
166
- create lib/tasks/mundo_pepino.rake
71
+ Del mapeo de atributos lo más destacable es la convención de que, si no se le indica lo contrario, el nombre del campo que guarda el //nombre// de cualquier modelo es **name**. Este mapeo nos permite escribir frases como ''Dado que tengo un usuario llamado "Casimiro"'' sin necesidad de hacer referencia al nombre del campo en el que debe guardarse //Casimiro//.
167
72
 
168
- En `mundo_pepino_es_ES.rb` tenemos lo siguiente:
73
+ Es recomendable para evitar problemas que los valores en el mapeo de atributos sean símbolos en lugar de cadenas ya que algunas factorias (p.e. FixtureReplacement) los quieren así.
169
74
 
170
- require 'mundo_pepino/es_ES' # Cargamos las definiciones en castellano
171
- MundoPepino.configure do |c|
172
- c.models_to_clean = [] # Array con los modelos que serán limpiados
173
- # antes de lanzar cada escenario.
174
- c.model_mappings = {} # Hash con el mapeo de los modelos a partir
175
- # de sus equivalencias en castellano.
176
- c.field_mappings = {} # Hash con el mapeo de los campos.
177
- class MiMundo < MundoPepino # Ejemplo de uso del MundoPepio con herencia.
178
- # include FixtureReplacement # FR listo para entrar en acción. Meter aquí
179
- # def mi_funcion; ...; end # las funciones específicas que necesitemos
180
- end # desde nuestras definiciones.
181
- Before do # La limpieza de modelos propiamente dicha...
182
- MundoPepino.clean_models
183
- end # ...se realizará antes de cada escenario.
184
- # Finalmente le pedimos a Cucumber que
185
- World(MiMundo) # utilice una instancia de nuestro mundo como
186
- # ámbito local de nuestros escenarios.
75
+ Del mapeo de rutas cabe destacar que si MundoPepino detecta la presencia del **método ''path_to''** (creado actualmente por Cucumber al preparar el entorno) ignorará dicho mapeo y utilizará ''path_to'' para obtener las rutas a partir de las capturas en los textos.
187
76
 
188
- Por otro lado `mundo_pepino.rake` añade una tarea llamada **caracteristicas** que lanza con la opción `--language es` todos los ficheros con extensión `.feature` que tengamos dentro del directorio `caracteristicas`.
77
+ ### Primera convención y como saltársela: campo **name** para el //nombre// en todos los modelos
189
78
 
190
- ### generate caracteristica
79
+ Como acabamos de comentar:
80
+
81
+ ''Dado que tengo un usuario llamado "Casimiro"''
191
82
 
192
- Se trata del generador equivalente a `script/generate feature` de Cucumber:
83
+ MundoPepino, por convención, intentará guardar "Casimiro" en el campo ''name'' del modelo contra el que esté mapeado "usuario". Vamos a tirar de imaginación y continuemos asumiendo que dicho modelo es ''User''.
193
84
 
194
- $ script/generate caracteristica Orchard Huerto name:string:nombre area:integer:área used:boolean:usado
195
- model_cleaning added Orchard (Orchard.destroy_all call before each scenario)
196
- model_mapping added /huertos?$/i => Orchard
197
- field_mapping added /nombres?$/i => :name
198
- field_mapping added /áreas?$/i => :area
199
- field_mapping added /usados?$/i => :used
200
- create caracteristicas/gestion_de_huertos.feature
85
+ Si queremos saltarnos la convención y que "Casimiro" se guarde en el campo ''login'' tendremos que indicarlo con un mapeo de atributo similar al siguiente:
201
86
 
202
- El fichero `gestion_de_huertos.feature` tendría:
87
+ config.model_mappings = {
88
+ /^User::name$/ => :login
89
+ }
203
90
 
204
- Característica: Gestión de Huertos
205
- Para [beneficio]
206
- Como [sujeto]
207
- Quiero [característica/comportamiento]
208
-
209
- Escenario: Añadir un/a nuevo/a Huerto
210
- Dado que visito la página de nuevo/a Huerto
211
- Cuando relleno nombre con "nombre 0"
212
- Y relleno área con "0"
213
- Y relleno usado con "true"
214
- Y pulso el botón "Crear"
215
- Entonces debería ver el texto "nombre 0"
216
- Y debería ver el texto "0"
217
- Y debería ver el texto "true"
218
-
219
- Escenario: Borrar Huerto
220
- Dado que tenemos los/las siguientes Huertos:
221
- |nombre|área|usado|
222
- |nombre 1|1|false|
223
- |nombre 2|2|true|
224
- |nombre 3|3|false|
225
- |nombre 4|4|true|
226
- Cuando borro el/la Huerto en la tercera posición
227
- Entonces debería ver una tabla con los siguientes contenidos:
228
- |nombre|área|usado|
229
- |nombre 1|1|false|
230
- |nombre 2|2|true|
231
- |nombre 4|4|true|
91
+ Si lo que nos interesa es cambiar la convención globalmente, es decir, que siempre se utilice otro nombre de campo para el nombre, simplemente tendriamos que quitar el modelo y los dos dos puntos del mapeo anterior. Por ejemplo, si queremos que dicho nombre de campo fuese **title** sería algo como:
232
92
 
233
- A diferencia de `generate feature` aquí no se crea un fichero `step_definitions.rb` con definiciones e implementaciones específicas ya que las mismas se encuentran dentro de las tratadas genéricamente dentro del MundoPepino.
93
+ config.model_mappings = {
94
+ /^name$/ => :title
95
+ }
234
96
 
235
97
  ### Relación con modelo utilizando un nombre que no se corresponde con el mismo
236
98
  Con un ejemplo se entiende mejor, creo. Tenemos un modelo User y un modelo Garden y este último "belongs_to :author, class_name => 'User'", de tal forma que //a_garden.author// nos devuelve un User.
@@ -255,6 +117,7 @@ Tengo que meter los siguentes mapeos en nuestro entorno:
255
117
 
256
118
  Con estos mapeos también deberían funcionar el resto de definiciones de MP en las que se haga referencia a una relación.
257
119
 
120
+
258
121
  ## Definiciones implementadas en MundoPepino
259
122
 
260
123
  **Cada definición** existente en MundoPepino tiene **al menos un escenario** que comprueba:
@@ -268,9 +131,9 @@ Para todos los escenarios podríamos tener una narrativa genérica que expresase
268
131
  Como usuario de Cucumber
269
132
  Quiero tener los pasos más habituales definidos, implementados y bien documentados
270
133
 
271
- Cada definición ha sido separada en un fichero `.feature` específico para poder enlazarlas desde este índice.
134
+ Cada definición ha sido separada en un fichero `.feature` específico para poder enlazarlas con //markdown// desde este README. La característica `features/mundo-pepino.feature` pretente ser todo lo contrario, un compendio de escenarios que muestren las posibilidades que ofrece más alla de una definición concreta (la aplicación que MundoPepino utiliza para correr estos tests se encuentra en `features/support/app`).
272
135
 
273
- Como **convención general** los nombres correspondientes a modelos y campos pueden ir sin comillas pero los valores deben ir entre comillas (simples o dobles). Por ejemplo:
136
+ Como **convención general**, aunque MundoPepino pretende ser lo más flexible posible en general, y con las comillas en particular, los nombres correspondientes a modelos y campos pueden ir sin comillas pero los valores deben ir entre comillas (simples o dobles). Por ejemplo:
274
137
 
275
138
  Dado que tenemos un artículo que tiene como título "Título del artículo"
276
139
 
@@ -396,7 +259,10 @@ Convenciones generales:
396
259
  #### Relleno/completo un campo con un texto (*text* o *textarea*) \*
397
260
  Cuando completo 'nombre' con 'Wadus'
398
261
  [más ejemplos](/nando/mundo-pepino/tree/master/features/es_ES/cuando-relleno-el-campo.feature)
399
- #### Relleno/completo varios campos (*text* o *textarea*) desde una step-table \*
262
+ #### Relleno/completo un campo (*text* o *textarea*) de un atributo anidado
263
+ Cuando relleno el email del usuario 'Antonio' con 'wadus@example.com'
264
+ [más ejemplos](/nando/mundo-pepino/tree/master/features/es_ES/cuando-relleno-el-campo-de-atributo-anidado.feature)
265
+ #### Relleno/completo varios campos (*text* o *textarea*) desde una step-table
400
266
  Cuando completo:
401
267
  | Campo | Valor |
402
268
  | Nombre | Lechuga |
@@ -525,6 +391,192 @@ Convenciones generales:
525
391
 
526
392
  (\*) Los **asteriscos** al final de la definición hacen referencia a las **definiciones oficialmente comunes** generadas en inglés por `script/generate cucumber`. Dos asteríscos (\*\*) hacen referencia a una definición presente en la feature autogenerada por `script/generate feature`.
527
393
 
394
+ ## Instalación
395
+
396
+ Como gema:
397
+
398
+ gem install mundo-pepino
399
+
400
+ Como plugin (ver dependencias más abajo):
401
+
402
+ script/plugin install git://github.com/nando/mundo-pepino.git
403
+
404
+ ### Dependencias
405
+ Si instalamos la gema junto con ella deberían quedar instaladas todas sus dependencias.
406
+
407
+ Si instalamos mundo-pepino como plugin debemos tener instaladas las gemas o plugins de **cucumber**, **webrat**, **rspec** y **rspec-rails**. Por ejemplo, para instalar todas ellas como plugins:
408
+
409
+ gem install term-ansicolor treetop diff-lcs nokogiri # dependencias de Cucumber
410
+ script/plugin install git://github.com/aslakhellesoy/cucumber.git
411
+ script/plugin install git://github.com/brynary/webrat.git
412
+ script/plugin install git://github.com/dchelimsky/rspec.git
413
+ script/plugin install git://github.com/dchelimsky/rspec-rails.git
414
+
415
+ Además necesitamos instalar la gema o plugin StringMapper:
416
+
417
+ gem install string-mapper
418
+
419
+ o
420
+
421
+ script/plugin install git://github.com/nando/string-mapper.git
422
+
423
+ Si hacemos uso de alguno de los pasos que hacen referencia a la **selección de un mes** como parte de una fecha en un formulario necesitamos que el método ''strftime'' devuelva en nombre del mes en castellano cuando se utilice ''"%B"''. Para conseguirlo, tenemos entre otras las siguientes opciones (ver más abajo):
424
+
425
+ * instalar el módulo ruby-locale,
426
+ * o redefinir la función strftime para lograr dicho comportamiento.
427
+
428
+ #### [FixtureReplacement](http://replacefixtures.rubyforge.org/)
429
+
430
+ De fábrica MundoPepino utiliza ActiveRecord para incorporar a la BBDD los datos que soliciten los escenarios.
431
+
432
+ Opcionalmente MundoPepino puede utilizar FixtureReplacement haciendo dicha tarea más simple y permitiéndo que los textos se centren en los objetivos de los escenarios sin preocuparse por el modelo de datos subyacente.
433
+
434
+ Para ello por un lado tenemos que instalar el plugin:
435
+
436
+ script/plugin install http://thmadb.com/public_svn/plugins/fixture_replacement2/
437
+ script/generate fixture_replacement
438
+
439
+ ...y por otro, al final de `env.rb` (que el generador de cucumber deja dentro del directorio ''features/support'') tenemos que incluir FixtureReplacement como módulo de nuestro *mundo pepino* (más sobre esto en [A Whole New World](http://wiki.github.com/aslakhellesoy/cucumber/a-whole-new-world)):
440
+
441
+ class MiMundo < MundoPepino
442
+ include FixtureReplacement
443
+ end
444
+
445
+ World do
446
+ MiMundo.new
447
+ end
448
+
449
+ #### [FactoryGirl](http://github.com/thoughtbot/factory_girl/)
450
+
451
+ Otra opción es utilizar FactoryGirl
452
+
453
+ Para ello por un lado tenemos que instalar la gema (para más información sobre FactoryGirl consultar (aquí)[http://github.com/thoughtbot/factory_girl/]):
454
+
455
+ gem install thoughtbot-factory_girl --source http://gems.github.com
456
+
457
+ ...y por otro, al final de `env.rb` (que el generador de cucumber deja dentro del directorio ''features/support'') tenemos que requerir la librería seguida de la definición de nuestras factorias:
458
+
459
+ require 'factory_girl'
460
+ require File.expand_path(File.dirname(__FILE__) + '/app/db/factories')
461
+
462
+ También se debe incluir un fichero donde se definan las factories a utilizar en nuestro mundo-pepino, como ejemplo consultar el fichero de factories que se encuentra en el directorio ''features/support/app/db/factories''
463
+
464
+ #### Selección de un mes en formularios
465
+
466
+ Para los pasos que hacen referencia a la selección de un mes en una fecha la implementación actual (de Webrat) busca en nuestro HTML un mes cuyo nombre sea el devuelto por **strftime('%B')** en una instancia de Time creada a partir de la fecha facilitada. En Ruby, si no hacemos nada para remediarlo, esto es sinónimo del nombre del mes de dicha fecha en inglés.
467
+
468
+ La opción más simple para resolver este problema es redefinir ''strftime'' para que devuelva el nombre del mes en el locale de la aplicación. Por ejemplo:
469
+
470
+ class Time
471
+ alias :strftime_nolocale :strftime
472
+ def strftime(format)
473
+ format = format.dup
474
+ format.gsub!(/%B/, I18n.translate('date.month_names')[self.mon])
475
+ self.strftime_nolocale(format)
476
+ end
477
+ end
478
+
479
+ Otra opción sería instalar **ruby-locale**. **ruby-locale** es un (viejo) módulo que añade **soporte para locales en Ruby** al que se hace referencia [desde el wiki de Rails](http://wiki.rubyonrails.org/rails/pages/HowToOutputDatesInAnotherLanguage/). Instalándolo en el sistema tendremos la posibilidad de que strftime('%B') devuelva el nombre del mes en castellano.
480
+
481
+ Para instalarlo nos bajamos [su código fuente](http://sourceforge.net/project/platformdownload.php?group_id=68254) y lo compilamos e instalamos en el sistema:
482
+
483
+ ruby extconf.rb
484
+ make
485
+ sudo make install
486
+ irb
487
+ irb> require 'locale'
488
+ => true
489
+ irb> Time.now.strftime('%B')
490
+ => "January"
491
+ irb> Locale.setlocale(Locale::LC_TIME, "es_ES.UTF-8")
492
+ => "es_ES"
493
+ irb> Time.now.strftime('%B')
494
+ => "enero"
495
+
496
+ Por último, para que los helpers de Rails relacionados con la selección de fechas muestren los meses en castellano es necesario hacer uso de la opción **:use\_month\_names**, pasándole en la misma un array con los nombres de los doce meses que deseamos utilizar. Por ejemplo, en algún punto de nuestra aplicación definimos el array con los meses con:
497
+
498
+ Meses = %w(enero febrero marzo abril mayo junio julio agosto septiembre octubre noviembre diciembre)
499
+
500
+ Y posteriormente en las vistas llamamos al helper con algo parecido a:
501
+
502
+ <%= pepino.datetime_select :harvested_at, :use_month_names => Meses %>
503
+
504
+ ## Uso
505
+ ### generate mundo\_pepino
506
+
507
+ rails_root$ script/generate mundo_pepino
508
+ exists features/step_definitions
509
+ create features/step_definitions/mundo_pepino_es_ES.rb
510
+ exists lib/tasks
511
+ create lib/tasks/mundo_pepino.rake
512
+
513
+ En `mundo_pepino_es_ES.rb` tenemos lo siguiente:
514
+
515
+ require 'mundo_pepino/es_ES' # Cargamos las definiciones en castellano
516
+ MundoPepino.configure do |c|
517
+ c.models_to_clean = [] # Array con los modelos que serán limpiados
518
+ # antes de lanzar cada escenario.
519
+ c.model_mappings = {} # Hash con el mapeo de los modelos a partir
520
+ # de sus equivalencias en castellano.
521
+ c.field_mappings = {} # Hash con el mapeo de los campos.
522
+ class MiMundo < MundoPepino # Ejemplo de uso del MundoPepio con herencia.
523
+ # include FixtureReplacement # FR listo para entrar en acción. Meter aquí
524
+ # def mi_funcion; ...; end # las funciones específicas que necesitemos
525
+ end # desde nuestras definiciones.
526
+ Before do # La limpieza de modelos propiamente dicha...
527
+ MundoPepino.clean_models
528
+ end # ...se realizará antes de cada escenario.
529
+ # Finalmente le pedimos a Cucumber que
530
+ World(MiMundo) # utilice una instancia de nuestro mundo como
531
+ # ámbito local de nuestros escenarios.
532
+
533
+ Por otro lado `mundo_pepino.rake` añade una tarea llamada **caracteristicas** que lanza con la opción `--language es` todos los ficheros con extensión `.feature` que tengamos dentro del directorio `caracteristicas`.
534
+
535
+ ### generate caracteristica
536
+
537
+ Se trata del generador equivalente a `script/generate feature` de Cucumber:
538
+
539
+ $ script/generate caracteristica Orchard Huerto name:string:nombre area:integer:área used:boolean:usado
540
+ model_cleaning added Orchard (Orchard.destroy_all call before each scenario)
541
+ model_mapping added /huertos?$/i => Orchard
542
+ field_mapping added /nombres?$/i => :name
543
+ field_mapping added /áreas?$/i => :area
544
+ field_mapping added /usados?$/i => :used
545
+ create caracteristicas/gestion_de_huertos.feature
546
+
547
+ El fichero `gestion_de_huertos.feature` tendría:
548
+
549
+ Característica: Gestión de Huertos
550
+ Para [beneficio]
551
+ Como [sujeto]
552
+ Quiero [característica/comportamiento]
553
+
554
+ Escenario: Añadir un/a nuevo/a Huerto
555
+ Dado que visito la página de nuevo/a Huerto
556
+ Cuando relleno nombre con "nombre 0"
557
+ Y relleno área con "0"
558
+ Y relleno usado con "true"
559
+ Y pulso el botón "Crear"
560
+ Entonces debería ver el texto "nombre 0"
561
+ Y debería ver el texto "0"
562
+ Y debería ver el texto "true"
563
+
564
+ Escenario: Borrar Huerto
565
+ Dado que tenemos los/las siguientes Huertos:
566
+ |nombre|área|usado|
567
+ |nombre 1|1|false|
568
+ |nombre 2|2|true|
569
+ |nombre 3|3|false|
570
+ |nombre 4|4|true|
571
+ Cuando borro el/la Huerto en la tercera posición
572
+ Entonces debería ver una tabla con los siguientes contenidos:
573
+ |nombre|área|usado|
574
+ |nombre 1|1|false|
575
+ |nombre 2|2|true|
576
+ |nombre 4|4|true|
577
+
578
+ A diferencia de `generate feature` aquí no se crea un fichero `step_definitions.rb` con definiciones e implementaciones específicas ya que las mismas se encuentran dentro de las tratadas genéricamente dentro del MundoPepino.
579
+
528
580
  ## License
529
581
 
530
582
  Copyright 2008, The Cocktail Experience. Fernando García Samblas <fernando.garcia at the-cocktail.com>
@@ -44,7 +44,7 @@ module MundoPepino
44
44
  attribs = Hash.new
45
45
  attributes.each do |key, value|
46
46
  if child_model = (key.to_s.to_model || key.to_s.to_relation_model)
47
- child = add_resource(child_model, field_for(child_model, 'nombre') => value)
47
+ child = add_resource(child_model, field_for(child_model) => value)
48
48
  field_name = key.to_s.to_relation_model ? key : child_model.name.underscore
49
49
  attribs["#{field_name}_id"] = child.id
50
50
  else
@@ -5,7 +5,7 @@ module MundoPepino
5
5
  /^tru(e|th)$/i => true,
6
6
  /^false$/i => false
7
7
  }) { |value| value } # "true".to_real_value # => true
8
- String.add_mapper(:field, {:nombre => :name})
8
+ String.add_mapper(:field)
9
9
 
10
10
  String.add_mapper(:number, {
11
11
  /^an?$/i => 1,
@@ -149,7 +149,7 @@ Cuando /^(?:que )?#{_pulso_} (?:en )?los (?:siguientes )?(?:enlaces|botones)(?:
149
149
  end
150
150
  end
151
151
 
152
- Cuando /^(?:que )?(?:completo|relleno) (.+) con (?:el valor )?['"](.+)["']$/i do |campo, valor|
152
+ Cuando /^(?:que )?(?:completo|relleno) (?!#{_localizador_de_atributo_anidado_(false)})(.+) con (?:el valor )?['"](.+)["']$/i do |campo, valor|
153
153
  find_field_and_do_with_webrat :fill_in, campo, :with => valor
154
154
  end
155
155
 
@@ -159,6 +159,11 @@ Cuando /^(?:que )?(?:completo|relleno):$/i do |tabla|
159
159
  end
160
160
  end
161
161
 
162
+ Cuando /^(?:que )?(?:completo|relleno) #{_localizador_de_atributo_anidado_} con (?:el valor )?['"](.+)["']$/i do |campo, modelo_anidado, nombre_anidado, valor|
163
+ field_id = nested_field_id(campo, modelo_anidado, nombre_anidado, last_mentioned)
164
+ find_field_and_do_with_webrat :fill_in, field_id, :with => valor
165
+ end
166
+
162
167
  Cuando /^(?:que )?elijo (?:la|el)? ?(.+) ['"](.+)["']$/i do |campo, valor|
163
168
  choose(campo_to_field(campo).to_s + '_' + valor.downcase.to_underscored)
164
169
  end
@@ -34,6 +34,10 @@ module MundoPepino
34
34
  def _debo_estar_en_
35
35
  '(?:debo|deber[ií]a) (?:estar|encontrarme) en'
36
36
  end
37
+ def _localizador_de_atributo_anidado_(capture=true)
38
+ o,c = capture ? ['(', ')'] : ['', '']
39
+ "(?:(?:el|la) )?#{o}.+?#{c} (?:del|de la) #{o}.+?#{c} ['\"]#{o}[^\"']+#{c}[\"']"
40
+ end
37
41
  end
38
42
  end
39
43
  end
@@ -41,7 +41,7 @@ module MundoPepino
41
41
  def then_we_have_a_number_of_instances_in_our_database(raw_number, raw_model, name)
42
42
  model = raw_model.to_unquoted.to_model
43
43
  conditions = if name
44
- {:conditions => [ "#{field_for(model, 'nombre')}=?", name ]}
44
+ {:conditions => [ "#{field_for(model)}=?", name ]}
45
45
  else
46
46
  {}
47
47
  end
@@ -1,3 +1,5 @@
1
+ require 'nokogiri'
2
+
1
3
  module MundoPepino
2
4
  module ImplementationsApi
3
5
  def real_value_for(v)
@@ -7,7 +9,7 @@ module MundoPepino
7
9
  def names_for_simple_creation(model, number, name_or_names, options = {})
8
10
  base_hash = base_hash_for(options)
9
11
  if name_or_names
10
- field = field_for(model, 'nombre')
12
+ field = field_for(model)
11
13
  names = name_or_names.split(/ ?, | y /)
12
14
  if names.size == number
13
15
  names.map { |name| base_hash.dup.merge(field => name) }
@@ -19,8 +21,16 @@ module MundoPepino
19
21
  end
20
22
  end
21
23
 
22
- def field_for(model, campo = 'nombre')
23
- "#{model && model.name}::#{campo}".to_field || campo.to_field
24
+ def field_for(model=nil, field = nil)
25
+ model_name = "#{model && model.name+'::'}"
26
+ if field
27
+ "#{model_name}#{field}".to_field || field.to_field
28
+ else
29
+ # The use of "nombre" the name field mapping is deprecated
30
+ "#{model_name}nombre".to_field || 'nombre'.to_field ||
31
+ # "Model::name" or "name" (for a global mapping) is the right use.
32
+ "#{model_name}name".to_field || 'name'.to_field || :name
33
+ end
24
34
  end
25
35
 
26
36
  def shouldify(should_or_not)
@@ -175,6 +185,32 @@ module MundoPepino
175
185
  raise MundoPepino::ModelNotMapped.new(unquoted_model)
176
186
  end
177
187
  end
188
+
189
+ def nested_field_id(nested_field, nested_model, nested_name, parent_resource=nil)
190
+ unquoted_model = nested_model.to_unquoted
191
+ if model = unquoted_model.to_model
192
+ if res = model.send("find_by_#{field_for(model)}", nested_name)
193
+ if field_prefix = nested_field_id_prefix(res, parent_resource)
194
+ "#{field_prefix}#{nested_field.to_field}"
195
+ end
196
+ else
197
+ raise MundoPepino::ResourceNotFound.new("No '#{unquoted_model}' called '#{nested_name}'")
198
+ end
199
+ else
200
+ raise MundoPepino::ModelNotMapped.new(unquoted_model)
201
+ end
202
+ end
203
+
204
+ def nested_field_id_prefix(resource, parent_resource=nil)
205
+ parent = parent_resource ? parent_resource.mr_model.name.underscore : '[a-z][a-z_]*[a-z]'
206
+ children = resource.class.name.pluralize.underscore
207
+ preprefix = "#{parent}_#{children}_attributes"
208
+ Nokogiri::HTML.parse(response.body).xpath(
209
+ "//input[@type='hidden' and @value=#{resource.id}]"
210
+ ).each do |input|
211
+ return "#{preprefix}_#{$1}_" if input.attributes['id'].to_s =~ /#{preprefix}_([0-9]+)_id/
212
+ end
213
+ end
178
214
  end
179
215
  end
180
216
 
@@ -90,7 +90,7 @@ module MundoPepino
90
90
 
91
91
  def add_resource_from_database(modelo, nombre)
92
92
  model = modelo.to_unquoted.to_model
93
- field = field_for(model, 'nombre')
93
+ field = field_for(model)
94
94
  if resource = model.send("find_by_#{field}", nombre)
95
95
  pile_up resource
96
96
  else
@@ -165,7 +165,7 @@ module MundoPepino
165
165
  arr.detect { |r| r.respond_to?(method) && r.send(method, value) }
166
166
  elsif value.is_a? Array
167
167
  model, val = value # [ class, value ]
168
- name_field = field_for(model, 'nombre')
168
+ name_field = field_for(model)
169
169
  arr.detect do |r|
170
170
  r.respond_to?(:is_a?) && r.is_a?(model) && r.send(name_field) =~ /#{val}/i
171
171
  end
@@ -187,7 +187,7 @@ module MundoPepino
187
187
  [[ mentioned ], [ valor ]]
188
188
  end
189
189
  field, values = if (child_model = campo.to_model)
190
- child_name_field = field_for(mentioned.mr_model, 'nombre')
190
+ child_name_field = field_for(mentioned.mr_model)
191
191
  values = add_resource(child_model,
192
192
  valores.map { |val| { child_name_field => val } })
193
193
  values = [ values ] unless values.is_a?(Array)
@@ -2,7 +2,7 @@ module MundoPepino #:nodoc:
2
2
  class VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 5
5
+ TINY = 6
6
6
  PATCH = nil # Set to nil for official release
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PATCH].compact.join('.')
@@ -16,13 +16,13 @@ MundoPepino.configure do |config|
16
16
 
17
17
  config.field_mappings = {
18
18
  # TRADUCCIÓN DE CAMPOS AQUÍ:
19
- # /^[Ááa]reas?$/i => 'area',
20
- # /^color(es)?$/i => 'color',
21
- # /^latitud(es)?$/i => 'latitude',
22
- # /^longitud(es)?/i => 'length'
19
+ # /^[Ááa]reas?$/i => :area,
20
+ # /^color(es)?$/i => :color,
21
+ # /^latitud(es)?$/i => :latitude,
22
+ # /^longitud(es)?/i => :length
23
23
  #
24
24
  # TRADUCCIÓN ESPECÍFICA PARA UN MODELO
25
- # /^Orchard::longitud(es)?$/ => 'longitude'
25
+ # /^Orchard::longitud(es)?$/ => :longitude
26
26
  }
27
27
  end
28
28
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mundo-pepino
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Fernando Garc\xC3\xADa Samblas"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-04 00:00:00 +01:00
12
+ date: 2009-11-13 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -62,6 +62,16 @@ dependencies:
62
62
  - !ruby/object:Gem::Version
63
63
  version: 1.2.6
64
64
  version:
65
+ - !ruby/object:Gem::Dependency
66
+ name: nokogiri
67
+ type: :runtime
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 1.2.0
74
+ version:
65
75
  - !ruby/object:Gem::Dependency
66
76
  name: string-mapper
67
77
  type: :runtime