groovycsv-releases-1.0/ 0000775 0000000 0000000 00000000000 11717712403 0015217 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/.gitignore 0000664 0000000 0000000 00000000060 11717712403 0017203 0 ustar 00root root 0000000 0000000 .gradle/*
build/*
lib/*
_site
gradle.properties
groovycsv-releases-1.0/LICENSE 0000664 0000000 0000000 00000001113 11717712403 0016220 0 ustar 00root root 0000000 0000000 Copyright 2010 Leonard Axelsson
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
groovycsv-releases-1.0/README.md 0000664 0000000 0000000 00000005334 11717712403 0016503 0 ustar 00root root 0000000 0000000 # GroovyCSV
GroovyCSV is a library for Groovy which aims to make csv data
easier (and more idiomatically Groovy) to work with. The library was inspired by @[goeh's](http://twitter.com/goeh)
[ExcelBuilder](http://www.technipelago.se/blog/?p=44) that lets you
iterate over rows in the excel file using `eachLine` and access values
using the column names.
*Important*
Package structure was changed from `com.xlson.csvparser` to
`com.xlson.groovycsv` between release 0.1 and 0.2.
## Features
* Value-access by header name or position
* Iteration using the ordinary collection methods (`findAll`, `collect`
and so on)
* Full support for OpenCSV's configurability
* Support for guessing separator and/or quote character
* Support for reading csv without headers
## Example
The parse method returns an iterator over the rows in the csv. This
means we can use any of the default groovy ways to iterate, in this
example we see the for each loop in use.
@Grab('com.xlson.groovycsv:groovycsv:1.0')
import static com.xlson.groovycsv.CsvParser.parseCsv
def csv = '''Name,Lastname
Mark,Andersson
Pete,Hansen'''
def data = parseCsv(csv)
for(line in data) {
println "$line.Name $line.Lastname"
}
The parse method takes a String or a Reader as argument.
**Output:**
Mark Andersson
Pete Hansen
## Getting GroovyCSV
GroovyCSV is available in Maven Central. It is also available directly from GitHub
(links below).
### Maven & Ivy configuration
#### Latest stable
* *GroupId:* com.xlson.groovycsv
* *ArtifactId:* groovycsv
* *Version:* 1.0
#### Latest snapshot
* *Version:* 1.0-SNAPSHOT
* *Repository:* https://oss.sonatype.org/content/groups/public/
### Downloads
*GroovyCSV 1.0*
* [groovycsv-1.0.jar](https://github.com/downloads/xlson/groovycsv/groovycsv-0.2.jar)
* [groovycsv-1.0-javadoc.jar](https://github.com/downloads/xlson/groovycsv/groovycsv-0.2-javadoc.jar)
* [Javadoc Online](http://xlson.github.com/groovycsv/docs/1.0/javadoc/)
## Dependencies
* [Groovy 1.7.x](http://groovy.codehaus.org)
* [OpenCSV 2.x](http://opencsv.sourceforge.net/)
Many thanks to Glen Smith and the other's in the OpenCSV team for
doing all the heavy lifting.
## Building
GroovyCSV uses Gradle for building as is packaged with the gradle wrapper which will download and install gradle for you behind the scenes the first time you run it.
**Build instruction**
1. Fetch the latest code: `git clone git://github.com/xlson/groovycsv.git`
2. (Optional) Run the tests using the gradle wrapper `./gradlew test`
4. Go to the project directory and run: `./gradlew jar`
You will find the built jar in `./build/libs`. If you need any
dependencies you can download them using `./gradlew downloadDeps`, they
end up in the `lib` folder.
groovycsv-releases-1.0/build.gradle 0000664 0000000 0000000 00000007301 11717712403 0017477 0 ustar 00root root 0000000 0000000 buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'de.huxhorn.gradle:de.huxhorn.gradle.pgp-plugin:0.0.4'
}
}
apply plugin: 'groovy'
apply plugin: 'maven'
apply plugin: de.huxhorn.gradle.pgp.PgpPlugin
apply plugin: 'idea'
repositories {
mavenCentral()
mavenRepo urls: "http://m2repo.spockframework.org/snapshots"
}
dependencies {
groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.7.3'
compile 'net.sf.opencsv:opencsv:2.1'
testCompile "org.spockframework:spock-core:0.4-groovy-1.7"
testCompile "cglib:cglib-nodep:2.2"
testCompile "org.objenesis:objenesis:1.2"
}
version = '1.0'
group = 'com.xlson.groovycsv'
sourceSets {
main {
groovy {
srcDir 'src'
}
}
test {
groovy {
srcDir 'test'
}
}
}
task groovydocJar(type: Jar, dependsOn: groovydoc) {
classifier = 'javadoc'
from 'build/docs/groovydoc'
}
task sourcesJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
}
artifacts {
archives groovydocJar
archives sourcesJar
}
def deployer = null
def installer = install.repositories.mavenInstaller
uploadArchives {
// Checks if login information for the logon repo is set correctly.
// Should be set in gradle.properties (check gradle.properties.example)
if(project.hasProperty('repoUserName') && project.hasProperty('repoPassword')) {
repositories {
deployer = mavenDeployer {
configureAuth = {
authentication(userName: repoUserName, password: repoPassword)
}
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/", configureAuth)
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/", configureAuth)
}
}
}
}
[installer, deployer]*.pom*.whenConfigured {pom ->
pom.project {
name 'GroovyCSV'
packaging 'jar' // not working
description 'Library for parsing csv in Groovy'
url 'http://github.com/xlson/groovycsv'
inceptionYear '2010'
scm {
url 'scm:git:git@github.com:xlson/groovycsv.git'
connection 'http://github.com/xlson/groovycsv'
}
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
developers {
developer {
id 'xlson'
name 'Leonard Axelsson'
email 'leonard.axelsson@gmail.com'
url 'http://xlson.com/'
timezone '+1'
}
}
}
pom.withXml { XmlProvider xmlProvider ->
def xml = xmlProvider.asString()
def pomXml = new XmlParser().parseText(xml.toString())
pomXml.version[0] + { packaging('jar') }
def newXml = new StringWriter()
def printer = new XmlNodePrinter(new PrintWriter(newXml))
printer.preserveWhitespace = true
printer.print(pomXml)
xml.setLength(0)
xml.append(newXml.toString())
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.0-milestone-3'
}
task downloadDeps << {
def libDir = file('lib')
ant.delete(dir: libDir)
copy {
from configurations.testRuntime
into libDir
}
}
groovycsv-releases-1.0/gradle.properties.example 0000664 0000000 0000000 00000000200 11717712403 0022215 0 ustar 00root root 0000000 0000000 // This must be configured if you wanna deploy to the Nexus OSS Public Repo
repoUserName=usernameHere
repoPassword=passwordHere
groovycsv-releases-1.0/samples/ 0000775 0000000 0000000 00000000000 11717712403 0016663 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/samples/GettingDependencyUsingGrab.groovy 0000664 0000000 0000000 00000000357 11717712403 0025341 0 ustar 00root root 0000000 0000000 @Grab('com.xlson.groovycsv:groovycsv:0.2')
import com.xlson.groovycsv.CsvParser
def csv = '''Name,Lastname
Mark,Andersson
Pete,Hansen'''
def data = new CsvParser().parse(csv)
for(line in data) {
println "$line.Name $line.Lastname"
}
groovycsv-releases-1.0/samples/UsingAutoDetection.groovy 0000664 0000000 0000000 00000000325 11717712403 0023707 0 ustar 00root root 0000000 0000000 import com.xlson.groovycsv.CsvParser
def csv = '''Name:Lastname
Mark:Andersson
Pete:Hansen'''
def data = new CsvParser().parse(csv, autoDetect:true)
for(line in data) {
println "$line.Name $line.Lastname"
}
groovycsv-releases-1.0/src/ 0000775 0000000 0000000 00000000000 11717712403 0016006 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/src/com/ 0000775 0000000 0000000 00000000000 11717712403 0016564 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/src/com/xlson/ 0000775 0000000 0000000 00000000000 11717712403 0017727 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/src/com/xlson/groovycsv/ 0000775 0000000 0000000 00000000000 11717712403 0021770 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/src/com/xlson/groovycsv/AutoDetectHandler.groovy 0000664 0000000 0000000 00000001573 11717712403 0026604 0 ustar 00root root 0000000 0000000 package com.xlson.groovycsv
class AutoDetectHandler {
List autoDetectSeparators = [",", ";", ":", "|"]
List autoDetectQuoteChars = ['"', "'", "%"]
String linesToInspect
String autoDetectQuoteChar() {
return mostFrequentChar(linesToInspect, autoDetectQuoteChars)
}
String autoDetectSeparator() {
return mostFrequentChar(linesToInspect, autoDetectSeparators)
}
/**
* Find the most frequent character in a string among a list of characters.
* Falls back on the first character in the list if no character is found.
*
* @param sequence The string to search.
* @param characters The list of characters to search.
* @return The most frequent character.
*/
private mostFrequentChar(String sequence, List characters) {
characters.max{ sequence.count(it) }
}
}
groovycsv-releases-1.0/src/com/xlson/groovycsv/CsvIterator.groovy 0000664 0000000 0000000 00000006133 11717712403 0025507 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Leonard Axelsson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xlson.groovycsv
import au.com.bytecode.opencsv.CSVReader
/**
* Iterates over the csv data in a non-synchronized way.
*
* @author Leonard Axelsson
* @since 0.1
*/
class CsvIterator implements Iterator {
private def columns
private CSVReader csvReader
private def readValue
private Boolean closed = false
def CsvIterator(def columnNames, CSVReader csvReader) {
this.columns = [:]
columnNames.eachWithIndex { name, i ->
columns."$name" = i
}
this.csvReader = csvReader
}
/**
* Closes the underlying reader object. Could be useful if one would
* not like to read all of the csv into memory.
*
* @throws IllegalStateException if the underlying dataset is already closed.
*/
void close() {
throwsExceptionIfClosed()
closed = true
csvReader.close()
}
/**
* Checks if there is more data available. Will close the underlying dataset
* if there isn't any more data.
*
* @return true if there is more data in the iterator
*/
boolean hasNext() {
if(isClosed()) {
return false
}
else if(nextValueIsRead()) {
return true
} else {
readValue = csvReader.readNext()
if(readValue == null) {
close()
}
return readValue != null
}
}
/**
* Checks if the underlying reader is closed.
*
* @return true if the underlying reader is closed
*/
boolean isClosed() {
closed
}
private boolean nextValueIsRead() {
readValue as boolean
}
private def getNextValue() {
if(nextValueIsRead()) {
def value = readValue
readValue = null
return value
} else {
return csvReader.readNext()
}
}
/**
* Gets the next row in the csv file.
*
* @return an instance of PropertyMapper
*/
def next() {
throwsExceptionIfClosed()
new PropertyMapper(columns: columns, values: nextValue)
}
private def throwsExceptionIfClosed() {
if (isClosed()) {
throw new IllegalStateException("The connection the underlying dataset has already been closed.")
}
}
/**
* remove is not supported in CsvIterator.
*
* @throws UnsupportedOperationException when called
*/
void remove() {
throw new UnsupportedOperationException()
}
}
groovycsv-releases-1.0/src/com/xlson/groovycsv/CsvParser.groovy 0000664 0000000 0000000 00000014557 11717712403 0025163 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Leonard Axelsson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xlson.groovycsv
import au.com.bytecode.opencsv.CSVReader
/**
* Helper class used to parse information from csv files using the column names
* in the first line. Currently it only supports csv files where the first line
* contains the column names.
*
* Usage: *
* def csv = '''Name,Lastname * Mark,Andersson * Pete,Hansen''' * * def data = new CsvParser().parse(csv) * for(line in data) { * println "$line.Name $line.Lastname" * }* * * @author Leonard Axelsson * @since 0.1 */ class CsvParser { /** * Number of characters used to provide to autodetection (in case auto * detection is used. */ Integer autoDetectCharNumber = 1000 /** * Parses a string as csv in the same way as CsvParser.parse(...). * * @param args * @param csv * @return */ static Iterator parseCsv(Map args = [:], String csv) { new CsvParser().parse(args, csv) } /** * Parses a reader as csv in the same way as CsvParser.parse(...). * * @param args * @param csv * @return */ static Iterator parseCsv(Map args = [:], Reader reader) { new CsvParser().parse(args, reader) } /** * Parses the csv supplied using the reader. See parse(Reader reader) for * more information about usage. * * @param args configurable parameters * @param csv the csv to parse * @return an instance of
com.xlson.groovycsv.CsvIterator
*/
Iterator parse(Map args = [:], String csv) {
parse(args, new StringReader(csv))
}
/**
* Parses the supplied csv and returns a CsvIterator that can be
* use to access the data. The first line of the csv will be used
* as column-headers. Named paramenters can be used to configure the
* parsing, see the class documentation for more more information on
* usage. There's also support for autodetecting the quote and separator
* characters.
* * Arguments for configuration: *
* Usage: *
* def csv = '''Fruit-Quantity * Apple-2 * Pear-5''' * * def data = new CsvParser().parse(csv, separator: '-') * * // Print all fruits that have a quantity higher than 3 * data.findAll{ (it.Quantity as int) > 3 }.each{ println it } ** * @param reader the csv to parse * @param args the configuration arguments * @return an instance of
com.xlson.groovycsv.CsvIterator
*/
Iterator parse(Map args = [:], Reader reader) {
def csvReader = createCSVReader(args, reader)
def columnNames = parseColumnNames(args, csvReader)
new CsvIterator(columnNames, csvReader)
}
private def parseColumnNames(Map args, CSVReader csvReader) {
def columnNames
if (!args.readFirstLine) {
columnNames = csvReader.readNext()
}
if (args.columnNames) {
columnNames = args.columnNames
}
return columnNames
}
private CSVReader createCSVReader(Map args = [:], Reader reader) {
char separator
char quoteChar
char escapeChar = args.escapeChar
if (args.autoDetect == true) {
reader = new PushbackReader(reader, autoDetectCharNumber)
doAutoDetection(args, reader)
separator = args.separator
quoteChar = args.quoteChar
} else {
separator = args.separator ?: ','
quoteChar = args.quoteChar ?: '"'
}
if(escapeChar) {
return new CSVReader(reader, separator, quoteChar, escapeChar)
} else {
return new CSVReader(reader, separator, quoteChar)
}
}
/**
* Performs automatic detection of separator and quote character.
*
* It will search arguments for values 'auto' in separator and quoteChar. It
* will return a new version of the arguments modified with the values that
* were found.
*
* If nothing is detected, the values are removed from the args.
*
* Note that
*
* @param args the configuration arguments.
* @param text the CSV as a String.
* @return modified args with detected.
*/
private Map doAutoDetection(Map args, PushbackReader reader) {
def buf = new char[autoDetectCharNumber]
def charsRead = reader.read(buf)
def linesToInspect = new String(buf)
reader.unread(buf, 0, charsRead)
def autoDetector = new AutoDetectHandler(linesToInspect: linesToInspect)
if (args.autoDetectQuoteChars) {
autoDetector.autoDetectQuoteChars = args.autoDetectQuoteChars
}
if (args.autoDetectSeparators) {
autoDetector.autoDetectSeparators = args.autoDetectSeparators
}
if (!args.separator) {
def detectedSeparator = autoDetector.autoDetectSeparator()
if (detectedSeparator) args.separator = detectedSeparator
else args.remove("separator")
}
if(!args.quoteChar) {
def detectedQuoteChar = autoDetector.autoDetectQuoteChar()
if (detectedQuoteChar) args.quoteChar = detectedQuoteChar
else args.remove("quoteChar")
}
return args
}
}
groovycsv-releases-1.0/src/com/xlson/groovycsv/PropertyMapper.groovy 0000664 0000000 0000000 00000003310 11717712403 0026225 0 ustar 00root root 0000000 0000000 /*
* Copyright 2010 Leonard Axelsson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xlson.groovycsv
/**
* Maps between column names and values in a list. Uses propertyMissing
* to allow for named access.
*
* @author Leonard Axelsson
* @since 0.1
*/
class PropertyMapper {
/**
* A list of values for one csv line.
*/
def values
/**
* The columns of the csv.
*/
def columns = [:]
/**
* Maps properties to values.
*
* @param name the name of the property
* @return the value as a String
* @throws MissingPropertyException where the values-list doesn't contain enough data.
*/
def propertyMissing(String name) {
def index = columns[name]
if (index != null) {
values[index]
} else {
throw new MissingPropertyException(name)
}
}
/**
* Allows values to be obtained using their position
*
* @param index
* @return the value at that position
*/
def getAt(Integer index) {
values[index]
}
String toString() {
columns.collect { key, index -> "$key: ${values[index]}" }.join(', ')
}
}
groovycsv-releases-1.0/test/ 0000775 0000000 0000000 00000000000 11717712403 0016176 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/test/com/ 0000775 0000000 0000000 00000000000 11717712403 0016754 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/test/com/xlson/ 0000775 0000000 0000000 00000000000 11717712403 0020117 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/test/com/xlson/groovycsv/ 0000775 0000000 0000000 00000000000 11717712403 0022160 5 ustar 00root root 0000000 0000000 groovycsv-releases-1.0/test/com/xlson/groovycsv/AutoDetectHandlerSpec.groovy 0000664 0000000 0000000 00000003220 11717712403 0027576 0 ustar 00root root 0000000 0000000 package com.xlson.groovycsv
import spock.lang.Specification;
class AutoDetectHandlerSpec extends Specification {
def "should auto detect quote character"() {
setup:
def adh = new AutoDetectHandler(linesToInspect: csvData)
expect:
adh.autoDetectQuoteChar() == quoteChar
where:
csvData | quoteChar
testDataWithColumnNamesAnd3Rows | '"'
testDataWithColumnNamesAnd2Rows | '"'
csvUsingDoubleQuoteAsQuoteChar | '"'
csvUsingPercentageAsQuoteChar | "%"
}
def "should auto detect separator"() {
setup:
def adh = new AutoDetectHandler(linesToInspect: csvData)
expect:
adh.autoDetectSeparator() == separator
where:
csvData | separator
testDataWithColumnNamesAnd3Rows | ","
testDataWithColumnNamesAnd2Rows | ","
csvUsingDoubleQuoteAsQuoteChar | ','
csvWithColonAsSeparator | ":"
}
def getTestDataWithColumnNamesAnd3Rows() {
'''Name,Lastname,Age,Email
Mark,Hamilton,45,mark@hamilton.com
Bosse,Bildoktorn,50,bildoktorn@tv4.se
Peps,Persson,65,peps.persson@hotmail.com'''
}
def getTestDataWithColumnNamesAnd2Rows() {
'''Letter,Word,Number
a,paris,5
h,drink,60'''
}
def getCsvWithColonAsSeparator() {
'''Fruit:Count
Apple:5
Pear:10
Kiwi:200'''
}
def getCsvUsingDoubleQuoteAsQuoteChar() {
'''Typo,Desc
123,"text ,and more"'''
}
def getCsvUsingPercentageAsQuoteChar() {
'''Typo,Desc
1123,%bla, ha%'''
}
}
groovycsv-releases-1.0/test/com/xlson/groovycsv/ConfigurableColumnNamesSpec.groovy 0000664 0000000 0000000 00000004146 11717712403 0031011 0 ustar 00root root 0000000 0000000 package com.xlson.groovycsv
import spock.lang.Specification
import au.com.bytecode.opencsv.CSVReader
class ConfigurableColumnNamesSpec extends Specification {
def csvWithoutCoulmnNames = """field1,field2,field3,
Joe,Doe,18
Jane,Doe,24"""
def "Replaces existing column names with new ones"() {
setup:
def persons = new CsvParser().parse(csvWithoutCoulmnNames, columnNames: ['name', 'lastname', 'age'])
when:
def joe = persons.next()
then:
joe.name == 'Joe'
joe.lastname == 'Doe'
joe.age == '18'
}
def "Read all lines of csv content using custom column as column names"() {
setup:
def persons = new CsvParser().parse(csvWithoutCoulmnNames, readFirstLine: true, columnNames: ['name', 'lastname', 'age'])
when:
def names = persons*.name
then:
names == ['field1', 'Joe', 'Jane']
}
def "Parses columns from the first line by default"() {
setup:
def reader = Mock(CSVReader)
when:
def columnNames = new CsvParser().parseColumnNames([:], reader)
then:
reader.readNext() >> ['a', 'b', 'c']
columnNames == ['a', 'b', 'c']
}
def "Throws away the first line by default when using custom column names."() {
setup:
def reader = Mock(CSVReader)
when:
def customColumnNames = ['1', '2', '3']
def columnNames = new CsvParser().parseColumnNames([columnNames:customColumnNames], reader)
then:
1 * reader.readNext()
columnNames == customColumnNames
}
def "Does not read the first line as header when readFirstLine is specified."() {
setup:
def reader = Mock(CSVReader)
when:
def customColumnNames = ['1', '2', '3']
def columnNames = new CsvParser().parseColumnNames([columnNames:customColumnNames,
readFirstLine: true],
reader)
then:
0 * reader.readNext()
columnNames == customColumnNames
}
}
groovycsv-releases-1.0/test/com/xlson/groovycsv/CsvIteratorSpec.groovy 0000664 0000000 0000000 00000004507 11717712403 0026515 0 ustar 00root root 0000000 0000000 package com.xlson.groovycsv
import spock.lang.Specification
import au.com.bytecode.opencsv.CSVReader
class CsvIteratorSpec extends Specification {
def getCsvData() {
def csv = """a,b,c
1,2,3
4,5,6"""
def csvReader = new CSVReader(new StringReader(csv))
def columnNames = csvReader.readNext()
return [columnNames, csvReader]
}
def "CsvIterator iterates correctly over the CSVReader"() {
setup:
def (colNames, csvReader) = csvData
def iter = new CsvIterator(colNames, csvReader)
expect:
iter.hasNext()
iter.next().a == '1'
iter.hasNext()
iter.next().c == '6'
!iter.hasNext()
}
def "CsvIterator should close the underlying CSVReader instance when reaching the end of the file."() {
setup:
CSVReader csvReader = Mock(CSVReader)
def iter = new CsvIterator(["a", "b"], csvReader)
csvReader.readNext() >>> [["1","2"],["3","4"], null]
when:
iter.next()
then:
iter.hasNext()
!iter.isClosed()
0 * csvReader.close()
when:
iter.next()
iter.hasNext()
then:
iter.isClosed()
1 * csvReader.close()
}
def "CsvIterator isClosed after a full iteration."() {
setup:
def csvIterator = new CsvIterator(*csvData)
when:
csvIterator.each { }
then:
csvIterator.isClosed()
when:
csvIterator.next()
then:
thrown(IllegalStateException)
}
def "close can be called on the CsvIterator to close the connection to the reader."() {
setup:
def (colNames, csvReader) = csvData
def iter = new CsvIterator(colNames, csvReader)
when:
iter.next()
iter.close()
then:
iter.isClosed()
when:
iter.next()
then:
thrown(IllegalStateException)
}
def "CsvIterator.hasNext() returns false when the underlying reader instance is closed."() {
setup: 'Create an instance of CsvIterator consisting of 2 rows.'
def csvIterator = new CsvIterator(*csvData)
when: 'Iterates over the iterator until hasNext() is false'
csvIterator.each {}
then: 'hasNext() should return false.'
!csvIterator.hasNext()
}
}
groovycsv-releases-1.0/test/com/xlson/groovycsv/CsvParserSpec.groovy 0000664 0000000 0000000 00000014406 11717712403 0026157 0 ustar 00root root 0000000 0000000 package com.xlson.groovycsv
import spock.lang.*
import au.com.bytecode.opencsv.CSVReader
class CsvParserSpec extends Specification {
def getTestDataWithColumnNamesAnd3Rows() {
'''Name,Lastname,Age,Email
Mark,Hamilton,45,mark@hamilton.com
Bosse,Bildoktorn,50,bildoktorn@tv4.se
Peps,Persson,65,peps.persson@hotmail.com'''
}
def getTestDataWithColumnNamesAnd2Rows() {
'''Letter,Word,Number
a,paris,5
h,drink,60'''
}
def getCsvWithColonAsSeparator() {
'''Fruit:Count
Apple:5
Pear:10
Kiwi:200'''
}
def getTestDataWithQuotedComma() {
'''a,b
-,abc-,4
abc,-4-'''
}
def "Iterating over the parsed csv values are available by column name."() {
setup:
def data = new CsvParser().parse(getTestDataWithColumnNamesAnd3Rows())
expect:
data*."$columnName" == values
where:
columnName | values
"Name" | ['Mark', 'Bosse', "Peps"]
"Lastname" | ['Hamilton', 'Bildoktorn', 'Persson']
'Age' | ['45', '50', '65']
"Email" | ['mark@hamilton.com', 'bildoktorn@tv4.se', 'peps.persson@hotmail.com']
}
def "Functional collection methods are available on parsed object."() {
setup:
def data = new CsvParser().parse(getTestDataWithColumnNamesAnd3Rows())
expect:
data.findAll { (it.Age as int) > 46 }.size() == 2
}
def "PropertyMapper has a toString() that returns all the data in it's columns."() {
setup:
def pm = new PropertyMapper(values: values, columns: columns)
expect:
pm.toString() == toStringRepresentation
where:
columns | values | toStringRepresentation
['a': 0, 'b': 1, 'c': 2] | ['1', '2', '3'] | "a: 1, b: 2, c: 3"
['Name': 0, 'Age': 1] | ['Mark', '56'] | "Name: Mark, Age: 56"
}
def "readAll should never be called on the CSVReader instance used to parse the csv."() {
setup:
CSVReader csvReader = Mock(CSVReader)
def partiallyMockedCsvParser = new CsvParser()
partiallyMockedCsvParser.metaClass.createCSVReader = { Reader reader ->
csvReader
}
when: "csv is parsed and looped through"
def data = partiallyMockedCsvParser.parse(getTestDataWithColumnNamesAnd2Rows())
for(d in data) {}
then: "readAll() should not be called."
0 * csvReader.readAll()
}
def "Parse supports a custom separator."() {
setup:
def data = new CsvParser().parse(csvWithColonAsSeparator, separator: ':')
expect:
data*."$columnName" == values
where:
columnName | values
"Fruit" | ['Apple', 'Pear', 'Kiwi']
"Count" | ["5", "10", "200"]
}
def getCsvUsingDoubleQuoteAsQuoteChar() {
'''Typo,Desc
123,"text ,and more"'''
}
def getCsvUsingPercentageAsQuoteChar() {
'''Typo,Desc
1123,%bla, ha%'''
}
def "Parse supports custom quote character."() {
when:
def csv = new CsvParser().parse(csvData, quoteChar: quoteChar)
then:
csv*."$columnName" == values
where:
csvData | quoteChar | values | columnName
csvUsingDoubleQuoteAsQuoteChar | '"' | ['text ,and more'] | "Desc"
csvUsingPercentageAsQuoteChar | "%" | ['bla, ha'] | "Desc"
}
def "Parse supports custom escape char."() {
setup:
def csvData = '''Test,It
1,"this is \"a quote\""'''
def csv = new CsvParser().parse(csvData, escapeChar: "\\")
expect:
csv*.It == ['this is "a quote"']
}
def "Parse supports java.io.Reader as input."() {
when:
def csv = new CsvParser().parse(new StringReader(testDataWithColumnNamesAnd2Rows))
then:
csv*.Number == ['5', '60']
}
def "CsvParser should auto detect separator and quote character"() {
when: "a CSV file is parsed with auto detection"
def csv = new CsvParser().parse(autoDetect: true, csvData)
then: "it should return the correct columns"
csv*."$property" == values
where:
csvData | property | values
testDataWithColumnNamesAnd3Rows | "Age" | ["45", "50", "65"]
csvWithColonAsSeparator | "Count" | ["5", "10", "200"]
csvUsingDoubleQuoteAsQuoteChar | "Desc" | ["text ,and more"]
csvUsingDoubleQuoteAsQuoteChar | "Typo" | ["123"]
testDataWithColumnNamesAnd2Rows | "Word" | ["paris", "drink"]
testDataWithColumnNamesAnd3Rows | "Email" | ["mark@hamilton.com", "bildoktorn@tv4.se", "peps.persson@hotmail.com"]
}
def "should allow to override auto detection"() {
when: "autoDetect is active and a separator is provided"
def csv = new CsvParser().parse(autoDetect: true, separator: ',', csvWithColonAsSeparator)
then: "the separator provided is used"
csv*."Fruit:Count" == ["Apple:5", "Pear:10", "Kiwi:200"]
}
def "The separator should be allowed in the csv data if its quoted"() {
when:
def csv = new CsvParser().parse(quoteChar:'-', testDataWithQuotedComma)
then:
csv*.a == [',abc','abc']
}
def "Values in the csv can be obtained by using the index of the column."() {
when:
def csv = new CsvParser().parse(testDataWithColumnNamesAnd2Rows)
def line = csv.next()
then:
line[0] == 'a'
line[1] == 'paris'
line[2] == '5'
}
def csvWithoutHeaders = 'Joe,Doe,19'
def "Parsing csv without headers using the position of the values."() {
when:
def csv = new CsvParser().parse(readFirstLine: true, csvWithoutHeaders)
def line = csv.next()
then:
line[0] == 'Joe'
line[1] == 'Doe'
line[2] == '19'
}
def "CsvParser.parseCsv can be used statically."() {
when:
def csv = CsvParser.parseCsv(csvData)
then:
csv*.Letter == letterValues
where:
csvData | letterValues
testDataWithColumnNamesAnd2Rows | ['a', 'h']
new StringReader(testDataWithColumnNamesAnd2Rows) | ['a', 'h']
}
}