Skip to content

Commit e8a3aa5

Browse files
authored
Merge pull request #85 from cucumber/feature/add-as-scala-raw-list-helper-method
Add asScalaRaw extension methods to DataTable
2 parents 3ec8266 + c881e2d commit e8a3aa5

File tree

6 files changed

+171
-35
lines changed

6 files changed

+171
-35
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ See also the [CHANGELOG](https://github.com/cucumber/cucumber-jvm/blob/master/CH
1111

1212
### Added
1313

14+
- Add `asScalaRawList[T]`, `asScalaRawMaps[T]` and `asScalaRawLists[T]` on `DataTable` (through `io.cucumber.scala.Implicits`) ([#83](https://github.com/cucumber/cucumber-jvm-scala/issues/83) Gaël Jourdan-Weil)
15+
1416
### Changed
1517

1618
### Deprecated

docs/datatables.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Cucumber Scala support DataTables with either:
88

99
See below the exhaustive list of possible mappings.
1010

11+
_Note: you can use [transformers](transformers.md) to map DataTables to custom types._
12+
1113
## As Map of Map
1214

1315
```gherkin

docs/transformers.md

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,15 @@ Given the following authors
113113
```
114114

115115
```scala
116-
Given("the following authors") { (authors: java.util.List[Author]) =>
117-
// Do something
118-
}
116+
import io.cucumber.scala.Implicits._
119117

120-
// Or using DataTable
121118
Given("the following authors") { (table: DataTable) =>
122-
val authors = table.asList[Author](classOf[Author])
119+
val authors = table.asScalaRawList[Author]
120+
}
121+
122+
// Or using Java type
123+
Given("the following authors") { (authors: java.util.List[Author]) =>
124+
// Do something
123125
}
124126
```
125127

@@ -142,28 +144,30 @@ Given the following authors
142144
```
143145

144146
```scala
145-
Given("the following authors") { (authors: java.util.List[Author]) =>
146-
// Do something
147-
}
147+
import io.cucumber.scala.Implicits._
148148

149-
// Or using DataTable
150149
Given("the following authors") { (table: DataTable) =>
151-
val authors = table.asList[Author](classOf[Author])
150+
val authors = table.asScalaRawList[Author]
151+
}
152+
153+
// Or using Java types
154+
Given("the following authors") { (authors: java.util.List[Author]) =>
155+
// Do something
152156
}
153157
```
154158

155159
### DataTable
156160

157161
For instance, the following transformer can be defined:
158162
```scala
163+
import io.cucumber.scala.Implicits._
164+
159165
case class Author(name: String, surname: String, famousBook: String)
160166
case class GroupOfAuthor(authors: Seq[Author])
161167

162168
DataTableType { table: DataTable =>
163-
val authors = table.asMaps().asScala
164-
.map(_.asScala)
165-
.map(entry => Author(entry("name"), entry("surname"), entry("famousBook")))
166-
.toSeq
169+
val authors = table.asScalaMaps
170+
.map(entry => Author(entry("name").getOrElse(""), entry("surname").getOrElse(""), entry("famousBook").getOrElse("")))
167171
GroupOfAuthor(authors)
168172
}
169173
```
@@ -204,13 +208,15 @@ Given the following authors
204208
```
205209

206210
```scala
207-
Given("the following authors") { (authors: java.util.List[java.util.List[RichCell]]) =>
208-
// Do something
209-
}
211+
import io.cucumber.scala.Implicits._
210212

211-
// Or using DataTable
212213
Given("the following authors") { (table: DataTable) =>
213-
val authors = table.asLists[RichCell](classOf[RichCell]))
214+
val authors = table.asScalaRawLists[RichCell]
215+
}
216+
217+
// Or using Java types
218+
Given("the following authors") { (authors: java.util.List[java.util.List[RichCell]]) =>
219+
// Do something
214220
}
215221
```
216222

@@ -223,13 +229,15 @@ Given the following authors
223229
```
224230

225231
```scala
226-
Given("the following authors") { (authors: java.util.List[java.util.Map[String, RichCell]]) =>
227-
// Do something
228-
}
232+
import io.cucumber.scala.Implicits._
229233

230-
// Or using DataTable
231234
Given("the following authors") { (table: DataTable) =>
232-
val authors = table.asMaps[String, RichCell](classOf[String], classOf[RichCell])
235+
val authors = table.asScalaRawMaps[String, RichCell]
236+
}
237+
238+
// Or with Java Types
239+
Given("the following authors") { (authors: java.util.List[java.util.Map[String, RichCell]]) =>
240+
// Do something
233241
}
234242
```
235243

@@ -296,13 +304,15 @@ DefaultDataTableEntryTransformer("[empty]") { (fromValue: Map[String, String], t
296304

297305
Will be used to convert with such step definitions:
298306
```scala
299-
Given("A step with a datatable") { (rows: java.util.List[SomeType]) =>
300-
// Do something
301-
}
307+
import io.cucumber.scala.Implicits._
302308

303-
// Or DataTable
304309
Given("A step with a datatable") { (dataTable: DataTable) =>
305-
val table = dataTable.asList[SomeType](classOf[SomeType])
310+
val table = dataTable.asScalaRawList[SomeType]
311+
}
312+
313+
// Or with Java types
314+
Given("A step with a datatable") { (rows: java.util.List[SomeType]) =>
315+
// Do something
306316
}
307317
```
308318

@@ -319,12 +329,14 @@ DefaultDataTableCellTransformer("[empty]") { (fromValue: String, toValueType: ja
319329

320330
Will be used to convert with such step definitions:
321331
```scala
322-
Given("A step with a datatable") { (rows: java.util.List[java.util.List[SomeType]]) =>
323-
// Do something
324-
}
332+
import io.cucumber.scala.Implicits._
325333

326-
// Or DataTable
327334
Given("A step with a datatable") { (dataTable: DataTable) =>
328-
val table = dataTable.asLists[SomeType](classOf[SomeType])
335+
val table = dataTable.asScalaRawLists[SomeType]
336+
}
337+
338+
// Or with Java Types
339+
Given("A step with a datatable") { (rows: java.util.List[java.util.List[SomeType]]) =>
340+
// Do something
329341
}
330342
```

scala/sources/src/main/scala/io/cucumber/scala/Implicits.scala

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ object Implicits {
2323
* Provides a view of the DataTable as a sequence of rows, each row being a key-value map where key is the column name.
2424
* Equivalent of `.asMaps[K,V](classOf[K], classOf[V])` but returned as Scala collection types without `null` values.
2525
*
26+
* See also `asScalaRawMaps[T]` if you don't need `Option`s (for instance if you are using a DataTableType).
27+
*
2628
* @tparam K key type
2729
* @tparam V value type
2830
* @return sequence of rows
@@ -42,6 +44,23 @@ object Implicits {
4244
*/
4345
def asScalaMaps: Seq[Map[String, Option[String]]] = asScalaMaps[String, String]
4446

47+
/**
48+
* Provides a view of the DataTable as a sequence of rows, each row being a key-value map where key is the column name.
49+
* Equivalent of `.asMaps[K,V](classOf[K], classOf[V])` but returned as Scala collection types.
50+
*
51+
* See also `asScalaMaps[T]`.
52+
*
53+
* @tparam K key type
54+
* @tparam V value type
55+
* @return sequence of rows
56+
*/
57+
def asScalaRawMaps[K, V](implicit evK: ClassTag[K], evV: ClassTag[V]): Seq[Map[K, V]] = {
58+
table.asMaps[K, V](evK.runtimeClass, evV.runtimeClass)
59+
.asScala
60+
.map(_.asScala.toMap)
61+
.toSeq
62+
}
63+
4564
/**
4665
* Provides a view of the DataTable as a key-value map where key are the first column values.
4766
* Equivalent of `.asMap[K,V](classOf[K],classOf[V])` but returned as Scala collection types without `null` values.
@@ -61,6 +80,8 @@ object Implicits {
6180
* Provides a view of the DataTable as a matrix.
6281
* Equivalent of `.asLists[T](classOf[T])` but returned as Scala collection types without `null` values.
6382
*
83+
* See also `asScalaRawLists[T]` if you don't need `Option`s (for instance if you are using a DataTableType).
84+
*
6485
* @tparam T cell type
6586
* @return matrix
6687
*/
@@ -79,10 +100,28 @@ object Implicits {
79100
*/
80101
def asScalaLists: Seq[Seq[Option[String]]] = asScalaLists[String]
81102

103+
/**
104+
* Provides a view of the DataTable as a matrix.
105+
* Equivalent of `.asLists[T](classOf[T])` but returned as Scala collection types.
106+
*
107+
* See also `asScalaLists[T]`
108+
*
109+
* @tparam T cell type
110+
* @return matrix
111+
*/
112+
def asScalaRawLists[T](implicit ev: ClassTag[T]): Seq[Seq[T]] = {
113+
table.asLists[T](ev.runtimeClass)
114+
.asScala
115+
.map(_.asScala.toSeq)
116+
.toSeq
117+
}
118+
82119
/**
83120
* Provides a view of the DataTable as a simple list of values.
84121
* Equivalent of `.asList[T](classOf[T])` but returned as Scala collection types without `null` values.
85122
*
123+
* See also `asScalaRawList[T]` if you don't need `Option`s (for instance if you are using a DataTableType).
124+
*
86125
* @tparam T cell type
87126
* @return list of values
88127
*/
@@ -101,6 +140,21 @@ object Implicits {
101140
*/
102141
def asScalaList: Seq[Option[String]] = asScalaList[String]
103142

143+
/**
144+
* Provides a view of the DataTable as a simple list of values.
145+
* Equivalent of `.asList[T](classOf[T])` but returned as Scala collection types.
146+
*
147+
* See also `asScalaList[T]`.
148+
*
149+
* @tparam T cell/row type
150+
* @return list of values
151+
*/
152+
def asScalaRawList[T](implicit ev: ClassTag[T]): Seq[T] = {
153+
table.asList[T](ev.runtimeClass)
154+
.asScala
155+
.toSeq
156+
}
157+
104158
/**
105159
* Provides a view of the DataTable as a full table: a key-value map of row where keys are the first column values
106160
* and each row being itself a key-value map where key is the column name.

scala/sources/src/test/resources/tests/datatables/DatatableAsScala.feature

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,27 @@ Feature: As Cucumber Scala, I want to parse DataTables to Scala types properly
9292
Given the following table as Scala List of integers
9393
| 11 |
9494
| |
95-
| 31 |
95+
| 31 |
96+
97+
# With custom types using DatatableType
98+
99+
Scenario: As List of custom type
100+
Given the following table as Scala List of custom type
101+
| key1 | key2 | key3 |
102+
| val11 | val12 | val13 |
103+
| val21 | | val23 |
104+
| val31 | val32 | val33 |
105+
106+
Scenario: As List of List of custom type
107+
Given the following table as Scala List of List of custom type
108+
| val11 | val12 | val13 |
109+
| val21 | | val23 |
110+
| val31 | val32 | val33 |
111+
112+
Scenario: As List of Map of custom type
113+
Given the following table as Scala List of Map of custom type
114+
| key1 | key2 | key3 |
115+
| val11 | val12 | val13 |
116+
| val21 | | val23 |
117+
| val31 | val32 | val33 |
118+

scala/sources/src/test/scala/tests/datatables/DatatableAsScalaSteps.scala

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,47 @@ class DatatableAsScalaSteps extends ScalaDsl with EN {
146146
assert(data == expected)
147147
}
148148

149+
case class CustomType(key1: String, key2: Option[String], key3: String)
150+
151+
DataTableType { map: Map[String, String] =>
152+
CustomType(map("key1"), Option(map("key2")), map("key3"))
153+
}
154+
155+
Given("the following table as Scala List of custom type") { (table: DataTable) =>
156+
val data: Seq[CustomType] = table.asScalaRawList[CustomType]
157+
val expected = Seq(
158+
CustomType("val11", Some("val12"), "val13"),
159+
CustomType("val21", None, "val23"),
160+
CustomType("val31", Some("val32"), "val33")
161+
)
162+
assert(data == expected)
163+
}
164+
165+
case class RichCell(content: Option[String])
166+
167+
DataTableType { cell: String =>
168+
RichCell(Option(cell))
169+
}
170+
171+
Given("the following table as Scala List of List of custom type") { (table: DataTable) =>
172+
val data: Seq[Seq[RichCell]] = table.asScalaRawLists[RichCell]
173+
val expected = Seq(
174+
Seq(RichCell(Some("val11")), RichCell(Some("val12")), RichCell(Some("val13"))),
175+
Seq(RichCell(Some("val21")), RichCell(None), RichCell(Some("val23"))),
176+
Seq(RichCell(Some("val31")), RichCell(Some("val32")), RichCell(Some("val33")))
177+
)
178+
assert(data == expected)
179+
}
180+
181+
Given("the following table as Scala List of Map of custom type") { (table: DataTable) =>
182+
val data: Seq[Map[String, RichCell]] = table.asScalaRawMaps[String, RichCell]
183+
val expected = Seq(
184+
Map("key1" -> RichCell(Some("val11")), "key2" -> RichCell(Some("val12")), "key3" -> RichCell(Some("val13"))),
185+
Map("key1" -> RichCell(Some("val21")), "key2" -> RichCell(None), "key3" -> RichCell(Some("val23"))),
186+
Map("key1" -> RichCell(Some("val31")), "key2" -> RichCell(Some("val32")), "key3" -> RichCell(Some("val33")))
187+
)
188+
assert(data == expected)
189+
190+
}
191+
149192
}

0 commit comments

Comments
 (0)