Groovy offers rich dynamic capabilities via its MetaClass support. In this blog post, I will take advantage of this feature to have a method called
getZodiakTropicalSign()
injected into the SDK-provided Calendar
. The purpose of this method is to provide the applicable Zodiak sign for a given instance of Calendar
.The portion of this script most relevant to this post appears at the top of the script. The syntax
Calendar.metaClass.getZodiakTropicalSign = { ->
defines a new method getZodiakTrpopicalSign
on Calendar
and then uses delegate
to work with the underlying instance of java.util.Calendar.
#!/usr/bin/env groovy
Calendar.metaClass.getZodiakTropicalSign = { ->
def humanMonth = delegate.get(Calendar.MONTH) + 1
def day = delegate.get(Calendar.DATE)
def zodiakTropicalSign = "Unknown"
switch (humanMonth)
{
case 1 :
zodiakTropicalSign = day < 20 ? "Capricorn" : "Aquarius"
break
case 2 :
zodiakTropicalSign = day < 19 ? "Aquarius" : "Pisces"
break
case 3 :
zodiakTropicalSign = day < 21 ? "Pisces" : "Aries"
break
case 4 :
zodiakTropicalSign = day < 20 ? "Aries" : "Taurus"
break
case 5 :
zodiakTropicalSign = day < 21 ? "Taurus" : "Gemini"
break
case 6 :
zodiakTropicalSign = day < 21 ? "Gemini" : "Cancer"
break
case 7 :
zodiakTropicalSign = day < 23 ? "Cancer" : "Leo"
break
case 8 :
zodiakTropicalSign = day < 23 ? "Leo" : "Virgo"
break
case 9 :
zodiakTropicalSign = day < 23 ? "Virgo" : "Libra"
break
case 10 :
zodiakTropicalSign = day < 23 ? "Libra" : "Scorpio"
break
case 11 :
zodiakTropicalSign = day < 22 ? "Scorpio" : "Sagittarius"
break
case 12 :
zodiakTropicalSign = day < 22 ? "Sagittarius" : "Capricorn"
break
}
return zodiakTropicalSign
}
def calendar = Calendar.instance
// First argument to script is expected to be month integer between 1 (January)
// and 12 (December). Second argument is expected to be the date of that month.
// If fewer than two arguments are provided, will use today's date (default) instead.
if (args.length > 1)
{
try
{
calendar.set(Calendar.MONTH, (args[0] as Integer) - 1)
calendar.set(Calendar.DATE, args[1] as Integer)
}
catch (NumberFormatException nfe)
{
println "Arguments ${args[0]} and ${args[1]} are not valid respective month and date integers."
println "Using today's date (${calendar.get(Calendar.MONTH)+1}/${calendar.get(Calendar.DATE)}) instead."
}
}
print "A person born on ${calendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.US)}"
println " ${calendar.get(Calendar.DATE)} has the Zodiak sign ${calendar.getZodiakTropicalSign()}"
The final line of the above script calls the injected
getZodiakTropicalSign()
method on Calendar. This is demonstrated in the next screen snapshot.The first execution of the script in the above screen snapshot is executed without parameters and so it prints out the Zodiak Sign for today (23 January). The remainder of the script runs are for different dates. This script could have been made more user-friendly using Groovy's built-in CLI support, but the focus here is on the dynamically injected method.
Conclusion
Groovy allows the developer to inject methods on instances of existing classes even when the developer does not own or have control over the existing class. This can be a powerful capability to bending an existing class to one's will.
No comments:
Post a Comment