-
Notifications
You must be signed in to change notification settings - Fork 42
Chapter 2 comments
Comments on chapter 2, Grails In Action, MEAP version posted 12/31/2008:
========
page 25 – “grails shell” only works if you are already in a grails project. Should note this.
========
page 30 – In section on Strings, /assert greeting == “The result of 2 + 2 is: 4”/ should be /assert output == “The result of 2 + 2 is: 4”/
========
page 30 – In section on Strings, consider presenting slashy strings, i.e., strings delimited with /. I know you discuss them later in the section on regex, but a brief mention seems appropriate here.
========
page 31 – Retested with Grails 1.1-beta2, works fine, so ignore this comment, sorry.
In section on the “as” keyword, /“34749397” as int/ fails in both the grails console and shell. I am running Grails 1.0.4
Cryptonomicon:rockstar joemctee$ grails shellWelcome to Grails 1.0.4 – http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /opt/grailsBase Directory: /Users/joemctee/Projects/grina/rockstar
Note: No plugin scripts found
Running script /opt/grails/scripts/Shell.groovy
Environment set to development
[copy] Copying 1 file to /Users/joemctee/.grails/1.0.4/projects/rockstar
0 spring.GrailsWebApplicationContext Refreshing org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext\914745: display name [org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext\914745]; startup date [Sun Jan 04 10:25:14 MST 2009]; root of context hierarchy
0 spring.GrailsWebApplicationContext Bean factory for application context [org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext\914745]: org.springframework.beans.factory.support.DefaultListableBeanFactory\c0ce8f
[copy] Copying 1 file to /Users/joemctee/.grails/1.0.4/projects/rockstar
2867 spring.GrailsWebApplicationContext Refreshing org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext\de71: display name [org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext\de71]; startup date [Sun Jan 04 10:25:17 MST 2009]; parent: org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext\914745 [2867] spring.GrailsWebApplicationContext Bean factory for application context [org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext\de71]: org.springframework.beans.factory.support.DefaultListableBeanFactory\@debc06
Groovy Shell (1.5.6, JVM: 1.5.0_13-119)
Type ‘help’ or ‘\h’ for help.
-——————————————————————————————————————————————————————————————————
groovy:000> “34749397” as int
ERROR org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object ‘34749397’ with class ‘java.lang.String’ to class ‘java.lang.Integer’
at groovysh_evaluate.run (groovysh_evaluate:1)
…
groovy:000> exit
org.codehaus.groovy.tools.shell.Groovysh
This appears to work fine in Groovy:
Cryptonomicon:~ joemctee$ groovyversion——————————————————————————————————————-
Groovy Version: 1.6-RC-1 JVM: 1.5.0_13
Cryptonomicon:~ joemctee$ groovysh
Groovy Shell (1.6-RC-1, JVM: 1.5.0_13)
Type ‘help’ or ‘\h’ for help.
-
groovy:000> “34749397” as int
===> 34749397
groovy:000> exit
So the issue must be a bug in the version of groovy (1.5.6?) used by the latest version of grails? Not sure how to handle issues like this, since the information you have presented is correct. BTW, I tested in grovy 1.5.7 and it worked fine. Don’t have a copy of 1.5.6, so couldn’t test that.
========
page 32 – Consider reformatting the listing for lists and maps as follows:
// Java-style list
List myList = new ArrayList()
myList.add(“apple”)
myList.add(“orange”)
myList.add(“lemon”)// Java-style map
Map myMap = new HashMap()
myMap.put(3, “three”)
myMap.put(6, “six”)
myMap.put(2, “two”)// Groovy-style list and map
List myGroovyList = [ “apple”, “orange”, “lemon” ]
Map myGroovyMap = [ 3: “three”, 6: “six”, 2: “two” ]// Groovy-style empty list and map
List l = []
Map m = [:]
This makes it easier to copy and paste code into the console for testing and playing.
Peter: Sorry, I don’t think we can do this :( Manning do code listings with annotations, not inline comments. I will raise this with our development editor, but since the final result is a book, I suspect there won’t be much traction. I guess this is partly why we have example source code.
========
page 32-33 – Consider similar change for next code listing:
List numbers = [ 5, 10, 15, 20, 25 ] // Access item via index, starting from beginning of list (zero-based) assert numbers[0] == 5 assert numbers[3] == 20 // Access item via index, starting from end of list (-1 is last item in list) assert numbers[-1] == 25 assert numbers[-3] == 15 // Replace item in list via index numbers[2] = 3 assert numbers[2] == 3 // Add item to end of list using "left-shift" operator numbers << 30 assert numbers[5] == 30 Map items = [ "one": "apple", "two": "orange", "three": "pear", "four": "cherry" ] // Access value in map referenced by key assert items["two"] == "orange" assert items["four"] == "cherry" // Replace value in map referenced by key items["one"] = "banana" assert items["one"] == "banana" // Add value to map and reference using key items["five"] = "grape" assert items["five"] == "grape"
========
General – A lot of folks will be using the PDF version of your book. The ability to copy and paste code from the PDF is one of the most appealing features (that and not having to lug books to/from work, flash drives are light!). Consider making it easy to copy/paste all code listings in the book such that they can be tested and run from the console with no editing.
========
page 33 – In second part of code example,
for (int i in 0..<fruit.size()) {
should be
for (int i in 0..><subList.size()) {
========
page 36 – I am getting a few errors with this example:
Running in the console, I get a complaint about the use of Matcher:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, Script16: 3: unable to resolve class Matcher
@ line 3, column 13.Script16: 5: unable to resolve class Matcher
@ line 5, column 9.Script16: 6: unable to resolve class Matcher
@ line 6, column 29.Script16: 8: unable to resolve class Matcher
@ line 8, column 32.Script16: 8: unable to resolve class Matcher
@ line 8, column 55.Script16: 9: unable to resolve class Matcher
@ line 9, column 31.
6 errors
Adding “import java.util.regex.Matcher” fixes this, but an even groovier solution is to dynamically type m: "def m = str =~ /\b(\w*)ain(\w*)\b/ "
I had to add a call to main() to see the output, but when I did, I received a stack overflow exception. Not sure why. The fix was to name the method something other than main. I suspect groovy is doing some magic behind the scenes for the special method name main?
So here is what worked for me:
static void testMatcher() {
String str = “The rain in Spain falls mainly on the plain”
def m = str =~ /\b(\w*)ain(\w*)\b/ if (m) { for (int i = 0; i >< m.count; i++) { println “Found: ‘${m0}’ – prefix: ‘${m1}’” + “, suffix: ‘${m2}’” } }}
testMatcher()
========
page 37 – In section 2.3.3 Property notation, this would be a good place to add an aside that describes a trick for getting around the need for parens in no arg methods. For example, if you have a method, calculateDuration() that takes no arguments, you can refactor the name to getCalculateDuration() and make it private. Users of the method can now call .calculateDuration without the parens. It is a kluge, but makes using some groovy libraries (such as DSLs) a lot more intuitive to use.
P. 26 section 2.1.2 change “compared to Java.Fewer imports”P. 29 section heading for 2.2.1 is not formatted correctlyP. 30 top paragraph “numbers.Numbers”P. 32 formatting of section heading 2.2.2
Peter: I think these come from OpenOffice change tracking, possibly with the addition of switching between OpenOffice and Word. Thanks for picking them up.
section 2.1.1, page 25 – ‘The Grails console. started with the “grails console” command…’ – this is the Groovy console, not the Grails console. the screenshot on page 26 (see the console’s title bar) backs me up on this.
Peter: True, but it’s not a “plain” old Groovy shell/console because it allows you to play with your domain classes and stuff.
section 2.1.2, page 26 – typesetting issue? The phrase “Fewer imports” butts up against a sentence, looks like it wants to be a header
section 2.1.2, page 28 – “Public” is the default scope – section 2.2.3 says that, for properties, the default scope is private, with
automagic getters and setters.
section 2.1.3, page 29 – the spaceship operator. you never say what this operator returns. later on (section 2.4.2, page 41) you say
that it returns a number less than zero, zero, or greater than zero, but that’s still fuzzy. does it return [-1, 0, 1]?
Peter: There are no guarantees as to the value, so no, not [-1, 0, 1]. I’ve tried to clarify that the value doesn’t matter, just the “sign”.
section 2.2.1, page 29 – the header is mis-typeset, page 30 a header “Numbers” is also done wrong.
section 2.2.1(?), page 33 – maps. y’all don’t mention the other way to reference map values, e.g.
items.five = “grape”
assert items.five == “grape”
section 2.2.1, page 33, listing 2.3 – the second loop should iterate over subList.size(), not fruit.size()
section 2.3.2, page 35-37 -
Literals – you give an example of how to use a java.util.regex.Pattern, but not the groovy slash-based regex in the paragraph
above. and it’s not really clear what that would look like in code.
Matching – the last parg is very confusing. you say ==~ matches the whole string, then ask how to match part of the string. isn’t
that what the =~ in the first parg does?
Groups – this section is complicated and long, and i kind of wonder if it is worthy of the space you give it. i used to hack perl
alot and i used groups occasionally, but not in most stuff. does grails use them alot?
Peter: I almost invariably use groups in my regular expressions. I guess it depends on what you use them for. The main point though is to explain the syntax, which is pretty opaque. Using the right numbers for the indices is also tricky.
section 2.3.3, page 37
Defining properties – you should mention that adding “final” to a property (as in “final String constant” in your example) makes
it read-only
section 2.3.4, page 38
i had real trouble in groovy with “internal” enums. i think that these fall under the inner class restrictions, but you could
mention enums as well
Peter: inner enums do work, although it seems you have to fully-qualify them, even when referring to them from the host class.
section 2.5, page 43 – the Collection.find(closure) bit. this sentence is ambiguous:
“More specifically, it returns the first element for which the given closure returns true, or null if there is no such element.”
The comma helps, but you do a much better job with findAll(), same section. you make it two sentences.
section 2.6, page 44 – “It can be used for a variety of purposes: writing scripts; as an embedded…” the semicolons should be commas, and the phrase “build tools” doesn’t fit – maybe “to build
tools”?
lastly, there’s something i see in groovy that baffles me that maybe y’all could explain. groovy seems to let you create strings for
maps and constructors without using quotes. an example is the SimpleDateFormat example on page 37. things like ‘lenient: false’ get
parsed to a Map where the key is the string “lenient”. it just throws me for a second when i see it. i expect anything not a
reserved word and not in quotes to be a variable reference, and this isn’t
Chapter 2 – The Groovy Essentials
1 – For some reason, I couldn’t open this chapter in Pages, but was able to do it with NeoOffice.
3 – Since you indicate the book is based on Grails 1.1, you should probably go back and correct the initial “grails version” example in chapter 1 to match this, and it would probably also be good to tell the reader right up front which version of Grails and Groovy to download.
p. 6 – “Fewer imports” should be a heading.