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 +12 -1
- data/README_es.markdown +230 -178
- data/lib/mundo_pepino/base.rb +1 -1
- data/lib/mundo_pepino/en_US/mappings.rb +1 -1
- data/lib/mundo_pepino/es_ES/definitions.rb +6 -1
- data/lib/mundo_pepino/es_ES/matchers.rb +4 -0
- data/lib/mundo_pepino/implementations.rb +1 -1
- data/lib/mundo_pepino/implementations_api.rb +39 -3
- data/lib/mundo_pepino/resources_history.rb +3 -3
- data/lib/mundo_pepino/version.rb +1 -1
- data/rails_generators/mundo_pepino/templates/mundo_pepino_es_ES.rb +5 -5
- metadata +12 -2
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
|
-
*
|
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
|
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
|
-
|
55
|
+
El primer paso del primer escenario generado por ''caracteristica'' en el fichero ''features/gestion_de_huertos.feature'' es la siguiente:
|
75
56
|
|
76
|
-
|
57
|
+
Dado que visito la página de nuevo/a Huerto
|
77
58
|
|
78
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
77
|
+
### Primera convención y como saltársela: campo **name** para el //nombre// en todos los modelos
|
189
78
|
|
190
|
-
|
79
|
+
Como acabamos de comentar:
|
80
|
+
|
81
|
+
''Dado que tengo un usuario llamado "Casimiro"''
|
191
82
|
|
192
|
-
|
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
|
-
|
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
|
-
|
87
|
+
config.model_mappings = {
|
88
|
+
/^User::name$/ => :login
|
89
|
+
}
|
203
90
|
|
204
|
-
|
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
|
-
|
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
|
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
|
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
|
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>
|
data/lib/mundo_pepino/base.rb
CHANGED
@@ -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
|
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
|
@@ -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
|
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
|
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,
|
23
|
-
"#{model && model.name}
|
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
|
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
|
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
|
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)
|
data/lib/mundo_pepino/version.rb
CHANGED
@@ -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 =>
|
20
|
-
# /^color(es)?$/i =>
|
21
|
-
# /^latitud(es)?$/i =>
|
22
|
-
# /^longitud(es)?/i =>
|
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)?$/ =>
|
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.
|
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-
|
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
|