Showing posts with label Grails Crowd. Show all posts
Showing posts with label Grails Crowd. Show all posts

Monday, August 18, 2008

Grails Crowd has launched

After working on this project on and off for around 9 months (funny coincidence with pregnancy time frame :-) [life took precedence], I was finally able to finish and launch Grails Crowd - "the friendly online community (or directory) for Grails developers Worldwide".

I will most likely open source the code and let the community drive the innovation and the future direction of the site. I have pretty much decided that the home of the code will be GitHub :-)

Later...

Friday, July 18, 2008

Getting closer

As I'm getting closer to finishing up the essential code for GrailsCrowd, I noticed that I'm doing on the fly refactorings more seamlessly than I was able to do when I first started hacking with Groovy/Grails. And Groovy Closures are my friends these days :-)

Here's a small example from the GrailsCrowd code base - 2 simple controller actions to query for Grails projects by tags, only with the difference that the first action gets all the projects within a system for a specified tag (globally) and the other one gets projects for a tag for a specific member. Both actions operate on the Tag instance, so I refactored the common functionality of querying for Tags into a method which takes a closure:


class GrailsProjectController {

...
private def withTag(callable) {
if (!params.selectedTag) {
redirect(uri: '/notAllowed')
}
def tag = Tag.findByName(params.selectedTag)
callable(tag)
}
...
}


And then the above mentioned actions became:


class GrailsProjectController {

...
def findByTagGlobally = {
def total = 0
def projects = []
withTag {tag ->
if (tag) {
total = Tagging.countByTag(tag)
//Using CrieteriaBuilder here, so we could query by 'taggings' association
projects = GrailsProject.createCriteria().list(params) {
taggings {
eq('tag', tag)
}
} //Criteria builder
//Sort by name since GrailsProject implements Comparable and the name property is its natural order
projects.sort()

} //if
} //Closure
render(view: 'list', model: [projects: projects, navMenu: 'discoverNavigationByTag',
paginatingController: controllerName, paginatingAction: actionName, total: total,
menuContext: [tag: params.selectedTag]])
}

def findByTagForMember = {
def total = 0
def projects = []
def member = Member.findByName(params._name)
withTag {tag ->
if (tag) {
if (!member) {
redirect(uri: '/notAllowed')
}
total = Tagging.countByTagAndMember(tag, member)
//Using CrieteriaBuilder here, so we could query by 'taggings' association
projects = GrailsProject.createCriteria().list(params) {
taggings {
eq('tag', tag)
eq('member', member)
}
} //Criteria builder
//Sort by name since GrailsProject implements Comparable and the name property is its natural order
projects.sort()
} //if
} //Closure
render(view: 'list', model: [projects: projects, navMenu: 'memberProjectsNavigationByTag',
paginatingController: controllerName, paginatingAction: actionName, total: total,
menuContext: [tag: params.selectedTag, member: member]])
}
...
}


Also notice the use of GORM CriteriaBuilder which allowed to nicely query m:n 'Tagging' association class!

Keep Groovying.

Later...

Saturday, June 7, 2008

Programming with closures

Recently I caught myself thinking that my programming habits are changing while programming in Groovy. In particular, I started using closures more and more to clean up my code, make it more DRYer, e.g. by not just merely using existing closures provided by libraries such as GDK, GORM, etc., but by creating my own closures.

Here's a small example from GrailsCrowd. The idea here is to either 'accept project participation invitation' or 'reject project participation invitation'. So, in the Controller, I factored out the common code of retrieving the Member, Project, redirecting to the appropriate action afterwards, etc. to a private method which takes a closure, and calling that closure for the actual action of 'acceptance' or 'rejection':


private def withProject(callable) {
def invitee = freshCurrentlyLoggedInMember()
def creator = Member.findByName(params.creator)
def project = GrailsProject.get(params.projectId)
//Call the closure
callable([project:project,creator:creator,invitee:invitee])
redirect(controller: 'mailbox')
}

def acceptParticipationInvitation = {
withProject {projectMap ->
projectMap.project.acknowlegeParticipationAcceptance(projectMap.creator,
projectMap.invitee, params.messageId.toLong())
}
}

def rejectParticipationInvitation = {
withProject {projectMap ->
projectMap.project.rejectParticipationInvitation(projectMap.creator,
projectMap.invitee, params.messageId.toLong())
}
}


IMO, this makes code cleaner, reusable, and more maintainable. Also, this style of programming with closures kind of replaces good old Template Method design pattern.

Keep on Groovying, folks!

Later...

Friday, April 4, 2008

So enjoyable

While hacking GrailsCrowd today, I caught myself thinking that programming in Groovy is such an enjoyable experience (for me). Take this method for example:


// Social feature: gets a list of 'colleagues' working on the same projects as *this* member
def getProjectColleagues() {
getActiveProjects().collect
{it.participants}.flatten().findAll
{it.participant.id != this.id}.collect {it.participant}
}
Is it possible to navigate "deep" object graph and express the same intent with the similar compactness in 'raw' Java code? I think not :-)

Later...

Saturday, December 15, 2007

Fetch random GORM model

Despite busy schedule at work and a year old daughter at home, who now requires constant attention, I was able to get some time to work on the Grails community site (Grails Crowd).

As a part of it, I wanted to have a feature to display a 'random' user (a 'member') In fact, keep displaying a random user as long as 'Discover users' link is being clicked. You know, kind of like Flickr's "Explore" feature. So with a help of standard JDK library features i.e. 'java.utils.Collections.shuffle()' and Groovy closures, here's what I've come up with:

MemberController's action:


...

def findRandom = {
def member = null

withMemberIds { memberIds ->
//Pick the last one
member = Member.get(memberIds[-1])
//Then remove it from the list
memberIds.pop()
}

if(member) {
render(view: 'discover', model: [member: member])
}
else {
//No one is registered yet - just 'go home'
redirect(uri:'/')
}
}

private def withMemberIds(closure) {
def memberIds = session.memberIds
if (!memberIds) {
memberIds = Member.withCriteria {
projections {
property('id')
}
}
if (!memberIds.isEmpty()) {
//Some members are in the database:
//Shuffle 'em up
Collections.shuffle(memberIds)
session.memberIds = memberIds
}
else {
//No members are in the database
return
}
}
closure(memberIds)
if (memberIds.isEmpty()) {
session.memberIds == null
}
}

...



It works like a charm.

Later...