GCommons
From Evgeny Goldin
Contents |
Introduction
GCommons is a general-usage library similar to Apache Commons. It extracts general reusable pieces from other projects and provides them in a simple and intuitive way for anyone. All my Maven plugins rely heavily on its abilities, especially "copy-maven-plugin" for its copying and archiving operations and "assert-maven-plugin" when it compares directories and evaluates Groovy expressions.
GCommons is covered in GroovyMag March 2011.
Details
| Provided By | ||
|---|---|---|
| Mailing List | Nabble | |
| Source Code | GitHub | |
| Tests | GitHub | |
| GroovyDoc | Gradle Groovydoc | |
| Issue Tracker | YouTrack |
|
| Build Server | Gradle TeamCity | |
| Maven Coordinates | com.github.goldin:gcommons:0.5.4
| |
| Maven Repositories | Artifactory Online |
What's New
v0.5.4, May 10, 2012
| Issue Id | Type | Summary | GroovyDoc |
|---|---|---|---|
| gc-115 | Feature | FileBean.pack() - allow to set compression level when using Ant | FileBean.pack()
|
| gc-112 | Feature | FileBean.pack() - add "overwrite" option | FileBean.pack()
|
| gc-73 | Task | Switch to Guice | |
| gc-114 | Feature | FileBean.baseName() - retrieve file base name (file.name minus ".$extension") | FileBean.baseName()
|
| gc-103 | Bug | NullPointerException in GeneralBean.array() | |
| gc-111 | Exception | GeneralBean$array.call fails on Java7 |
v0.5.3.5, November 12, 2011
| Issue Id | Type | Summary | GroovyDoc |
|---|---|---|---|
| gc-102 | Bug | FileBean.copy() doesn't preserve origin's lastModified | FileBean.copy()
|
| gc-100 | Bug | FileBean.extension() returns extension lower-cased | FileBean.extension()
|
| gc-104 | Bug | FileBean.files() fails when directory specified doesn't exist even if "failIfNotFound" is "false" | FileBean.files()
|
| gc-105 | Bug | GeneralBean.executeWithResult() occasionally returns empty String | GeneralBean.executeWithResult()
|
| gc-98 | Feature | FileBean.extension() - return empty String if file has no extension | FileBean.extension()
|
| gc-99 | Feature | FileBean.recurse() - return list of files iterated and passed to the closure callback | FileBean.recurse()
|
| gc-101 | Feature | FileBean.unpackZipEntries() - accept new parameter: zip entries to exclude | FileBean.unpackZipEntries()
|
| gc-75 | Task | Eliminate CodeNarc violations | |
| gc-45 | Task | FileBean.recurse() - make sure no values are left in configuration Map after it is read |
v0.5.3.4, October 17, 2011
| Issue Id | Type | Summary | GroovyDoc |
|---|---|---|---|
| gc-86 | Bug | Ant scanner fix - set basedir with canonical path | |
| gc-78 | Bug | Duplicate log messages | |
| gc-77 | Feature | FileBean.pack() - add "fullpath" and "prefix" options | FileBean.pack()
|
| gc-88 | Feature | FileBean.pack() - support "fullpath", "prefix" for all archives (zip/tar/tar.gz) and "filemode" for tar/tar.gz | FileBean.pack()
|
| gc-93 | Feature | FileBean.pack() - support "filemode" specified as part of include pattern | FileBean.pack()
|
| gc-85 | Feature | FileBean.pack() - allow to optionally use TrueZip when packing archives | FileBean.pack()
|
| gc-94 | Feature | VerifyBean.equal() - use combination "directory/pattern" to match files | VerifyBean.equal()
|
| gc-95 | Feature | VerifyBean.equal() - provide an option whether or not to fail if no files were found | VerifyBean.equal()
|
| gc-87 | Feature | GeneralBean.executeWithResult() returning String (stdout + stderr) | GeneralBean.executeWithResult()
|
| gc-90 | Feature | FileBean.copyDir() - copy directory recursively | FileBean.copyDir()
|
| gc-84 | Feature | FileBean.unpack() - allow to optionally use TrueZip when unpacking archives | FileBean.unpack()
|
| gc-89 | Feature | Treat "sar" extension as zip archive | |
| gc-40 | Feature | FileBean.checksum() - add checksum support | FileBean.checksum()
|
| gc-67 | Usability Problem | Do not impose logging backend |
v0.5.3, May 15, 2011
| Issue # | Type | Summary | GroovyDoc |
|---|---|---|---|
| gc-58 | Feature | Switch to Groovy 1.8.0 | |
| gc-57 | Feature | Add full FTP path to FTPFile when listing files natively | |
| gc-66 | Bug | After unpacking zip entry of <dependency> without <dependenciesAtM2> - it can't be deleted from a temp folder | |
| gc-47 | Feature | VerifyBean.isInstance(Object, Class) | VerifyBean.isInstance(Object, Class)
|
| gc-56 | Feature | AlgorithmsBean - various sort and search implementations
| AlgorithmsBean
|
| gc-60 | Feature | IOBean.resource(), IOBean.resourceText() - convenient retrieval of classpath resources
| IOBean
|
| gc-70 | Feature | LoggerOutputStream - OutputStream implementation sending all output to SLF4J Logger
| LoggerOutputStream
|
v0.5.2, March 09, 2011
| Issue # | Type | Summary | GroovyDoc |
|---|---|---|---|
| gc-27 | Bug | NoSuchMethodError running svnOp.groovy | |
| gc-53 | Feature | Switch to Groovy "1.8-rc-2" |
v0.5.1, February 25, 2011
| Issue # | Type | Summary | GroovyDoc |
|---|---|---|---|
| gc-28 | Feature | FileBean.copy() - provide third optional argument: a file name
| FileBean.copy()
|
| gc-29 | Feature | VerifyBean.equal() - make sure identical directories are of the same size
| VerifyBean.equal()
|
| gc-33 | Feature | Return ConfigurableApplicationContext from GCommons instead of ApplicationContext
| GCommons.context()
|
| gc-34 | Feature | Add GeneralBean.execute()
| GeneralBean.execute()
|
Retrieving
Gradle
repositories { maven { url 'http://evgenyg.artifactoryonline.com/evgenyg/repo/' }} dependencies { compile 'com.github.goldin:gcommons:0.5.4' }
@Grab
@GrabResolver( name='com.github.goldin', root='http://evgenyg.artifactoryonline.com/evgenyg/repo/' ) @Grab('com.github.goldin:gcommons:0.5.4') @GrabExclude('xml-apis:xml-apis') import com.github.goldin.gcommons.GCommons
- Example of a script using
GCommonswith@Grab. - When run for the first time it may take some time to download all library dependencies.
Maven
<repositories> <repository> <id>gcommons-repo</id> <url>http://evgenyg.artifactoryonline.com/evgenyg/repo/</url> <releases><enabled>true</enabled></releases> <snapshots><enabled>false</enabled></snapshots> </repository> </repositories> <dependency> <groupId>com.github.goldin</groupId> <artifactId>gcommons</artifactId> <version>0.5.4</version> <scope>compile</scope> </dependency>
Usage
Other general libraries usually provide classes with static methods. GCommons is different, it supplies its functionality through a number of Spring beans, retrieved from com.github.goldin.gcommons.GCommons entry point.
import com.github.goldin.gcommons.GCommons /** * Retrieving Spring context */ ApplicationContext context = GCommons.context() /** * Retrieving verification bean */ GCommons.verify().file( sourceFile ) GCommons.verify().notNullOrEmpty( data ).splitWith( 'eachLine', String )*.trim().findAll{ it } Class.getResourceAsStream( GCommons.verify().notNullOrEmpty( classPath )) /** * Retrieving file bean */ File tempDirectory = GCommons.file().tempDirectory() List<File> files = GCommons.file().files( sourceDirectory, [ '**/*.groovy' ], [ '**/*-Test.groovy'] ) GCommons.file().delete( sourceDirectory ) GCommons.file().unpack( archiveFile, targetDirectory ) GCommons.file().pack ( sourceDirectory, archiveFile, [ '**/*.xml', '**/*.properties' ] )
Spring Beans
| Bean | Retrieved as | Summary |
|---|---|---|
ConstantsBean
| GCommons.constants()
| Constant values:
|
GeneralBean
| GCommons.general()
| General methods for:
|
VerifyBean
| GCommons.verify()
| Verification methods for:
|
FileBean
| GCommons.file()
| File methods for:
|
IOBean
| GCommons.io()
| I/O methods for:
|
NetBean
| GCommons.net()
| Networking methods for:
|
GroovyBean
| GCommons.groovy()
| Groovy-related methods for:
|
MOP Updates
GCommons adds new methods to traditional JDK classes.
| Class.method | Summary | Also available as | Example | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
File.recurse
| File.eachFileRecurse on steroids! Provides the following improvements over traditional recursive iteration:
Arguments:
Returns:
| GCommons.file().recurse()
|
long directorySize = 0 new File( directory ).recurse([ type : FileType.FILES, detectLoops : true ]){ directorySize += it.size() } assert dir.splitWith( 'recurse' ) == dir.splitWith( 'eachFileRecurse' ) new File( directory ).recurse { println "[$it]" } | ||||||||||||||||||||||||||||
Object.splitWith
| Splits object provided to "pieces" using one of its iteration methods, like String.eachLine or File.eachFile.
Arguments:
Returns:
| GCommons.general().splitWith()
|
" ... ".splitWith( 'eachLine' )*.trim().findAll{ it } " ... ".splitWith( 'eachLine', String )*.trim().findAll{ it } assert dir.splitWith( 'recurse' ) == dir.splitWith( 'eachFileRecurse' ) new File( .. ).splitWith( 'eachLine' )*.trim().findAll{ it } new File( .. ).splitWith( 'eachFile', File ).findAll{ it.size() > 10240 } | ||||||||||||||||||||||||||||
File.directorySize
| Calculates directory size. Runs recurse() with loop-detection enabled.
Arguments:
Returns:
| GCommons.file().directorySize()
|
def size = new File( .. ).directorySize() |
Principles
This library follows a number of principals which I find very useful:
- It always tries to operate on varargs arguments so a caller can provide any number of parameters to validate or files to delete:
GCommons.verify().file( sourceFile, anotherFile, thirdFile ) GCommons.verify().notNull( argument1, argument2 ) GCommons.verify().notNullOrEmpty( data, " ... ", anotherString ) GCommons.file().mkdirs( dir1, dir2, dir3 ) GCommons.general().choose( object, anotherObject, thirdObject, defaultValue ) GCommons.io().close( stream, anotherStream, thirdStream )
Right now varargs arguments are not shown by GroovyDoc, an issue was created.
- It does not return
voidif any meaningful information can be returned instead. Therefore, all validation methods, for example, return first value validated allowing to reuse it in following chain calls. Likewise, file operations returnFilethat was deleted or created.
def size = GCommons.verify().notNullOrEmpty( " .. " ).size() def parent = GCommons.verify().file( someFile ).parentFile GCommons.file().mkdirs( directory ).recurse { ... } def dir = fileBean.mkdirs( fileBean.delete( dir ).parentFile )
