Showing preview only (840K chars total). Download the full file or copy to clipboard to get everything.
Repository: Dierk/GroovyInAction
Branch: master
Commit: 7affde058fa9
Files: 719
Total size: 676.3 KB
Directory structure:
gitextract_qrfoz67k/
├── .idea/
│ └── vcs.xml
├── LICENSE
├── README.md
├── alltests.groovy
├── listings/
│ ├── allsources.txt
│ ├── appD/
│ │ ├── Listing_D_01_GStrings.groovy
│ │ ├── Listing_D_02_Lists.groovy
│ │ ├── Listing_D_03_Closures.groovy
│ │ ├── Listing_D_04_Regex.groovy
│ │ └── Listing_D_05_GPath.groovy
│ ├── chap01/
│ │ ├── Listing_01_01_Gold.groovy
│ │ ├── customers.xml
│ │ ├── data.txt
│ │ ├── groovysh.txt
│ │ ├── snippet0101_customers.groovy
│ │ ├── snippet0101_fileLineNumbers.groovy
│ │ ├── snippet0101_newDates.txt
│ │ ├── snippet0101_printPackageNames.groovy
│ │ ├── snippet0101_printPackageNamesGpath.groovy
│ │ ├── snippet0102_printGroovyWebSiteCount.groovy
│ │ └── snippet0103_googleIpAdr.groovy
│ ├── chap02/
│ │ ├── Book.groovy
│ │ ├── Listing_02_01_Assertions.groovy
│ │ ├── Listing_02_02_Book.txt
│ │ ├── Listing_02_03_BookScript.groovy
│ │ ├── Listing_02_04_BookBean.groovy
│ │ ├── Listing_02_05_ImmutableBook.groovy
│ │ ├── Listing_02_06_Grab.groovy
│ │ ├── Listing_02_07_Clinks.groovy
│ │ ├── Listing_02_08_ControlStructures.groovy
│ │ ├── snippet0201_comments.groovy
│ │ ├── snippet0202_failing_assert.groovy
│ │ ├── snippet0202_failing_assertion_error.txt
│ │ ├── snippet0203_clinks_java.groovy
│ │ ├── snippet0203_gstring.groovy
│ │ ├── snippet0203_int_usage.groovy
│ │ ├── snippet0203_map_usage.groovy
│ │ ├── snippet0203_range_usage.groovy
│ │ ├── snippet0203_roman.groovy
│ │ ├── snippet0204_evaluate_jdk7_only.groovy
│ │ ├── snippet0204_evaluate_jdk8_only.groovy
│ │ └── snippet0204_failing_typechecked.groovy
│ ├── chap03/
│ │ ├── ArrayListSummer.java
│ │ ├── Listing_03_01_PrimitiveMethodsObjectOperators.groovy
│ │ ├── Listing_03_02_ListMapCast.groovy
│ │ ├── Listing_03_03_DefiningOperators.groovy
│ │ ├── Listing_03_04_DefiningGStrings.groovy
│ │ ├── Listing_03_05_StringOperations.groovy
│ │ ├── Listing_03_06_RegexGStrings.groovy
│ │ ├── Listing_03_07_RegularExpressions.groovy
│ │ ├── Listing_03_08_EachMatch.groovy
│ │ ├── Listing_03_09_PatternReuse.groovy
│ │ ├── Listing_03_10_PatternsClassification.groovy
│ │ ├── Listing_03_11_NumberMethodsGDK.groovy
│ │ ├── extra_escaped_characters_table36.groovy
│ │ ├── extra_method_operators_table34.groovy
│ │ ├── extra_numeric_literals_table32.groovy
│ │ ├── extra_numerical_coercion_table310.groovy
│ │ ├── extra_optional_typing_table33.groovy
│ │ ├── extra_primitive_values_table31.groovy
│ │ ├── regex_dgm.txt
│ │ ├── snippet0301_autoboxing.groovy
│ │ ├── snippet0304_GString_internals.groovy
│ │ ├── snippet0304_stringbuffer.groovy
│ │ ├── snippet0305_matcher_each_group.groovy
│ │ ├── snippet0305_matcher_groups.groovy
│ │ ├── snippet0305_matcher_parallel_assignment.groovy
│ │ ├── snippet0305_matcher_plain.groovy
│ │ └── snippet0306_GDK_methods_for_numbers.groovy
│ ├── chap04/
│ │ ├── Listing_04_01_range_declarations.groovy
│ │ ├── Listing_04_02_ranges_are_objects.groovy
│ │ ├── Listing_04_03_custom_ranges.groovy
│ │ ├── Listing_04_04_list_declarations.groovy
│ │ ├── Listing_04_05_list_subscript_operator.groovy
│ │ ├── Listing_04_06_list_add_remove.groovy
│ │ ├── Listing_04_07_lists_control_structures.groovy
│ │ ├── Listing_04_08_list_content_manipulation.groovy
│ │ ├── Listing_04_09_list_other_methods.groovy
│ │ ├── Listing_04_10_list_quicksort.groovy
│ │ ├── Listing_04_11_list_mapreduce.groovy
│ │ ├── Listing_04_12_map_declarations.groovy
│ │ ├── Listing_04_13_map_accessors.groovy
│ │ ├── Listing_04_14_map_query_methods.groovy
│ │ ├── Listing_04_15_map_iteration.groovy
│ │ ├── Listing_04_16_map_content.groovy
│ │ ├── Listing_04_17_map_example.groovy
│ │ ├── extra_EnumRange.groovy
│ │ ├── extra_ListCast.groovy
│ │ ├── extra_ListTable.groovy
│ │ ├── extra_Map_as.groovy
│ │ ├── extra_Map_group.groovy
│ │ ├── extra_MaxMinSum.groovy
│ │ ├── extra_SplitList.groovy
│ │ ├── snippet0402_ListAsSet.groovy
│ │ ├── snippet0402_ListRemoveNulls.groovy
│ │ ├── snippet0402_ListStreams_jdk8_plus.groovy
│ │ ├── snippet0403_Map_Ctor_Expression.groovy
│ │ ├── snippet0403_Map_Ctor_Unquoted.groovy
│ │ ├── snippet0403_Map_MapReduce.groovy
│ │ └── snippet0403_Map_String_accessors.groovy
│ ├── chap05/
│ │ ├── Listing_05_01_closure_simple_declaration.groovy
│ │ ├── Listing_05_02_simple_method_closure.groovy
│ │ ├── Listing_05_03_multi_method_closure.groovy
│ │ ├── Listing_05_04_closure_all_declarations.groovy
│ │ ├── Listing_05_05_simple_closure_calling.groovy
│ │ ├── Listing_05_06_calling_closures.groovy
│ │ ├── Listing_05_07_simple_currying.groovy
│ │ ├── Listing_05_08_logging_curry_example.groovy
│ │ ├── Listing_05_09_closure_scope.groovy
│ │ ├── Listing_05_10_closure_accumulator.groovy
│ │ ├── Listing_05_11_visitor_pattern.groovy
│ │ ├── extra_ClosureProperty.groovy
│ │ ├── extra_Closure_delegate.groovy
│ │ ├── extra_Closure_myWith.groovy
│ │ ├── snippet0501_envelope.groovy.txt
│ │ ├── snippet0504_closure_default_params.groovy
│ │ ├── snippet0504_closure_isCase.groovy
│ │ ├── snippet0504_closure_paramcount.groovy
│ │ ├── snippet0505_map_with.groovy
│ │ ├── snippet0505_scoping.groovy
│ │ ├── snippet0506_closure_return.groovy
│ │ ├── snippet0507_closure_composition.groovy
│ │ ├── snippet0508_memoize.groovy
│ │ └── snippet0509_trampoline.groovy
│ ├── chap06/
│ │ ├── Listing_06_01_groovy_truth.groovy
│ │ ├── Listing_06_02_assignment_bug.groovy
│ │ ├── Listing_06_03_if_then_else.groovy
│ │ ├── Listing_06_04_conditional_operator.groovy
│ │ ├── Listing_06_05_switch_basic.groovy
│ │ ├── Listing_06_06_switch_advanced.groovy
│ │ ├── Listing_06_07_assert_host.groovy
│ │ ├── Listing_06_08_while.groovy
│ │ ├── Listing_06_09_for.groovy
│ │ ├── Listing_06_10_break_continue.groovy
│ │ ├── Listing_06_11_exception_example.groovy
│ │ ├── extra_if_return.groovy
│ │ ├── extra_in_operator.groovy
│ │ ├── extra_switch_return.groovy
│ │ ├── myFileName.txt
│ │ ├── snippet0602_bad_file_read.groovy
│ │ ├── snippet0602_bad_file_read_with_message.groovy
│ │ ├── snippet0602_failing_assert.groovy
│ │ ├── snippet0603_each_loop_iterate.groovy
│ │ ├── snippet0603_file_iterate_lines.groovy
│ │ ├── snippet0603_for_loop_iterate.groovy
│ │ ├── snippet0603_null_iterate.groovy
│ │ ├── snippet0603_object_iterate.groovy
│ │ ├── snippet0603_regex_iterate_match.groovy
│ │ └── snippet0604_multicatch.groovy
│ ├── chap07/
│ │ ├── Listing_07_01_Declaring_Variables.groovy
│ │ ├── Listing_07_02_TypeBreaking_Assignment.groovy
│ │ ├── Listing_07_03_Referencing_Fields.groovy
│ │ ├── Listing_07_04_Overriding_Field_Access.groovy
│ │ ├── Listing_07_05_Declaring_Methods.groovy
│ │ ├── Listing_07_06_Declaring_Parameters.groovy
│ │ ├── Listing_07_07_Parameter_Usages.groovy
│ │ ├── Listing_07_08_Safe_Dereferencing.groovy
│ │ ├── Listing_07_09_Instantiation.groovy
│ │ ├── Listing_07_10_Instantiation_Named.groovy
│ │ ├── Listing_07_11_Classes.groovy
│ │ ├── Listing_07_13_Import.groovy
│ │ ├── Listing_07_14_Import_As_BugFix.groovy
│ │ ├── Listing_07_15_Import_As_NameClash.groovy
│ │ ├── Listing_07_16_Multimethods.groovy
│ │ ├── Listing_07_17_MultiEquals.groovy
│ │ ├── Listing_07_18_Traits.groovy
│ │ ├── Listing_07_19_Declaring_Beans.groovy
│ │ ├── Listing_07_20_Calling_Beans.groovy
│ │ ├── Listing_07_21_Calling_Beans_Advanced.groovy
│ │ ├── Listing_07_22_Property_Methods.groovy
│ │ ├── Listing_07_23_Expando.groovy
│ │ ├── Listing_07_24_GPath.groovy
│ │ ├── business/
│ │ │ └── Vendor.groovy
│ │ ├── snippet0703_Implicit_Closure_To_SAM.groovy
│ │ ├── snippet0705_Spread_List.groovy
│ │ ├── snippet0705_Spread_Map.groovy
│ │ ├── snippet0705_Spread_Range.groovy
│ │ ├── thirdparty/
│ │ │ └── MathLib.groovy
│ │ └── thirdparty2/
│ │ └── MathLib.groovy
│ ├── chap08/
│ │ ├── Listing_08_01_method_missing.groovy
│ │ ├── Listing_08_02_mini_gorm.groovy
│ │ ├── Listing_08_03_property_missing.groovy
│ │ ├── Listing_08_04_bin_property.groovy
│ │ ├── Listing_08_05_closure_dynamic.groovy
│ │ ├── Listing_08_06_property_method.groovy
│ │ ├── Listing_08_07_MetaClass_jdk7_only.groovy
│ │ ├── Listing_08_07_MetaClass_jdk8_plus.groovy
│ │ ├── Listing_08_08_ProxyMetaClass.groovy
│ │ ├── Listing_08_09_Expando.groovy
│ │ ├── Listing_08_10_EMC.groovy
│ │ ├── Listing_08_11_EMC_Groovy_Class.groovy
│ │ ├── Listing_08_12_EMC_Groovy_Object.groovy
│ │ ├── Listing_08_13_EMC_Java_Object.groovy
│ │ ├── Listing_08_14_EMC_Builder.groovy
│ │ ├── Listing_08_15_EMC_static.groovy
│ │ ├── Listing_08_16_EMC_super.groovy
│ │ ├── Listing_08_17_EMC_hooks.groovy
│ │ ├── Listing_08_18_Existing_Categories.groovy
│ │ ├── Listing_08_19_Marshal.groovy
│ │ ├── Listing_08_20_MarshalCategory.groovy
│ │ ├── Listing_08_21_Test_Mixin.groovy
│ │ ├── Listing_08_22_Sieve_Mixin.groovy
│ │ ├── Listing_08_23_Millimeter.groovy
│ │ ├── Listing_08_24_create_factory.groovy
│ │ ├── Listing_08_25_fake_assign.groovy
│ │ ├── Listing_08_26_restore_emc.groovy
│ │ ├── Listing_08_27_intercept_cache_invoke.groovy
│ │ ├── custom/
│ │ │ ├── Custom.groovy
│ │ │ └── useCustom.groovy
│ │ ├── failing_Listing_08_15_EMC_static.groovy
│ │ ├── failing_Listing_08_16_EMC_super.groovy
│ │ ├── groovy/
│ │ │ └── runtime/
│ │ │ └── metaclass/
│ │ │ └── custom/
│ │ │ └── CustomMetaClass.groovy
│ │ └── markup.html
│ ├── chap09/
│ │ ├── .gradle/
│ │ │ └── 2.2.1/
│ │ │ └── taskArtifacts/
│ │ │ └── cache.properties
│ │ ├── Listing_09_01_ToStringDetective.groovy
│ │ ├── Listing_09_02_ToStringSleuth.groovy
│ │ ├── Listing_09_03_EqualsAndHashCode.groovy
│ │ ├── Listing_09_04_TupleConstructor.groovy
│ │ ├── Listing_09_05_Lazy.groovy
│ │ ├── Listing_09_06_IndexedProperty.groovy
│ │ ├── Listing_09_07_InheritConstructors.groovy
│ │ ├── Listing_09_08_Sortable.groovy
│ │ ├── Listing_09_09_Builder.groovy
│ │ ├── Listing_09_10_Canonical.groovy
│ │ ├── Listing_09_11_Immutable.groovy
│ │ ├── Listing_09_12_Delegate.groovy
│ │ ├── Listing_09_13_Singleton.groovy
│ │ ├── Listing_09_14_Memoized.groovy
│ │ ├── Listing_09_15_TailRecursive.groovy
│ │ ├── Listing_09_16_Log.groovy
│ │ ├── Listing_09_17_Synchronized.groovy
│ │ ├── Listing_09_18_SynchronizedCustomLock.groovy
│ │ ├── Listing_09_19_ReadWriteLock.groovy
│ │ ├── Listing_09_20_AutoClone.groovy
│ │ ├── Listing_09_21_AutoCloneCopyConstructor.groovy
│ │ ├── Listing_09_22_AutoExternalize.groovy
│ │ ├── Listing_09_23_TimedInterrupt.groovy
│ │ ├── Listing_09_24_ThreadInterrupt.groovy
│ │ ├── Listing_09_25_ConditionalInterrupt.groovy
│ │ ├── Listing_09_26_Field.groovy
│ │ ├── Listing_09_27_BaseScript.groovy
│ │ ├── Listing_09_28_AstByHand.groovy
│ │ ├── Listing_09_29_AstByHandWithUtils.groovy
│ │ ├── Listing_09_30_AstBuildFromSpec.groovy
│ │ ├── Listing_09_31_AstBuildFromString.groovy
│ │ ├── Listing_09_32_AstBuildFromStringMixed.groovy
│ │ ├── Listing_09_33_AstBuildFromCode.groovy
│ │ ├── Listing_09_34_GreeterMainTransform.groovy
│ │ ├── Listing_09_35_GreeterMainTransform2.groovy
│ │ ├── Listing_09_38_AstTesting1.groovy
│ │ ├── Listing_09_39_AstTesting2.groovy
│ │ ├── Listing_09_40_AstTesting3.groovy
│ │ ├── Listing_09_41_AstTesting4.groovy
│ │ ├── Listing_09_42_AstTesting5.groovy
│ │ ├── Listings.txt
│ │ ├── build/
│ │ │ ├── reports/
│ │ │ │ └── tests/
│ │ │ │ ├── classes/
│ │ │ │ │ └── regina.CompiledAtASTTransformationTest.html
│ │ │ │ ├── css/
│ │ │ │ │ ├── base-style.css
│ │ │ │ │ └── style.css
│ │ │ │ ├── index.html
│ │ │ │ ├── js/
│ │ │ │ │ └── report.js
│ │ │ │ └── packages/
│ │ │ │ └── regina.html
│ │ │ ├── resources/
│ │ │ │ └── main/
│ │ │ │ └── META-INF/
│ │ │ │ └── services/
│ │ │ │ └── org.codehaus.groovy.transform.ASTTransformation
│ │ │ └── test-results/
│ │ │ ├── TEST-regina.CompiledAtASTTransformationTest.xml
│ │ │ └── binary/
│ │ │ └── test/
│ │ │ └── output.bin.idx
│ │ ├── build.gradle
│ │ ├── gradle/
│ │ │ └── wrapper/
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradle.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── settings.gradle
│ │ ├── snippet0902_autoCloneDefault.txt
│ │ ├── snippet0902_autoCloneSerialization.txt
│ │ ├── snippet0902_autoExternalize.txt
│ │ ├── snippet0902_fieldEquivalent.txt
│ │ ├── snippet0902_mapCreation.txt
│ │ ├── snippet0902_noisySetDelegateByHand.txt
│ │ ├── snippet0902_noisySetInheritance.txt
│ │ ├── snippet0902_nonTailCallReverseList.txt
│ │ ├── snippet0902_readWriteByHand.txt
│ │ ├── snippet0902_readWriteLock.txt
│ │ ├── snippet0902_singletonByHand.txt
│ │ ├── snippet0902_toStringEquivalent.txt
│ │ ├── snippet0903_greeterExpanded.txt
│ │ ├── snippet0903_greeterScript.txt
│ │ ├── snippet0903_localMain.txt
│ │ ├── snippet0903_localMainTransformation.txt
│ │ ├── snippet0905_GetCompiledTimeScript.txt
│ │ └── src/
│ │ ├── main/
│ │ │ ├── groovy/
│ │ │ │ └── regina/
│ │ │ │ └── CompiledAtASTTransformation.groovy
│ │ │ └── resources/
│ │ │ └── META-INF/
│ │ │ └── services/
│ │ │ └── org.codehaus.groovy.transform.ASTTransformation
│ │ └── test/
│ │ └── groovy/
│ │ └── regina/
│ │ └── CompiledAtASTTransformationTest.groovy
│ ├── chap10/
│ │ ├── Greeter.java
│ │ ├── Listing_10_01_Duck.groovy
│ │ ├── Listing_10_02_failing_Typo.groovy
│ │ ├── Listing_10_03_ClassTC.groovy
│ │ ├── Listing_10_04_OneMethodTC.groovy
│ │ ├── Listing_10_05_CompileTimeTypo.groovy
│ │ ├── Listing_10_06_MethodNameTypo.groovy
│ │ ├── Listing_10_07_MethodArgsFlipped.groovy
│ │ ├── Listing_10_08_InvalidAssignments.groovy
│ │ ├── Listing_10_09_AssignmentsWithCoercion.groovy
│ │ ├── Listing_10_10_DefField.groovy
│ │ ├── Listing_10_11_InPlaceList.groovy
│ │ ├── Listing_10_12_Generics.groovy
│ │ ├── Listing_10_13_ListStyleCtorRuntime.groovy
│ │ ├── Listing_10_14_ListStyleCtorTC.groovy
│ │ ├── Listing_10_15_MapStyleCtorBad.groovy
│ │ ├── Listing_10_16_ListStyleCtor.groovy
│ │ ├── Listing_10_17_ListStyleCtorFixed.groovy
│ │ ├── Listing_10_18_CodeAsData.groovy
│ │ ├── Listing_10_19_ClosuresBadReturnType.groovy
│ │ ├── Listing_10_20_UserValidation.groovy
│ │ ├── Listing_10_21_UserValidationTC.groovy
│ │ ├── Listing_10_22_UserValidation_ExplicitTypes.groovy
│ │ ├── Listing_10_23_UserValidation_SAM.groovy
│ │ ├── Listing_10_24_UserValidation_ClosureParams.groovy
│ │ ├── Listing_10_25_UserValidation_DSL.groovy
│ │ ├── Listing_10_26_UserValidation_DelegatesTo.groovy
│ │ ├── Listing_10_27_UserValidation_DelegatesToTarget.groovy
│ │ ├── Listing_10_28_Category.groovy
│ │ ├── Listing_10_29_EMC.groovy
│ │ ├── Listing_10_30_Builder.groovy
│ │ ├── Listing_10_31_MixedTypeChecking.groovy
│ │ ├── Listing_10_32_Skip.groovy
│ │ ├── Listing_10_33_FlowTyping.groovy
│ │ ├── Listing_10_34_FlowTypingOk.groovy
│ │ ├── Listing_10_35_LUB.groovy
│ │ ├── Listing_10_36_Condition.groovy
│ │ ├── Listing_10_37_ClosureSharedVar.groovy
│ │ ├── Listing_10_38_LubError.groovy
│ │ ├── Listing_10_39_LubOk.groovy
│ │ ├── Listing_10_40_FibBench.groovy
│ │ ├── Listing_10_41_JavaGreeter.txt
│ │ ├── Listing_10_42_StaticCompileDispatch.groovy
│ │ ├── Listing_10_43_MonkeyPatching.groovy
│ │ ├── Listing_10_44_BookingDSL.groovy
│ │ ├── Listing_10_45_MultiValidation.groovy
│ │ ├── Listing_10_46_RobotExtension.groovy
│ │ ├── Listing_10_47_SQLExtension.groovy
│ │ ├── User.groovy
│ │ ├── extra1004_JavaDispatch.java
│ │ ├── extra1004_RuntimeGroovyDispatch.groovy
│ │ ├── markup.html
│ │ ├── snippet1003_GroovyGreeter.groovy
│ │ ├── snippet1005_RobotMainTC.groovy
│ │ └── snippet1005_SqlMainTC.groovy
│ ├── chap11/
│ │ ├── Listing_11_01_SquaresFactors.xml
│ │ ├── Listing_11_02_SquaresFactors.java
│ │ ├── Listing_11_03_MarkupBuilderPlain.groovy
│ │ ├── Listing_11_04_NodeBuilder.groovy
│ │ ├── Listing_11_05_NodeBuilderLogic.groovy
│ │ ├── Listing_11_06_MarkupBuilderLogic.groovy
│ │ ├── Listing_11_07_MarkupBuilderHtml.groovy
│ │ ├── Listing_11_08_StreamingMarkupBuilderLogic.groovy
│ │ ├── Listing_11_09_ExampleBuild.xml
│ │ ├── Listing_11_10_PW_SwingBuilder.groovy
│ │ ├── Listing_11_11_Swing_Widgets.groovy
│ │ ├── Listing_11_12_Swing_Layout.groovy
│ │ ├── Listing_11_13_Table_Demo.groovy
│ │ ├── Listing_11_14_Binding.groovy
│ │ ├── Listing_11_15_Plotter.groovy
│ │ ├── Listing_11_16_Groovyfx.groovy
│ │ ├── Listing_11_17_CalorieCounterBuilderSupport.groovy
│ │ ├── Listing_11_18_CalorieCounterFactoryBuilderSupport.groovy
│ │ ├── Listing_11_19_CalorieCounterByHand.groovy
│ │ ├── markup.html
│ │ ├── snippet1103_MarkupBuilderOutput.html
│ │ ├── snippet1103_MarkupWithHyphen.groovy
│ │ ├── snippet1106_AntBuilderIf.groovy
│ │ ├── snippet1106_AntIf.xml
│ │ ├── snippet1107_Printer.groovy
│ │ └── snippet1107_binding.txt
│ ├── chap12/
│ │ ├── Listing_12_01_info_jdk6_only.groovy
│ │ ├── Listing_12_01_info_jdk7_only.groovy
│ │ ├── Listing_12_01_info_jdk8_plus.groovy
│ │ ├── Listing_12_02_properties.groovy
│ │ ├── Listing_12_03_File_Iteration.groovy
│ │ ├── Listing_12_04_Filesystem.groovy
│ │ ├── Listing_12_05_Traversal.groovy
│ │ ├── Listing_12_06_File_Read.groovy
│ │ ├── Listing_12_07_File_Write.groovy
│ │ ├── Listing_12_08_Writer_LeftShift.groovy
│ │ ├── Listing_12_09_File_Transform_jdk7_plus.groovy
│ │ ├── Listing_12_10_File_ObjectStreams.groovy
│ │ ├── Listing_12_11_Temp_Dir.groovy
│ │ ├── Listing_12_12_Threads.groovy
│ │ ├── Listing_12_13_Processes_UnixCommands.groovy
│ │ ├── Listing_12_14_Processes_ZipUnzip.groovy
│ │ ├── Listing_12_15_SimpleTemplateEngine.groovy
│ │ ├── Listing_12_16_GroovletExample.groovy
│ │ ├── Listing_12_17_HelloWorldGroovlet.groovy
│ │ ├── Listing_12_19_InspectGroovlet.groovy
│ │ ├── Listing_12_20_HiLowGame.groovy
│ │ ├── Listing_12_21_NumberTemplate.txt
│ │ ├── Listing_12_22_TemplateGroovlet.groovy
│ │ ├── Number.template.html
│ │ ├── data/
│ │ │ └── example.txt
│ │ ├── objects.dta
│ │ ├── snippet1201_SlowTyping.groovy
│ │ ├── snippet1201_UseCategory.groovy
│ │ ├── snippet1202_base64.groovy
│ │ └── web.xml
│ ├── chap13/
│ │ ├── Listing_13_01_Connecting.groovy
│ │ ├── Listing_13_02_ConnectingDataSource.groovy
│ │ ├── Listing_13_03_Creating.groovy
│ │ ├── Listing_13_04_DbUtilClass.txt
│ │ ├── Listing_13_05_Inserting.groovy
│ │ ├── Listing_13_06_Reading.groovy
│ │ ├── Listing_13_07_Updating.groovy
│ │ ├── Listing_13_08_Delete.groovy
│ │ ├── Listing_13_09_Transactions.groovy
│ │ ├── Listing_13_10_Batching.groovy
│ │ ├── Listing_13_11_Paging.groovy
│ │ ├── Listing_13_12_Metadata.groovy
│ │ ├── Listing_13_13_MoreMetadata.groovy
│ │ ├── Listing_13_14_NamedOrdinal.groovy
│ │ ├── Listing_13_15_StoredProcBasic.groovy
│ │ ├── Listing_13_16_StoredProcParam.groovy
│ │ ├── Listing_13_17_StoredProcInOut.groovy
│ │ ├── Listing_13_18_DataSetBasics.groovy
│ │ ├── Listing_13_19_DataSetFiltering.groovy
│ │ ├── Listing_13_20_DataSetViews.groovy
│ │ ├── Listing_13_21_DbHelper.txt
│ │ ├── Listing_13_22_DataAccessObject.txt
│ │ ├── Listing_13_23_AthleteDAO.txt
│ │ ├── Listing_13_24_AthleteApplication.txt
│ │ ├── Listing_13_25_AthleteAppMain.groovy
│ │ ├── Listing_13_26_AthleteAppTest.groovy
│ │ ├── Listing_13_27_MongoAthletes.groovy
│ │ ├── Listing_13_28_NeoAthletes.groovy
│ │ ├── Listing_13_29_NeoGremlin.groovy
│ │ ├── extra_NeoGremlinGraph.groovy
│ │ ├── layering/
│ │ │ ├── AthleteApplication.groovy
│ │ │ ├── AthleteDAO.groovy
│ │ │ ├── DataAccessObject.groovy
│ │ │ └── DbHelper.groovy
│ │ ├── marathon/
│ │ │ ├── active_tx_log
│ │ │ ├── index/
│ │ │ │ ├── lucene.log.active
│ │ │ │ ├── lucene.log.v0
│ │ │ │ ├── lucene.log.v1
│ │ │ │ ├── lucene.log.v2
│ │ │ │ ├── lucene.log.v3
│ │ │ │ ├── lucene.log.v4
│ │ │ │ ├── lucene.log.v5
│ │ │ │ ├── lucene.log.v6
│ │ │ │ ├── lucene.log.v7
│ │ │ │ └── lucene.log.v8
│ │ │ ├── messages.log
│ │ │ ├── neostore
│ │ │ ├── neostore.id
│ │ │ ├── neostore.labeltokenstore.db.id
│ │ │ ├── neostore.labeltokenstore.db.names
│ │ │ ├── neostore.labeltokenstore.db.names.id
│ │ │ ├── neostore.nodestore.db.id
│ │ │ ├── neostore.nodestore.db.labels
│ │ │ ├── neostore.nodestore.db.labels.id
│ │ │ ├── neostore.propertystore.db.arrays
│ │ │ ├── neostore.propertystore.db.arrays.id
│ │ │ ├── neostore.propertystore.db.id
│ │ │ ├── neostore.propertystore.db.index
│ │ │ ├── neostore.propertystore.db.index.id
│ │ │ ├── neostore.propertystore.db.index.keys
│ │ │ ├── neostore.propertystore.db.index.keys.id
│ │ │ ├── neostore.propertystore.db.strings
│ │ │ ├── neostore.propertystore.db.strings.id
│ │ │ ├── neostore.relationshipgroupstore.db.id
│ │ │ ├── neostore.relationshipstore.db.id
│ │ │ ├── neostore.relationshiptypestore.db.id
│ │ │ ├── neostore.relationshiptypestore.db.names
│ │ │ ├── neostore.relationshiptypestore.db.names.id
│ │ │ ├── neostore.schemastore.db.id
│ │ │ ├── nioneo_logical.log.active
│ │ │ ├── nioneo_logical.log.v6
│ │ │ ├── nioneo_logical.log.v7
│ │ │ ├── nioneo_logical.log.v8
│ │ │ ├── schema/
│ │ │ │ └── label/
│ │ │ │ └── lucene/
│ │ │ │ ├── segments.gen
│ │ │ │ └── segments_1
│ │ │ ├── store_lock
│ │ │ └── tm_tx_log.1
│ │ ├── snippet1301_ConnectingWithGrab.groovy
│ │ ├── snippet1301_ConnectingWithInstance.groovy
│ │ ├── snippet1301_ConnectingWithMap.groovy
│ │ ├── snippet1301_ReadEachRow.groovy
│ │ ├── snippet1301_ReadEachRowList.groovy
│ │ ├── snippet1301_ReadQuery.groovy
│ │ ├── snippet1301_ReadRows.groovy
│ │ └── util/
│ │ ├── DbUtil.groovy
│ │ ├── MarathonRelationships.groovy
│ │ └── Neo4jUtil.groovy
│ ├── chap14/
│ │ ├── Listing_14_01_Plan.txt
│ │ ├── Listing_14_02_DOM.groovy
│ │ ├── Listing_14_03_DOM_Category.groovy
│ │ ├── Listing_14_04_XmlParser.groovy
│ │ ├── Listing_14_05_XmlSlurper.groovy
│ │ ├── Listing_14_06_SAX.groovy
│ │ ├── Listing_14_07_StAX.groovy
│ │ ├── Listing_14_08_XmlBoiler.groovy
│ │ ├── Listing_14_09_XmlStreamer.groovy
│ │ ├── Listing_14_10_StreamedHtml.groovy
│ │ ├── Listing_14_11_UpdateDomCategory.groovy
│ │ ├── Listing_14_12_UpdateParser.groovy
│ │ ├── Listing_14_13_UpdateSlurper.groovy
│ │ ├── Listing_14_14_XPath.groovy
│ │ ├── Listing_14_15_GroovyPlansTemplate.txt
│ │ ├── Listing_14_16_XPathTemplate.groovy
│ │ ├── Listing_14_17_JsonParser.groovy
│ │ ├── Listing_14_18_JsonBuilder.groovy
│ │ ├── Listing_14_19_JsonBuilderLogic.groovy
│ │ ├── Listing_14_20_JsonOutputAthlete.groovy
│ │ ├── UpdateChecker.groovy
│ │ ├── data/
│ │ │ ├── GroovyPlans.html
│ │ │ ├── GroovyPlans.template.html
│ │ │ ├── StreamedGroovyPlans.html
│ │ │ ├── XPathGroovyPlans.html
│ │ │ ├── plan.json
│ │ │ ├── plan.xml
│ │ │ └── style.css
│ │ └── log4j.xml
│ ├── chap15/
│ │ ├── Listing_15_01_RSS_bbcnews.groovy
│ │ ├── Listing_15_02_ATOM_devworks.groovy
│ │ ├── Listing_15_03_REST_jira_url.groovy
│ │ ├── Listing_15_04_REST_jira_httpb_get.groovy
│ │ ├── Listing_15_05_REST_currency_httpb_get.groovy
│ │ ├── Listing_15_06_REST_currency_httpb_post.groovy
│ │ ├── Listing_15_07_REST_currency_jaxrs.groovy
│ │ ├── Listing_15_08_REST_currency_jaxrs_proxy.groovy
│ │ ├── Listing_15_09_XMLRPC_echo.groovy
│ │ ├── Listing_15_10_XMLRPC_jira.groovy
│ │ ├── Listing_15_11_SOAP_wsdl.groovy
│ │ ├── Listing_15_12_SOAP11_currency_url.groovy
│ │ ├── Listing_15_13_SOAP12_currency_httpb.groovy
│ │ ├── Listing_15_14_SOAP11_currency_wslite.groovy
│ │ ├── Listing_15_15_SOAP12_currency_wslite.groovy
│ │ └── data/
│ │ └── conv.templ.xml
│ ├── chap16/
│ │ ├── HelloIntegrationWorld.java
│ │ ├── Listing_16_01_HelloIntegration.groovy
│ │ ├── Listing_16_02_HelloIntegrationJava.txt
│ │ ├── Listing_16_03_MultilineScript.groovy
│ │ ├── Listing_16_04_UsingEval.groovy
│ │ ├── Listing_16_05_Binding.groovy
│ │ ├── Listing_16_06_BindingTwoWay.groovy
│ │ ├── Listing_16_07_ClassInScript.groovy
│ │ ├── Listing_16_08_Payment_calculator.groovy
│ │ ├── Listing_16_09_MethodsInBinding.groovy
│ │ ├── Listing_16_10_ShapeInfoMain.txt
│ │ ├── Listing_16_11_SpringConfig.txt
│ │ ├── Listing_16_12_BeanToString.groovy
│ │ ├── shapes/
│ │ │ ├── Circle.groovy
│ │ │ ├── MaxAreaInfo.groovy
│ │ │ ├── MaxPerimeterInfo.java
│ │ │ ├── Shape.java
│ │ │ ├── ShapeInfo.java
│ │ │ ├── ShapeInfoMain.java
│ │ │ └── Square.java
│ │ └── spring/
│ │ ├── common/
│ │ │ ├── Shape.java
│ │ │ └── ShapeInfo.java
│ │ ├── groovy/
│ │ │ ├── Circle.groovy
│ │ │ └── MaxAreaInfo.groovy
│ │ ├── java/
│ │ │ ├── MaxPerimeterInfo.java
│ │ │ ├── ShapeInfoFactoryMain.java
│ │ │ ├── ShapeInfoMain.java
│ │ │ ├── ShapeInfoSpringMain.java
│ │ │ └── Square.java
│ │ ├── lib/
│ │ │ ├── commons-logging.jar
│ │ │ ├── spring-beans.jar
│ │ │ ├── spring-core.jar
│ │ │ └── spring.jar
│ │ └── resources/
│ │ └── beans.xml
│ ├── chap17/
│ │ ├── .classpath
│ │ ├── .project
│ │ ├── Converter.groovy
│ │ ├── Counter.groovy
│ │ ├── Farm.groovy
│ │ ├── Listing_17_01_Celsius.groovy
│ │ ├── Listing_17_02_CounterTest.groovy
│ │ ├── Listing_17_03_HashMapTest.groovy
│ │ ├── Listing_17_04_GroovyTestSuite.groovy
│ │ ├── Listing_17_05_AllTestSuite.groovy
│ │ ├── Listing_17_06_DataDrivenJUnitTest.groovy
│ │ ├── Listing_17_07_PropertyBased.groovy
│ │ ├── Listing_17_08_Balancer.groovy
│ │ ├── Listing_17_09_BalancerStub.groovy
│ │ ├── Listing_17_10_BalancerMock.groovy
│ │ ├── Listing_17_11_LoggingCounterTest.groovy
│ │ ├── Listing_17_12_JUnitPerf.groovy
│ │ ├── Listing_17_13_SpockSimple.groovy
│ │ ├── Listing_17_14_SpockMock.groovy
│ │ ├── Listing_17_15_SpockMockWildcards.groovy
│ │ ├── Listing_17_16_SpockMockClosureChecks.groovy
│ │ ├── Listing_17_17_SpockDataDriven.groovy
│ │ ├── LoggingCounter.groovy
│ │ ├── MovieTheater.groovy
│ │ ├── Purchase.groovy
│ │ ├── automation/
│ │ │ ├── build.gradle
│ │ │ ├── gradle/
│ │ │ │ └── wrapper/
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ │ ├── gradlew
│ │ │ ├── gradlew.bat
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── groovy/
│ │ │ │ └── Calculator.groovy
│ │ │ └── test/
│ │ │ └── groovy/
│ │ │ └── CalculatorTest.groovy
│ │ ├── cobertura/
│ │ │ ├── build.gradle
│ │ │ ├── gradle/
│ │ │ │ └── wrapper/
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ │ ├── gradlew
│ │ │ ├── gradlew.bat
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── groovy/
│ │ │ │ ├── BiggestPairCalc.groovy
│ │ │ │ └── BiggestPairCalcFixed.groovy
│ │ │ └── test/
│ │ │ └── groovy/
│ │ │ └── BiggestPairCalcTest.groovy
│ │ ├── extra_ParameterizedTestNG.groovy
│ │ ├── extra_TestNG.groovy
│ │ ├── snippet1701_JUnit4.groovy
│ │ ├── snippet1704_listPropertyCheck.groovy
│ │ └── test-output/
│ │ ├── Command line suite/
│ │ │ ├── Command line test.html
│ │ │ └── Command line test.xml
│ │ ├── emailable-report.html
│ │ ├── index.html
│ │ ├── junitreports/
│ │ │ ├── TEST-extra_ParameterizedTestNG.xml
│ │ │ └── TEST-extra_TestNG.xml
│ │ ├── old/
│ │ │ ├── Command line suite/
│ │ │ │ ├── Command line test.properties
│ │ │ │ ├── classes.html
│ │ │ │ ├── groups.html
│ │ │ │ ├── index.html
│ │ │ │ ├── main.html
│ │ │ │ ├── methods-alphabetical.html
│ │ │ │ ├── methods-not-run.html
│ │ │ │ ├── methods.html
│ │ │ │ ├── reporter-output.html
│ │ │ │ ├── testng.xml.html
│ │ │ │ └── toc.html
│ │ │ └── index.html
│ │ ├── testng-reports.css
│ │ ├── testng-reports.js
│ │ ├── testng-results.xml
│ │ └── testng.css
│ ├── chap18/
│ │ ├── Listing_18_01_ConcurrentSquares.groovy
│ │ ├── Listing_18_02_ConcurrentSquaresTransparent.groovy
│ │ ├── Listing_18_03_ConcurrentSquaresTransitive.groovy
│ │ ├── Listing_18_04_MapFilterReduce.groovy
│ │ ├── Listing_18_05_SquaresMapReduce.groovy
│ │ ├── Listing_18_06_Dataflow.groovy
│ │ ├── Listing_18_07_DataflowStreams.groovy
│ │ ├── Listing_18_08_Actors.groovy
│ │ ├── Listing_18_09_ActorsLifecycle.groovy
│ │ ├── Listing_18_10_ActorsMessageAware.groovy
│ │ ├── Listing_18_11_Agent.groovy
│ │ ├── Listing_18_12.txt
│ │ ├── Listing_18_13_YahooForkJoin.groovy
│ │ ├── Listing_18_14_YahooMapReduce.groovy
│ │ ├── Listing_18_15_YahooDataflow.groovy
│ │ ├── YahooService.groovy
│ │ ├── snippet1801_startThread.groovy
│ │ ├── snippet1803_java_parallel_streams_jdk8_only.groovy
│ │ ├── snippet1804_deadlock.groovy
│ │ └── snippet1804_nondeterministic.groovy
│ ├── chap19/
│ │ ├── FetchOptions.groovy
│ │ ├── FetchOptionsBuilder.groovy
│ │ ├── Listing_19_06_Binding.groovy
│ │ ├── Listing_19_29_OrderDSL.groovy
│ │ ├── Listing_19_30_WhenIfControlStructure.groovy
│ │ ├── Listing_19_31_Until_failing_.groovy
│ │ ├── Listing_19_32_UntilControlStructure.groovy
│ │ ├── Listing_19_39_GivenWhenThen.groovy
│ │ ├── Listing_19_43_FetchOptionsScript.groovy
│ │ ├── Listing_19_44_RubyStyleNewify.groovy
│ │ ├── Listing_19_45_PythonStyleNewify.groovy
│ │ ├── Listing_19_46_Terms.groovy
│ │ ├── Listing_19_47_NewifyInjected.txt
│ │ ├── Listing_19_48_No_IO.groovy
│ │ ├── Listing_19_49_ArithmeticShell.groovy
│ │ ├── Listing_19_50_TimedInterrupt.groovy
│ │ ├── Listing_19_51_SystemExitGuard.groovy
│ │ ├── Listing_19_53_QueryCustomizer.groovy
│ │ ├── Listings.txt
│ │ ├── Query.groovy
│ │ ├── extra_FetchOptions_traditional.groovy
│ │ ├── v01/
│ │ │ └── Listing_19_01_SelfContainedScript.groovy
│ │ ├── v02/
│ │ │ ├── Listing_19_04_MainSimple.groovy
│ │ │ ├── Listing_19_05_MainGroovyShell.groovy
│ │ │ ├── Listing_19_07_MainBinding.groovy
│ │ │ ├── Listing_19_08_MainDirectionConstants.groovy
│ │ │ ├── Listing_19_09_MainDirectionsSpread.groovy
│ │ │ ├── Listing_19_10_MainImplicitMethod.groovy
│ │ │ ├── Listing_19_12_MainBaseScript.groovy
│ │ │ ├── Listing_19_13_MainImportCustomizer.groovy
│ │ │ ├── Listing_19_14_MainCustomBaseScriptClass.groovy
│ │ │ ├── Listing_19_16_MainMethodClosure.groovy
│ │ │ ├── Listing_19_19_MainLowerCase.groovy
│ │ │ ├── integration/
│ │ │ │ ├── CaseRobotBaseScript.groovy
│ │ │ │ ├── CustomBinding.groovy
│ │ │ │ └── RobotBaseScript.groovy
│ │ │ ├── model/
│ │ │ │ ├── Direction.groovy
│ │ │ │ └── Robot.groovy
│ │ │ └── snippet1901_MainFileRunner.groovy
│ │ ├── v03/
│ │ │ ├── Listing_19_27_SimpleCommandChain.groovy
│ │ │ ├── Listing_19_40_Robot_With.groovy
│ │ │ ├── integration/
│ │ │ │ ├── DistanceCategory.groovy
│ │ │ │ ├── RobotBaseScript.groovy
│ │ │ │ └── SuperBotBaseScript.groovy
│ │ │ └── model/
│ │ │ ├── Direction.groovy
│ │ │ ├── Distance.groovy
│ │ │ ├── Duration.groovy
│ │ │ ├── Robot.groovy
│ │ │ ├── Speed.groovy
│ │ │ ├── SuperBot.groovy
│ │ │ └── Unit.groovy
│ │ └── xform/
│ │ ├── BusinessLogicScript.groovy
│ │ ├── CustomControlStructure.groovy
│ │ ├── Listing_19_36_WhenTransformation.groovy
│ │ ├── WhenUntilTransform.groovy
│ │ ├── extra_WhenTransformationWorksWithoutBraces.groovy
│ │ └── snippet1906_WhenUntilXform_Structure.groovy
│ └── chap20/
│ ├── Listing_20_01_Grapes_for_twitter_urls.groovy
│ ├── Listing_20_02_Scriptom_Windows_only.groovy
│ ├── Listing_20_03_ActivX_Windows_only.groovy
│ ├── Listing_20_10_SquaringMapValue.groovy
│ ├── Listing_20_11_Synchronized.groovy
│ └── Listing_20_12_DbC_invariants.groovy
└── test.groovy
================================================
FILE CONTENTS
================================================
================================================
FILE: .idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.
================================================
FILE: README.md
================================================
# Groovy In Action
Source code of the book [Groovy in Action, 2nd edition (manning,](http://manning.com/koenig2/?a_aid=regina&a_bid=8ade3b0e)
[amazon)](http://www.amazon.com/gp/product/1935182447/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1935182447&linkCode=as2&tag=httpgroovycan-20&linkId=XLTAIALXLIUBWPOH)
### Use it? Star it!
All source code is free for everybody's use under the Apache 2 license.
If you want to do us a favor in return, please give this repo a "star" such that we can get at least a feeling of how many developers are using it. _Thanks!_
# Prerequisites
* Java 1.7 or higher
* Groovy 2.4.1 or higher
# Considerations
One can run all listings by calling
groovy alltests
However, since some listings rely on external
constraints like special versions of the JVM
(e.g. to test Groovy features for Java 8) or
OS-specific integration features, some listings
may be excluded from execution.
Listings are usually made such that you can
`cd` into the directory for that chapter and
call the listing via
groovy mylistingname
If no other instructions apply, you best
use Groovy 2.4.1 and Java 7. More recent versions
will also work in most cases.
There are code adaptions to Java 8.
Please use the Java_8 branch if you rely on those.
Keep groovin'
The authors
================================================
FILE: alltests.groovy
================================================
for (number in 1..20) {
def ant = new AntBuilder()
def dir = 'listings/chap' + number.toString().padLeft(2, '0')
def runner = "../../test"
if (number == 11) {
def home = System.getenv("JAVA_HOME")
jfxcp = "$home/jre/lib/jfxrt.jar"
runner = "-classpath $jfxcp " + runner
} else if (number == 10) {
// add type extension source files to classpath
runner = "-classpath . " + runner
}
println "testing dir $dir"
def os = System.getProperty("os.name").toLowerCase()
def groovy = os.contains('windows') ? System.getenv("GROOVY_HOME") + '\\bin\\groovy.bat' : 'groovy'
ant.exec(
dir: dir,
outputproperty: "cmdOut",
executable: groovy) {
arg(line: runner)
}
def out = ant.project.properties.cmdOut
println out
if (out.contains('FAILED')) {
out.split("\n").grep(~/.*FAILED:.*/).each { println it }
System.exit(1)
}
}
================================================
FILE: listings/allsources.txt
================================================
./appD/Listing_D_01_GStrings.groovy
./appD/Listing_D_02_Lists.groovy
./appD/Listing_D_03_Closures.groovy
./appD/Listing_D_04_Regex.groovy
./appD/Listing_D_05_GPath.groovy
./chap01/customers.xml
./chap01/data.txt
./chap01/groovysh.txt
./chap01/Listing_01_01_Gold.groovy
./chap01/snippet0101_customers.groovy
./chap01/snippet0101_fileLineNumbers.groovy
./chap01/snippet0101_newDates.txt
./chap01/snippet0101_printPackageNames.groovy
./chap01/snippet0101_printPackageNamesGpath.groovy
./chap01/snippet0102_printGroovyWebSiteCount.groovy
./chap01/snippet0103_googleIpAdr.groovy
./chap02/Book.groovy
./chap02/Listing_02_01_Assertions.groovy
./chap02/Listing_02_02_Book.txt
./chap02/Listing_02_03_BookScript.groovy
./chap02/Listing_02_04_BookBean.groovy
./chap02/Listing_02_05_ImmutableBook.groovy
./chap02/Listing_02_06_Grab.groovy
./chap02/Listing_02_07_Clinks.groovy
./chap02/Listing_02_08_ControlStructures.groovy
./chap02/snippet0201_comments.groovy
./chap02/snippet0202_failing_assert.groovy
./chap02/snippet0202_failing_assertion_error.txt
./chap02/snippet0203_clinks_java.groovy
./chap02/snippet0203_gstring.groovy
./chap02/snippet0203_int_usage.groovy
./chap02/snippet0203_map_usage.groovy
./chap02/snippet0203_range_usage.groovy
./chap02/snippet0203_roman.groovy
./chap02/snippet0204_evaluate_jdk7_only.groovy
./chap02/snippet0204_evaluate_jdk8_only.groovy
./chap02/snippet0204_failing_typechecked.groovy
./chap03/ArrayListSummer.java
./chap03/extra_escaped_characters_table36.groovy
./chap03/extra_method_operators_table34.groovy
./chap03/extra_numeric_literals_table32.groovy
./chap03/extra_numerical_coercion_table310.groovy
./chap03/extra_optional_typing_table33.groovy
./chap03/extra_primitive_values_table31.groovy
./chap03/Listing_03_01_PrimitiveMethodsObjectOperators.groovy
./chap03/Listing_03_02_ListMapCast.groovy
./chap03/Listing_03_03_DefiningOperators.groovy
./chap03/Listing_03_04_DefiningGStrings.groovy
./chap03/Listing_03_05_StringOperations.groovy
./chap03/Listing_03_06_RegexGStrings.groovy
./chap03/Listing_03_07_RegularExpressions.groovy
./chap03/Listing_03_08_EachMatch.groovy
./chap03/Listing_03_09_PatternReuse.groovy
./chap03/Listing_03_10_PatternsClassification.groovy
./chap03/Listing_03_11_NumberMethodsGDK.groovy
./chap03/regex_dgm.txt
./chap03/snippet0301_autoboxing.groovy
./chap03/snippet0304_GString_internals.groovy
./chap03/snippet0304_stringbuffer.groovy
./chap03/snippet0305_matcher_each_group.groovy
./chap03/snippet0305_matcher_groups.groovy
./chap03/snippet0305_matcher_parallel_assignment.groovy
./chap03/snippet0305_matcher_plain.groovy
./chap03/snippet0306_GDK_methods_for_numbers.groovy
./chap04/extra_EnumRange.groovy
./chap04/extra_ListCast.groovy
./chap04/extra_ListTable.groovy
./chap04/extra_Map_as.groovy
./chap04/extra_Map_group.groovy
./chap04/extra_MaxMinSum.groovy
./chap04/extra_SplitList.groovy
./chap04/Listing_04_01_range_declarations.groovy
./chap04/Listing_04_02_ranges_are_objects.groovy
./chap04/Listing_04_03_custom_ranges.groovy
./chap04/Listing_04_04_list_declarations.groovy
./chap04/Listing_04_05_list_subscript_operator.groovy
./chap04/Listing_04_06_list_add_remove.groovy
./chap04/Listing_04_07_lists_control_structures.groovy
./chap04/Listing_04_08_list_content_manipulation.groovy
./chap04/Listing_04_09_list_other_methods.groovy
./chap04/Listing_04_10_list_quicksort.groovy
./chap04/Listing_04_11_list_mapreduce.groovy
./chap04/Listing_04_12_map_declarations.groovy
./chap04/Listing_04_13_map_accessors.groovy
./chap04/Listing_04_14_map_query_methods.groovy
./chap04/Listing_04_15_map_iteration.groovy
./chap04/Listing_04_16_map_content.groovy
./chap04/Listing_04_17_map_example.groovy
./chap04/snippet0402_ListAsSet.groovy
./chap04/snippet0402_ListRemoveNulls.groovy
./chap04/snippet0402_ListStreams_jdk8_plus.groovy
./chap04/snippet0403_Map_Ctor_Expression.groovy
./chap04/snippet0403_Map_Ctor_Unquoted.groovy
./chap04/snippet0403_Map_MapReduce.groovy
./chap04/snippet0403_Map_String_accessors.groovy
./chap05/extra_Closure_delegate.groovy
./chap05/extra_Closure_myWith.groovy
./chap05/extra_ClosureProperty.groovy
./chap05/Listing_05_01_closure_simple_declaration.groovy
./chap05/Listing_05_02_simple_method_closure.groovy
./chap05/Listing_05_03_multi_method_closure.groovy
./chap05/Listing_05_04_closure_all_declarations.groovy
./chap05/Listing_05_05_simple_closure_calling.groovy
./chap05/Listing_05_06_calling_closures.groovy
./chap05/Listing_05_07_simple_currying.groovy
./chap05/Listing_05_08_logging_curry_example.groovy
./chap05/Listing_05_09_closure_scope.groovy
./chap05/Listing_05_10_closure_accumulator.groovy
./chap05/Listing_05_11_visitor_pattern.groovy
./chap05/snippet0501_envelope.groovy.txt
./chap05/snippet0504_closure_default_params.groovy
./chap05/snippet0504_closure_isCase.groovy
./chap05/snippet0504_closure_paramcount.groovy
./chap05/snippet0505_map_with.groovy
./chap05/snippet0505_scoping.groovy
./chap05/snippet0506_closure_return.groovy
./chap05/snippet0507_closure_composition.groovy
./chap05/snippet0508_memoize.groovy
./chap05/snippet0509_trampoline.groovy
./chap06/extra_if_return.groovy
./chap06/extra_in_operator.groovy
./chap06/extra_switch_return.groovy
./chap06/Listing_06_01_groovy_truth.groovy
./chap06/Listing_06_02_assignment_bug.groovy
./chap06/Listing_06_03_if_then_else.groovy
./chap06/Listing_06_04_conditional_operator.groovy
./chap06/Listing_06_05_switch_basic.groovy
./chap06/Listing_06_06_switch_advanced.groovy
./chap06/Listing_06_07_assert_host.groovy
./chap06/Listing_06_08_while.groovy
./chap06/Listing_06_09_for.groovy
./chap06/Listing_06_10_break_continue.groovy
./chap06/Listing_06_11_exception_example.groovy
./chap06/myFileName.txt
./chap06/snippet0602_bad_file_read.groovy
./chap06/snippet0602_bad_file_read_with_message.groovy
./chap06/snippet0602_failing_assert.groovy
./chap06/snippet0603_each_loop_iterate.groovy
./chap06/snippet0603_file_iterate_lines.groovy
./chap06/snippet0603_for_loop_iterate.groovy
./chap06/snippet0603_null_iterate.groovy
./chap06/snippet0603_object_iterate.groovy
./chap06/snippet0603_regex_iterate_match.groovy
./chap06/snippet0604_multicatch.groovy
./chap07/business/Vendor.groovy
./chap07/Listing_07_01_Declaring_Variables.groovy
./chap07/Listing_07_02_TypeBreaking_Assignment.groovy
./chap07/Listing_07_03_Referencing_Fields.groovy
./chap07/Listing_07_04_Overriding_Field_Access.groovy
./chap07/Listing_07_05_Declaring_Methods.groovy
./chap07/Listing_07_06_Declaring_Parameters.groovy
./chap07/Listing_07_07_Parameter_Usages.groovy
./chap07/Listing_07_08_Safe_Dereferencing.groovy
./chap07/Listing_07_09_Instantiation.groovy
./chap07/Listing_07_10_Instantiation_Named.groovy
./chap07/Listing_07_11_Classes.groovy
./chap07/Listing_07_13_Import.groovy
./chap07/Listing_07_14_Import_As_BugFix.groovy
./chap07/Listing_07_15_Import_As_NameClash.groovy
./chap07/Listing_07_16_Multimethods.groovy
./chap07/Listing_07_17_MultiEquals.groovy
./chap07/Listing_07_18_Traits.groovy
./chap07/Listing_07_19_Declaring_Beans.groovy
./chap07/Listing_07_20_Calling_Beans.groovy
./chap07/Listing_07_21_Calling_Beans_Advanced.groovy
./chap07/Listing_07_22_Property_Methods.groovy
./chap07/Listing_07_23_Expando.groovy
./chap07/Listing_07_24_GPath.groovy
./chap07/snippet0703_Implicit_Closure_To_SAM.groovy
./chap07/snippet0705_Spread_List.groovy
./chap07/snippet0705_Spread_Map.groovy
./chap07/snippet0705_Spread_Range.groovy
./chap07/thirdparty/MathLib.groovy
./chap07/thirdparty2/MathLib.groovy
./chap08/custom/Custom.groovy
./chap08/custom/useCustom.groovy
./chap08/failing_Listing_08_15_EMC_static.groovy
./chap08/failing_Listing_08_16_EMC_super.groovy
./chap08/groovy/runtime/metaclass/custom/CustomMetaClass.groovy
./chap08/Listing_08_01_method_missing.groovy
./chap08/Listing_08_02_mini_gorm.groovy
./chap08/Listing_08_03_property_missing.groovy
./chap08/Listing_08_04_bin_property.groovy
./chap08/Listing_08_05_closure_dynamic.groovy
./chap08/Listing_08_06_property_method.groovy
./chap08/Listing_08_07_MetaClass_jdk7_only.groovy
./chap08/Listing_08_07_MetaClass_jdk8_plus.groovy
./chap08/Listing_08_08_ProxyMetaClass.groovy
./chap08/Listing_08_09_Expando.groovy
./chap08/Listing_08_10_EMC.groovy
./chap08/Listing_08_11_EMC_Groovy_Class.groovy
./chap08/Listing_08_12_EMC_Groovy_Object.groovy
./chap08/Listing_08_13_EMC_Java_Object.groovy
./chap08/Listing_08_14_EMC_Builder.groovy
./chap08/Listing_08_15_EMC_static.groovy
./chap08/Listing_08_16_EMC_super.groovy
./chap08/Listing_08_17_EMC_hooks.groovy
./chap08/Listing_08_18_Existing_Categories.groovy
./chap08/Listing_08_19_Marshal.groovy
./chap08/Listing_08_20_MarshalCategory.groovy
./chap08/Listing_08_21_Test_Mixin.groovy
./chap08/Listing_08_22_Sieve_Mixin.groovy
./chap08/Listing_08_23_Millimeter.groovy
./chap08/Listing_08_24_create_factory.groovy
./chap08/Listing_08_25_fake_assign.groovy
./chap08/Listing_08_26_restore_emc.groovy
./chap08/Listing_08_27_intercept_cache_invoke.groovy
./chap08/markup.html
./chap09/gradlew.bat
./chap09/Listing_09_01_ToStringDetective.groovy
./chap09/Listing_09_02_ToStringSleuth.groovy
./chap09/Listing_09_03_EqualsAndHashCode.groovy
./chap09/Listing_09_04_TupleConstructor.groovy
./chap09/Listing_09_05_Lazy.groovy
./chap09/Listing_09_06_IndexedProperty.groovy
./chap09/Listing_09_07_InheritConstructors.groovy
./chap09/Listing_09_08_Sortable.groovy
./chap09/Listing_09_09_Builder.groovy
./chap09/Listing_09_10_Canonical.groovy
./chap09/Listing_09_11_Immutable.groovy
./chap09/Listing_09_12_Delegate.groovy
./chap09/Listing_09_13_Singleton.groovy
./chap09/Listing_09_14_Memoized.groovy
./chap09/Listing_09_15_TailRecursive.groovy
./chap09/Listing_09_16_Log.groovy
./chap09/Listing_09_17_Synchronized.groovy
./chap09/Listing_09_18_SynchronizedCustomLock.groovy
./chap09/Listing_09_19_ReadWriteLock.groovy
./chap09/Listing_09_20_AutoClone.groovy
./chap09/Listing_09_21_AutoCloneCopyConstructor.groovy
./chap09/Listing_09_22_AutoExternalize.groovy
./chap09/Listing_09_23_TimedInterrupt.groovy
./chap09/Listing_09_24_ThreadInterrupt.groovy
./chap09/Listing_09_25_ConditionalInterrupt.groovy
./chap09/Listing_09_26_Field.groovy
./chap09/Listing_09_27_BaseScript.groovy
./chap09/Listing_09_28_AstByHand.groovy
./chap09/Listing_09_29_AstByHandWithUtils.groovy
./chap09/Listing_09_30_AstBuildFromSpec.groovy
./chap09/Listing_09_31_AstBuildFromString.groovy
./chap09/Listing_09_32_AstBuildFromStringMixed.groovy
./chap09/Listing_09_33_AstBuildFromCode.groovy
./chap09/Listing_09_34_GreeterMainTransform.groovy
./chap09/Listing_09_35_GreeterMainTransform2.groovy
./chap09/Listing_09_38_AstTesting1.groovy
./chap09/Listing_09_39_AstTesting2.groovy
./chap09/Listing_09_40_AstTesting3.groovy
./chap09/Listing_09_41_AstTesting4.groovy
./chap09/Listing_09_42_AstTesting5.groovy
./chap09/Listings.txt
./chap09/settings.gradle
./chap09/snippet0902_autoCloneDefault.txt
./chap09/snippet0902_autoCloneSerialization.txt
./chap09/snippet0902_autoExternalize.txt
./chap09/snippet0902_fieldEquivalent.txt
./chap09/snippet0902_mapCreation.txt
./chap09/snippet0902_noisySetDelegateByHand.txt
./chap09/snippet0902_noisySetInheritance.txt
./chap09/snippet0902_nonTailCallReverseList.txt
./chap09/snippet0902_readWriteByHand.txt
./chap09/snippet0902_readWriteLock.txt
./chap09/snippet0902_singletonByHand.txt
./chap09/snippet0902_toStringEquivalent.txt
./chap09/snippet0903_greeterExpanded.txt
./chap09/snippet0903_greeterScript.txt
./chap09/snippet0903_localMain.txt
./chap09/snippet0903_localMainTransformation.txt
./chap09/snippet0905_GetCompiledTimeScript.txt
./chap09/src/main/groovy/regina/CompiledAtASTTransformation.groovy
./chap09/src/test/groovy/regina/CompiledAtASTTransformationTest.groovy
./chap10/extra1004_JavaDispatch.java
./chap10/extra1004_RuntimeGroovyDispatch.groovy
./chap10/Greeter.java
./chap10/Listing_10_01_Duck.groovy
./chap10/Listing_10_02_failing_Typo.groovy
./chap10/Listing_10_03_ClassTC.groovy
./chap10/Listing_10_04_OneMethodTC.groovy
./chap10/Listing_10_05_CompileTimeTypo.groovy
./chap10/Listing_10_06_MethodNameTypo.groovy
./chap10/Listing_10_07_MethodArgsFlipped.groovy
./chap10/Listing_10_08_InvalidAssignments.groovy
./chap10/Listing_10_09_AssignmentsWithCoercion.groovy
./chap10/Listing_10_10_DefField.groovy
./chap10/Listing_10_11_InPlaceList.groovy
./chap10/Listing_10_12_Generics.groovy
./chap10/Listing_10_13_ListStyleCtorRuntime.groovy
./chap10/Listing_10_14_ListStyleCtorTC.groovy
./chap10/Listing_10_15_MapStyleCtorBad.groovy
./chap10/Listing_10_16_ListStyleCtor.groovy
./chap10/Listing_10_17_ListStyleCtorFixed.groovy
./chap10/Listing_10_18_CodeAsData.groovy
./chap10/Listing_10_19_ClosuresBadReturnType.groovy
./chap10/Listing_10_20_UserValidation.groovy
./chap10/Listing_10_21_UserValidationTC.groovy
./chap10/Listing_10_22_UserValidation_ExplicitTypes.groovy
./chap10/Listing_10_23_UserValidation_SAM.groovy
./chap10/Listing_10_24_UserValidation_ClosureParams.groovy
./chap10/Listing_10_25_UserValidation_DSL.groovy
./chap10/Listing_10_26_UserValidation_DelegatesTo.groovy
./chap10/Listing_10_27_UserValidation_DelegatesToTarget.groovy
./chap10/Listing_10_28_Category.groovy
./chap10/Listing_10_29_EMC.groovy
./chap10/Listing_10_30_Builder.groovy
./chap10/Listing_10_31_MixedTypeChecking.groovy
./chap10/Listing_10_32_Skip.groovy
./chap10/Listing_10_33_FlowTyping.groovy
./chap10/Listing_10_34_FlowTypingOk.groovy
./chap10/Listing_10_35_LUB.groovy
./chap10/Listing_10_36_Condition.groovy
./chap10/Listing_10_37_ClosureSharedVar.groovy
./chap10/Listing_10_38_LubError.groovy
./chap10/Listing_10_39_LubOk.groovy
./chap10/Listing_10_41_FibBench.groovy
./chap10/Listing_10_41_JavaGreeter.txt
./chap10/Listing_10_42_StaticCompileDispatch.groovy
./chap10/Listing_10_43_MonkeyPatching.groovy
./chap10/Listing_10_44_BookingDSL.groovy
./chap10/Listing_10_45_MultiValidation.groovy
./chap10/Listing_10_46_RobotExtension.groovy
./chap10/Listing_10_47_SQLExtension.groovy
./chap10/markup.html
./chap10/snippet1003_GroovyGreeter.groovy
./chap10/snippet1005_RobotMainTC.groovy
./chap10/snippet1005_SqlMainTC.groovy
./chap10/User.groovy
./chap11/Listing_11_01_SquaresFactors.xml
./chap11/Listing_11_02_SquaresFactors.java
./chap11/Listing_11_03_MarkupBuilderPlain.groovy
./chap11/Listing_11_04_NodeBuilder.groovy
./chap11/Listing_11_05_NodeBuilderLogic.groovy
./chap11/Listing_11_06_MarkupBuilderLogic.groovy
./chap11/Listing_11_07_MarkupBuilderHtml.groovy
./chap11/Listing_11_08_StreamingMarkupBuilderLogic.groovy
./chap11/Listing_11_09_ExampleBuild.xml
./chap11/Listing_11_10_PW_SwingBuilder.groovy
./chap11/Listing_11_11_Swing_Widgets.groovy
./chap11/Listing_11_12_Swing_Layout.groovy
./chap11/Listing_11_13_Table_Demo.groovy
./chap11/Listing_11_14_Binding.groovy
./chap11/Listing_11_15_Plotter.groovy
./chap11/Listing_11_16_Groovyfx.groovy
./chap11/Listing_11_17_CalorieCounterBuilderSupport.groovy
./chap11/Listing_11_18_CalorieCounterFactoryBuilderSupport.groovy
./chap11/Listing_11_19_CalorieCounterByHand.groovy
./chap11/markup.html
./chap11/snippet1103_MarkupBuilderOutput.html
./chap11/snippet1103_MarkupWithHyphen.groovy
./chap11/snippet1106_AntBuilderIf.groovy
./chap11/snippet1106_AntIf.xml
./chap11/snippet1107_binding.txt
./chap11/snippet1107_Printer.groovy
./chap12/data/example.txt
./chap12/Listing_12_01_info_jdk6_only.groovy
./chap12/Listing_12_01_info_jdk7_only.groovy
./chap12/Listing_12_01_info_jdk8_plus.groovy
./chap12/Listing_12_02_properties.groovy
./chap12/Listing_12_03_File_Iteration.groovy
./chap12/Listing_12_04_Filesystem.groovy
./chap12/Listing_12_05_Traversal.groovy
./chap12/Listing_12_06_File_Read.groovy
./chap12/Listing_12_07_File_Write.groovy
./chap12/Listing_12_08_Writer_LeftShift.groovy
./chap12/Listing_12_09_File_Transform_jdk7_plus.groovy
./chap12/Listing_12_10_File_ObjectStreams.groovy
./chap12/Listing_12_11_Temp_Dir.groovy
./chap12/Listing_12_12_Threads.groovy
./chap12/Listing_12_13_Processes_UnixCommands.groovy
./chap12/Listing_12_14_Processes_ZipUnzip.groovy
./chap12/Listing_12_15_SimpleTemplateEngine.groovy
./chap12/Listing_12_16_GroovletExample.groovy
./chap12/Listing_12_17_HelloWorldGroovlet.groovy
./chap12/Listing_12_19_InspectGroovlet.groovy
./chap12/Listing_12_20_HiLowGame.groovy
./chap12/Listing_12_21_NumberTemplate.txt
./chap12/Listing_12_22_TemplateGroovlet.groovy
./chap12/Number.template.html
./chap12/snippet1201_SlowTyping.groovy
./chap12/snippet1201_UseCategory.groovy
./chap12/snippet1202_base64.groovy
./chap12/web.xml
./chap13/extra_NeoGremlinGraph.groovy
./chap13/layering/AthleteApplication.groovy
./chap13/layering/AthleteDAO.groovy
./chap13/layering/DataAccessObject.groovy
./chap13/layering/DbHelper.groovy
./chap13/Listing_13_01_Connecting.groovy
./chap13/Listing_13_02_ConnectingDataSource.groovy
./chap13/Listing_13_03_Creating.groovy
./chap13/Listing_13_04_Inserting.groovy
./chap13/Listing_13_05_Reading.groovy
./chap13/Listing_13_06_Updating.groovy
./chap13/Listing_13_07_Delete.groovy
./chap13/Listing_13_08_Transactions.groovy
./chap13/Listing_13_09_Batching.groovy
./chap13/Listing_13_10_Paging.groovy
./chap13/Listing_13_11_Metadata.groovy
./chap13/Listing_13_12_MoreMetadata.groovy
./chap13/Listing_13_13_NamedOrdinal.groovy
./chap13/Listing_13_14_StoredProcBasic.groovy
./chap13/Listing_13_15_StoredProcParam.groovy
./chap13/Listing_13_16_StoredProcInOut.groovy
./chap13/Listing_13_17_DataSetBasics.groovy
./chap13/Listing_13_18_DataSetFiltering.groovy
./chap13/Listing_13_19_DataSetViews.groovy
./chap13/Listing_13_20_DbHelper.txt
./chap13/Listing_13_21_DataAccessObject.txt
./chap13/Listing_13_22_AthleteDAO.txt
./chap13/Listing_13_23_AthleteApplication.txt
./chap13/Listing_13_24_AthleteAppMain.groovy
./chap13/Listing_13_25_AthleteAppTest.groovy
./chap13/Listing_13_26_MongoAthletes.groovy
./chap13/Listing_13_27_NeoAthletes.groovy
./chap13/Listing_13_28_NeoGremlin.groovy
./chap13/snippet1301_ConnectingWithGrab.groovy
./chap13/snippet1301_ConnectingWithInstance.groovy
./chap13/snippet1301_ConnectingWithMap.groovy
./chap13/snippet1301_ReadEachRow.groovy
./chap13/snippet1301_ReadEachRowList.groovy
./chap13/snippet1301_ReadQuery.groovy
./chap13/snippet1301_ReadRows.groovy
./chap13/util/DbUtil.groovy
./chap13/util/MarathonRelationships.groovy
./chap13/util/Neo4jUtil.groovy
./chap14/data/GroovyPlans.html
./chap14/data/GroovyPlans.template.html
./chap14/data/plan.json
./chap14/data/plan.xml
./chap14/data/StreamedGroovyPlans.html
./chap14/data/style.css
./chap14/data/XPathGroovyPlans.html
./chap14/Listing_14_01_Plan.txt
./chap14/Listing_14_02_DOM.groovy
./chap14/Listing_14_03_DOM_Category.groovy
./chap14/Listing_14_04_XmlParser.groovy
./chap14/Listing_14_05_XmlSlurper.groovy
./chap14/Listing_14_06_SAX.groovy
./chap14/Listing_14_07_StAX.groovy
./chap14/Listing_14_08_XmlBoiler.groovy
./chap14/Listing_14_09_XmlStreamer.groovy
./chap14/Listing_14_10_StreamedHtml.groovy
./chap14/Listing_14_11_UpdateDomCategory.groovy
./chap14/Listing_14_12_UpdateParser.groovy
./chap14/Listing_14_13_UpdateSlurper.groovy
./chap14/Listing_14_14_XPath.groovy
./chap14/Listing_14_15_GroovyPlansTemplate.txt
./chap14/Listing_14_16_XPathTemplate.groovy
./chap14/Listing_14_17_JsonParser.groovy
./chap14/Listing_14_18_JsonBuilder.groovy
./chap14/Listing_14_19_JsonBuilderLogic.groovy
./chap14/Listing_14_20_JsonOutputAthlete.groovy
./chap14/log4j.xml
./chap14/UpdateChecker.groovy
./chap15/data/conv.templ.xml
./chap15/Listing_15_01_RSS_bbcnews.groovy
./chap15/Listing_15_02_ATOM_devworks.groovy
./chap15/Listing_15_03_REST_jira_url.groovy
./chap15/Listing_15_04_REST_jira_httpb_get.groovy
./chap15/Listing_15_05_REST_currency_httpb_get.groovy
./chap15/Listing_15_06_REST_currency_httpb_post.groovy
./chap15/Listing_15_07_REST_currency_jaxrs.groovy
./chap15/Listing_15_08_REST_currency_jaxrs_proxy.groovy
./chap15/Listing_15_09_XMLRPC_echo.groovy
./chap15/Listing_15_10_XMLRPC_jira.groovy
./chap15/Listing_15_11_SOAP_wsdl.groovy
./chap15/Listing_15_12_SOAP11_currency_url.groovy
./chap15/Listing_15_13_SOAP12_currency_httpb.groovy
./chap15/Listing_15_14_SOAP11_currency_wslite.groovy
./chap15/Listing_15_15_SOAP12_currency_wslite.groovy
./chap16/HelloIntegrationWorld.java
./chap16/Listing_16_01_HelloIntegration.groovy
./chap16/Listing_16_02_HelloIntegrationJava.txt
./chap16/Listing_16_03_MultilineScript.groovy
./chap16/Listing_16_04_UsingEval.groovy
./chap16/Listing_16_05_Binding.groovy
./chap16/Listing_16_06_BindingTwoWay.groovy
./chap16/Listing_16_07_ClassInScript.groovy
./chap16/Listing_16_08_Payment_calculator.groovy
./chap16/Listing_16_09_MethodsInBinding.groovy
./chap16/Listing_16_10_ShapeInfoMain.txt
./chap16/Listing_16_11_SpringConfig.txt
./chap16/Listing_16_12_BeanToString.groovy
./chap16/shapes/Circle.groovy
./chap16/shapes/MaxAreaInfo.groovy
./chap16/shapes/MaxPerimeterInfo.java
./chap16/shapes/Shape.java
./chap16/shapes/ShapeInfo.java
./chap16/shapes/ShapeInfoMain.java
./chap16/shapes/Square.java
./chap16/spring/common/Shape.java
./chap16/spring/common/ShapeInfo.java
./chap16/spring/groovy/Circle.groovy
./chap16/spring/groovy/MaxAreaInfo.groovy
./chap16/spring/java/MaxPerimeterInfo.java
./chap16/spring/java/ShapeInfoFactoryMain.java
./chap16/spring/java/ShapeInfoMain.java
./chap16/spring/java/ShapeInfoSpringMain.java
./chap16/spring/java/Square.java
./chap16/spring/resources/beans.xml
./chap17/automation/src/main/groovy/Calculator.groovy
./chap17/automation/src/test/groovy/CalculatorTest.groovy
./chap17/cobertura/src/main/groovy/BiggestPairCalc.groovy
./chap17/cobertura/src/main/groovy/BiggestPairCalcFixed.groovy
./chap17/cobertura/src/test/groovy/BiggestPairCalcTest.groovy
./chap17/Converter.groovy
./chap17/Counter.groovy
./chap17/extra_ParameterizedTestNG.groovy
./chap17/extra_TestNG.groovy
./chap17/Farm.groovy
./chap17/Listing_17_01_Celsius.groovy
./chap17/Listing_17_02_CounterTest.groovy
./chap17/Listing_17_03_HashMapTest.groovy
./chap17/Listing_17_04_GroovyTestSuite.groovy
./chap17/Listing_17_05_AllTestSuite.groovy
./chap17/Listing_17_06_DataDrivenJUnitTest.groovy
./chap17/Listing_17_07_PropertyBased.groovy
./chap17/Listing_17_08_Balancer.groovy
./chap17/Listing_17_09_BalancerStub.groovy
./chap17/Listing_17_10_BalancerMock.groovy
./chap17/Listing_17_11_LoggingCounterTest.groovy
./chap17/Listing_17_12_JUnitPerf.groovy
./chap17/Listing_17_13_SpockSimple.groovy
./chap17/Listing_17_14_SpockMock.groovy
./chap17/Listing_17_15_SpockMockWildcards.groovy
./chap17/Listing_17_16_SpockMockClosureChecks.groovy
./chap17/Listing_17_17_SpockDataDriven.groovy
./chap17/LoggingCounter.groovy
./chap17/MovieTheater.groovy
./chap17/Purchase.groovy
./chap17/snippet1701_JUnit4.groovy
./chap17/snippet1704_listPropertyCheck.groovy
./chap18/Listing_18_01_ConcurrentSquares.groovy
./chap18/Listing_18_02_ConcurrentSquaresTransparent.groovy
./chap18/Listing_18_03_ConcurrentSquaresTransitive.groovy
./chap18/Listing_18_04_MapFilterReduce.groovy
./chap18/Listing_18_05_SquaresMapReduce.groovy
./chap18/Listing_18_06_Dataflow.groovy
./chap18/Listing_18_07_DataflowStreams.groovy
./chap18/Listing_18_08_Actors.groovy
./chap18/Listing_18_09_ActorsLifecycle.groovy
./chap18/Listing_18_10_ActorsMessageAware.groovy
./chap18/Listing_18_11_Agent.groovy
./chap18/Listing_18_12.txt
./chap18/Listing_18_13_YahooForkJoin.groovy
./chap18/Listing_18_14_YahooMapReduce.groovy
./chap18/Listing_18_15_YahooDataflow.groovy
./chap18/snippet1801_startThread.groovy
./chap18/snippet1803_java_parallel_streams_jdk8_only.groovy
./chap18/snippet1804_deadlock.groovy
./chap18/snippet1804_nondeterministic.groovy
./chap18/YahooService.groovy
./chap19/extra_19_41_FetchOptions.groovy
./chap19/FetchOptions.groovy
./chap19/FetchOptionsBuilder.groovy
./chap19/Listing_19_06_Binding.groovy
./chap19/Listing_19_29_OrderDSL.groovy
./chap19/Listing_19_30_WhenIfControlStructure.groovy
./chap19/Listing_19_31_Until_failing_.groovy
./chap19/Listing_19_32_UntilControlStructure.groovy
./chap19/Listing_19_38_GivenWhenThen.groovy
./chap19/Listing_19_42_FetchOptionsScript.groovy
./chap19/Listing_19_43_RubyStyleNewify.groovy
./chap19/Listing_19_44_PythonStyleNewify.groovy
./chap19/Listing_19_45_Terms.groovy
./chap19/Listing_19_46_NewifyInjected.txt
./chap19/Listing_19_47_No_IO.groovy
./chap19/Listing_19_48_ArithmeticShell.groovy
./chap19/Listing_19_49_TimedInterrupt.groovy
./chap19/Listing_19_50_SystemExitGuard.groovy
./chap19/Listing_19_52_QueryCustomizer.groovy
./chap19/Listings.txt
./chap19/Query.groovy
./chap19/v01/Listing_19_01_SelfContainedScript.groovy
./chap19/v02/integration/CaseRobotBaseScript.groovy
./chap19/v02/integration/CustomBinding.groovy
./chap19/v02/integration/RobotBaseScript.groovy
./chap19/v02/Listing_19_04_MainSimple.groovy
./chap19/v02/Listing_19_05_MainGroovyShell.groovy
./chap19/v02/Listing_19_07_MainBinding.groovy
./chap19/v02/Listing_19_08_MainDirectionConstants.groovy
./chap19/v02/Listing_19_09_MainDirectionsSpread.groovy
./chap19/v02/Listing_19_10_MainImplicitMethod.groovy
./chap19/v02/Listing_19_12_MainBaseScript.groovy
./chap19/v02/Listing_19_13_MainImportCustomizer.groovy
./chap19/v02/Listing_19_14_MainCustomBaseScriptClass.groovy
./chap19/v02/Listing_19_16_MainMethodClosure.groovy
./chap19/v02/Listing_19_19_MainLowerCase.groovy
./chap19/v02/model/Direction.groovy
./chap19/v02/model/Robot.groovy
./chap19/v02/snippet1901_MainFileRunner.groovy
./chap19/v03/integration/DistanceCategory.groovy
./chap19/v03/integration/RobotBaseScript.groovy
./chap19/v03/integration/SuperBotBaseScript.groovy
./chap19/v03/Listing_19_27_SimpleCommandChain.groovy
./chap19/v03/Listing_19_39_Robot_With.groovy
./chap19/v03/model/Direction.groovy
./chap19/v03/model/Distance.groovy
./chap19/v03/model/Duration.groovy
./chap19/v03/model/Robot.groovy
./chap19/v03/model/Speed.groovy
./chap19/v03/model/SuperBot.groovy
./chap19/v03/model/Unit.groovy
./chap19/xform/BusinessLogicScript.groovy
./chap19/xform/CustomControlStructure.groovy
./chap19/xform/extra_WhenTransformationWorksWithoutBraces.groovy
./chap19/xform/Listing_19_36_WhenTransformation.groovy
./chap19/xform/snippet1906_WhenUntilXform_Structure.groovy
./chap19/xform/WhenUntilTransform.groovy
./chap20/Listing_20_01_Grapes_for_twitter_urls.groovy
./chap20/Listing_20_02_Scriptom_Windows_only.groovy
./chap20/Listing_20_03_ActivX_Windows_only.groovy
./chap20/Listing_20_10_SquaringMapValue.groovy
./chap20/Listing_20_11_Synchronized.groovy
./chap20/Listing_20_12_DbC_invariants.groovy
================================================
FILE: listings/appD/Listing_D_01_GStrings.groovy
================================================
// normal use
def g1 = "1 + 1 equals ${1 + 1}"
assert g1 == '1 + 1 equals 2'
assert g1 instanceof CharSequence
assert g1 instanceof GString
def x = 10
def g2 = "$x" // reference
assert g2 == "10"
def g3 = "${x}" // expression
assert g3 == "10"
// lazy evaluation with a writeable closure!
def g4 = "${ -> x}" // closure
x = 20 // value change after definition
assert g4 == "20" // lazy evaluation!
================================================
FILE: listings/appD/Listing_D_02_Lists.groovy
================================================
assert [1,2,3,4] == (1..4)
assert [1,2,3] + [1] == [1,2,3,1]
assert [1,2,3] << 1 == [1,2,3,1]
assert [1,2,3,1] - [1] == [2,3]
assert [1,2,3] * 2 == [1,2,3,1,2,3]
assert [1,[2,3]].flatten() == [1,2,3]
assert [1,2,3].reverse() == [3,2,1]
assert [1,2,3].disjoint([4,5,6])
assert [1,2,3].intersect([4,3,1]) == [3,1]
assert [1,2,3].collect{ it+3 } == [4,5,6]
assert [1,2,3,1].unique().size() == 3
assert [1,2,3,1].count(1) == 2
assert [1,2,3,4].min() == 1
assert [1,2,3,4].max() == 4
assert [1,2,3,4].sum() == 10
assert [4,2,1,3].sort() == [1,2,3,4]
assert [4,2,1,3].findAll{ it%2 == 0 } == [4,2]
def animals = ['cat','kangaroo','koala','dog']
assert animals[2] == 'koala'
def kanimals = animals[1..2]
assert animals.findAll{ it =~ /k.*/ } == kanimals
assert animals.find{ it =~ /k.*/ } == kanimals[0]
assert animals.grep(~/k.*/) == kanimals
// parallel assignment as swap
def a = 1, b = 2
(a, b) = [b, a]
assert a == 2
assert b == 1
// lesser known methods
assert animals.sort { it.size() } == ['cat', 'dog', 'koala', 'kangaroo']
assert animals.max { it.size() } == 'kangaroo'
assert animals.groupBy { it.size() } == [ 3:['cat','dog'], 5:['koala'], 8:['kangaroo'] ]
assert [1,2,3].permutations().toList() == [
[1, 2, 3], [2, 3, 1], [3, 2, 1], [3, 1, 2], [2, 1, 3], [1, 3, 2]
]
assert (1..10).collate(3) == [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
def matrix = [
['a', 'b'],
[ 1 , 2 ]
]
assert matrix.transpose() == [ ['a', 1], ['b', 2] ]
assert matrix.combinations() == [ ['a', 1], ['b', 1], ['a', 2], ['b', 2] ]
================================================
FILE: listings/appD/Listing_D_03_Closures.groovy
================================================
def add = { x, y -> x + y }
def mult = { x, y -> x * y }
assert add(1,3) == 4
assert mult(1,3) == 3
def min = { x, y -> [x,y].min() }
def max = { x, y -> [x,y].max() }
def atLeastTen = max.curry(10)
assert atLeastTen(5) == 10
assert atLeastTen(15) == 15
def pairWise(list, Closure invoke) {
if (list.size() < 2) return []
def next = invoke(list[0],list[1])
return [next] + pairWise(list[1..-1], invoke)
}
assert pairWise(1..5, add) == [3, 5, 7, 9]
assert pairWise(1..5, mult) == [2, 6, 12, 20]
assert pairWise(1..5, min) == [1, 2, 3, 4]
assert pairWise(1..5, max) == [2, 3, 4, 5]
assert 'cbaxabc' == ['a','b','c'].inject('x') {
result, item -> item + result + item
}
assert [1,2,3].grep{ it<3 } == [1,2]
assert [1,2,3].any{ it%2 == 0 }
assert [1,2,3].every{ it<4 }
assert (1..9).collect{it}.join() == '123456789'
assert (1..4).collect{it*2}.join() == '2468'
================================================
FILE: listings/appD/Listing_D_04_Regex.groovy
================================================
def twister = 'she sells sea shells by the sea shore'
// contains word 'shore'
assert twister =~ 'shore'
// contains 'sea' twice (two ways)
assert (twister =~ 'sea').count == 2
assert twister.split(/ /).grep(~/sea/).size() == 2
// words that start with 'sh', \b = word boundary
def shwords = (twister =~ /sh[a-z]*\b/).collect{it}.join(' ')
assert shwords == 'she shells shore'
// sh-words by parallel assignment
def (a, b, c) = twister =~ /sh[a-z]*\b/
assert a == 'she'
assert b == 'shells'
assert c == 'shore'
// four words have three letter, \S = non-Space letter
assert (twister =~ /\b\S{3}\b/).count == 4
// three words start with 's' and have 4, 5, or 6 letters
assert (twister =~ /\bs\S{4}\S?\b/).count == 3
// replace words with 'X', \w = word character
assert twister.replaceAll(/\w+/,'X') == 'X X X X X X X X'
// starts with 'she' and ends with 'shore'
def pattern = ~/she.*shore/
assert pattern.matcher(twister).matches()
// replace 'sea' with 'ocean' but only if preceded by word 'the'
def ocean = twister.replaceAll('(?<=the )sea','ocean')
assert ocean == 'she sells sea shells by the ocean shore'
// swap 1st and 2nd pairs of words
def pairs = twister =~ /(\S+) (\S+) ?/
assert pairs.hasGroup()
twister = [1, 0, 2, 3].collect{ pairs[it][0] }.join()
assert twister == 'sea shells she sells by the sea shore'
================================================
FILE: listings/appD/Listing_D_05_GPath.groovy
================================================
import groovy.xml.dom.DOMCategory
def recipeXml = '''
<recipe>
<ingredients>
<ingredient amount='2 cups'>Self-raising Flour</ingredient>
<ingredient amount='2 tablespoons'>Icing sugar</ingredient>
<ingredient amount='2 tablespoons'>Butter</ingredient>
<ingredient amount='3/4 - 1 cup'>Milk</ingredient>
</ingredients>
<steps>
<step>Preheat oven to 230 degrees celsius</step>
<step>Sift flour and icing sugar into a bowl</step>
<step>Melt butter and mix into dry ingredients</step>
<step>Gradually add milk to the mixture until moist</step>
<step>Turn onto floured board and cut into portions</step>
<step>Bake for 15 minutes</step>
<step>Serve with jam and whipped cream</step>
</steps>
</recipe>
'''
def recipe = new XmlSlurper().parseText(recipeXml)
assert 4 == recipe.ingredients.ingredient.size()
// should be 14 elements in total
assert 14 == recipe.'**'.findAll{true}.size()
// step 4 (index 3 because we start from 0) involves milk
assert recipe.steps.step[3].text().contains('milk')
assert '2 cups' == recipe.ingredients.ingredient[0].'@amount'.toString()
// two ingredients have '2 tablespoons' amount attribute
def ingredients = recipe.ingredients.ingredient.grep{
it.'@amount' == '2 tablespoons'
}
assert ingredients.size() == 2
// every step has at least 4 words
assert recipe.steps.step.every{
step -> step.text().tokenize(' ').size() >= 4
}
def recipe2 = new XmlParser().parseText(recipeXml)
/* … processing steps … */
def reader = new StringReader(recipeXml)
def doc = groovy.xml.DOMBuilder.parse(reader)
def recipe3 = doc.documentElement
use (groovy.xml.dom.DOMCategory) {
/* … processing steps … */
}
================================================
FILE: listings/chap01/Listing_01_01_Gold.groovy
================================================
List fibo = [1, 1] //#A
List gold = [1, 2] //#B
while ( ! isGolden( gold[-1] ) ) { //#C
fibo.add( fibo[-1] + fibo[-2] ) //#D
gold.add( fibo[-1] / fibo[-2] ) //#E
}
println "found golden ratio with fibo(${ fibo.size-1 }) as"
println fibo[-1] + " / " + fibo[-2] + " = " + gold[-1]
println "_" * 10 + "|" + "_" * (10 * gold[-1])
def isGolden(candidate) { //#F
def small = 1 //#G
def big = small * candidate //#H
return isCloseEnough( (small+big)/big, big/small)
}
def isCloseEnough(a,b) { return (a-b).abs() < 1.0e-9 }
//#A Initial Fibonacci numbers
//#B Golden ration candidates
//#C Last gold candidate
//#D Next fibo number
//#E Next golden candidate
//#F Candidate satisfies golden rule
//#G Smaller section
//#H Bigger section
================================================
FILE: listings/chap01/customers.xml
================================================
<?xml version="1.0" ?>
<customers>
<corporate>
<customer name="Bill Gates" company="Microsoft" />
<customer name="Tim Cook" company="Apple" />
<customer name="Larry Ellison" company="Oracle" />
</corporate>
<consumer>
<customer name="John Doe" />
<customer name="Jane Doe" />
</consumer>
</customers>
================================================
FILE: listings/chap01/data.txt
================================================
first line
second line
================================================
FILE: listings/chap01/groovysh.txt
================================================
Groovy Shell (2.4.0, JVM: 1.7.0_75)
Type ':help' or ':h' for help.
--------------------------------------------------------------------
groovy:000> "Welcome, " + System.properties."user.name"
===> Welcome, Dierk
groovy:000>
================================================
FILE: listings/chap01/snippet0101_customers.groovy
================================================
def customers = new XmlSlurper().parse(new File('customers.xml'))
for (customer in customers.corporate.customer) {
println "${customer.@name} works for ${customer.@company}"
}
================================================
FILE: listings/chap01/snippet0101_fileLineNumbers.groovy
================================================
def number = 0
new File('data.txt').eachLine { line ->
number++
println "$number: $line"
}
================================================
FILE: listings/chap01/snippet0101_newDates.txt
================================================
import java.util.*; // Java
Date today = new Date(); // Java
today = new Date() // Groovy
require 'date' # Ruby
today = Date.new # Ruby
import java.util._ // Scala
var today = new Date // Scala
(import '(java.util Date)) ; Clojure
(def today (new Date)) ; Clojure
(def today (Date.)) ; Clojure alternative
================================================
FILE: listings/chap01/snippet0101_printPackageNames.groovy
================================================
def classes = [String, List, File]
for (clazz in classes) {
println clazz.package.name
}
================================================
FILE: listings/chap01/snippet0101_printPackageNamesGpath.groovy
================================================
println( [String, List, File]*.package*.name )
================================================
FILE: listings/chap01/snippet0102_printGroovyWebSiteCount.groovy
================================================
import static groovyx.gpars.GParsPool.withPool
def urls = [
'http://www.groovy-lang.org',
'http://gpars.codehaus.org',
'http://gr8conf.org/'
]*.toURL()
println withPool {
urls.collectParallel {
it.text.findAll(~/[Gg]roovy/).size()
}
}
================================================
FILE: listings/chap01/snippet0103_googleIpAdr.groovy
================================================
InetAddress.getAllByName("google.com").collect {
it.toString().split('/')[1]
}
================================================
FILE: listings/chap02/Book.groovy
================================================
class Book {
private String title
Book (String theTitle) {
title = theTitle
}
String getTitle(){
return title
}
}
================================================
FILE: listings/chap02/Listing_02_01_Assertions.groovy
================================================
assert(true)
assert 1 == 1
def x = 1
assert x == 1
def y = 1 ; assert y == 1
================================================
FILE: listings/chap02/Listing_02_02_Book.txt
================================================
see Book.groovy
================================================
FILE: listings/chap02/Listing_02_03_BookScript.groovy
================================================
Book gina = new Book('Groovy in Action')
assert gina.getTitle() == 'Groovy in Action'
assert getTitleBackwards(gina) == 'noitcA ni yvoorG'
String getTitleBackwards(book) {
String title = book.getTitle()
return title.reverse()
}
================================================
FILE: listings/chap02/Listing_02_04_BookBean.groovy
================================================
class BookBean {
String title //#A
}
def groovyBook = new BookBean()
groovyBook.setTitle('Groovy in Action') //#B
assert groovyBook.getTitle() == 'Groovy in Action' //#B
groovyBook.title = 'Groovy conquers the world' //#C
assert groovyBook.title == 'Groovy conquers the world' //#C
//#A Property declaration
//#B Property use with explicit getter calls
//#C Property use with Groovy shortcuts
================================================
FILE: listings/chap02/Listing_02_05_ImmutableBook.groovy
================================================
import groovy.transform.Immutable
@Immutable class FixedBook { //#A
String title
}
def gina = new FixedBook('Groovy in Action') //#B
def regina = new FixedBook(title:'Groovy in Action') //#C
assert gina.title == 'Groovy in Action'
assert gina == regina //#D
try {
gina.title = "Oops!" //#E
assert false, "should not reach here"
} catch (ReadOnlyPropertyException expected) {
println "Expected Error: '$expected.message'"
}
//#A AST annotation
//#B Positional constructor
//#C Named-arg constructor
//#D Standard equals()
//#E Not allowed!
================================================
FILE: listings/chap02/Listing_02_06_Grab.groovy
================================================
@Grab('commons-lang:commons-lang:2.4')
import org.apache.commons.lang.ClassUtils
class Outer {
class Inner {}
}
assert !ClassUtils.isInnerClass(Outer)
assert ClassUtils.isInnerClass(Outer.Inner)
================================================
FILE: listings/chap02/Listing_02_07_Clinks.groovy
================================================
def totalClinks = 0
def partyPeople = 100
1.upto(partyPeople) { guestNumber ->
clinksWithGuest = guestNumber-1
totalClinks += clinksWithGuest //#A
}
assert totalClinks == (partyPeople * (partyPeople-1)) / 2
//#A Modifies outer scope
================================================
FILE: listings/chap02/Listing_02_08_ControlStructures.groovy
================================================
if (false) assert false //#A
if (null) //#B
{ //#C
assert false
}
else
{
assert true
}
def i = 0 //#D
while (i < 10) { //#D
i++ //#D
} //#D
assert i == 10 //#D
def clinks = 0 //#E
for (remainingGuests in 0..9) { //#E
clinks += remainingGuests //#E
} //#E
assert clinks == (10*9)/2 //#E
def list = [0, 1, 2, 3] //#F
for (j in list) { //#F
assert j == list[j] //#F
} //#F
list.each() { item -> //#G
assert item == list[item] //#G
} //#G
switch(3) { //#H
case 1 : assert false; break //#H
case 3 : assert true; break //#H
default: assert false //#H
} //#H
//#A The if as one-liner
//#B Null is false
//#C Blocks may start on new line
//#D Classic while
//#E The for in range
//#F The for in list
//#G The each method with a closure
//#H Class switch
================================================
FILE: listings/chap02/snippet0201_comments.groovy
================================================
#!/usr/bin/env groovy
// some line comment
/* some multi-
line comment */
================================================
FILE: listings/chap02/snippet0202_failing_assert.groovy
================================================
def a = 5
def b = 9
assert b == a + a //#A
//#A expected to fail
================================================
FILE: listings/chap02/snippet0202_failing_assertion_error.txt
================================================
Assertion failed:
assert b == a + a //#A
| | | | |
9 | 5 | 5 //#B
| 10 //#C
false //#C
at snippet22_failing_assert.run(snippet22_failing_assert.groovy:3)
#A Expression is retained
#B Referenced values
#C Subexpression values
================================================
FILE: listings/chap02/snippet0203_clinks_java.groovy
================================================
// Java snippet
int totalClinks = 0;
int partyPeople = 100;
for(int guestNumber = 1;
guestNumber <= partyPeople;
guestNumber++) {
int clinksWithGuest = guestNumber-1;
totalClinks += clinksWithGuest;
}
================================================
FILE: listings/chap02/snippet0203_gstring.groovy
================================================
def nick = 'ReGina'
def book = 'Groovy in Action, 2nd ed.'
assert "$nick is $book" == 'ReGina is Groovy in Action, 2nd ed.'
================================================
FILE: listings/chap02/snippet0203_int_usage.groovy
================================================
def x = 1
def y = 2
assert x + y == 3
assert x.plus(y) == 3
assert x instanceof Integer
================================================
FILE: listings/chap02/snippet0203_map_usage.groovy
================================================
def http = [
100 : 'CONTINUE',
200 : 'OK',
400 : 'BAD REQUEST'
]
assert http[200] == 'OK'
http[500] = 'INTERNAL SERVER ERROR'
assert http.size() == 4
================================================
FILE: listings/chap02/snippet0203_range_usage.groovy
================================================
def x = 1..10
assert x.contains(5)
assert !x.contains(15)
assert x.size() == 10
assert x.from == 1
assert x.to == 10
assert x.reverse() == 10..1
================================================
FILE: listings/chap02/snippet0203_roman.groovy
================================================
def roman = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII'] //#A
assert roman[4] == 'IV' //#B
roman[8] = 'VIII' //#C
assert roman.size() == 9
//#A List of Roman numerals
//#B List access
//#C List expansion
================================================
FILE: listings/chap02/snippet0204_evaluate_jdk7_only.groovy
================================================
//java.class.version
//jdk5=49.0
//jdk6=50.0
//jdk7=51.0
//jdk8=52.0
def code = '1 + '
code += System.getProperty('java.class.version')
assert code == '1 + 51.0'
assert 52.0 == evaluate(code)
================================================
FILE: listings/chap02/snippet0204_evaluate_jdk8_only.groovy
================================================
//java.class.version
//jdk5=49.0
//jdk6=50.0
//jdk7=51.0
//jdk8=52.0
def code = '1 + '
code += System.getProperty('java.class.version')
assert code == '1 + 52.0'
assert 53.0 == evaluate(code)
================================================
FILE: listings/chap02/snippet0204_failing_typechecked.groovy
================================================
class Universe {
@groovy.transform.TypeChecked
int answer() { "forty two" }
}
println new Universe().answer()
================================================
FILE: listings/chap03/ArrayListSummer.java
================================================
public class ArrayListSummer {
public static void main(String[] args) {
// (60 * 60 * 24 * 365).toString();
int secondsPerYear = 60 * 60 * 24 * 365;
// secondsPerYear.toString();
new Integer(secondsPerYear).toString();
}
}
================================================
FILE: listings/chap03/Listing_03_01_PrimitiveMethodsObjectOperators.groovy
================================================
(60 * 60 * 24 * 365).toString(); // invalid Java
int secondsPerYear = 60 * 60 * 24 * 365;
secondsPerYear.toString(); // invalid Java
new Integer(secondsPerYear).toString();
assert "abc" - "a" == "bc" // invalid Java
================================================
FILE: listings/chap03/Listing_03_02_ListMapCast.groovy
================================================
import java.awt.*
Point topLeft = new Point(0, 0) // classic
Point botRight = [100, 100] // List cast
Point center = [x:50, y:50] // Map cast
assert botRight instanceof Point
assert center instanceof Point
def rect = new Rectangle()
rect.location = [0, 0] // Point
rect.size = [width:100, height:100] // Dimension
================================================
FILE: listings/chap03/Listing_03_03_DefiningOperators.groovy
================================================
import groovy.transform.Immutable
@Immutable //#1
class Money {
int amount
String currency
Money plus (Money other) { //#2
if (null == other) return this
if (other.currency != currency) {
throw new IllegalArgumentException(
"cannot add $other.currency to $currency")
}
return new Money(amount + other.amount, currency)
}
}
Money buck = new Money(1, 'USD')
assert buck
assert buck == new Money(1, 'USD') //#3
assert buck + buck == new Money(2, 'USD') //#4
//#1 Overrides == operator
//#2 Implements + operator
//#3 Use overridden ==
//#4 Use implemented +
================================================
FILE: listings/chap03/Listing_03_04_DefiningGStrings.groovy
================================================
import static java.util.Calendar.*
def me = 'Tarzan'
def you = 'Jane'
def line = "me $me - you $you" //#1
assert line == 'me Tarzan - you Jane'
TimeZone.default = TimeZone.getTimeZone('GMT')
def date = new Date(0)
def dateMap = [y:date[YEAR]-1900, m:date[MONTH], d:date[DAY_OF_MONTH]]
def out = "Year $dateMap.y Month $dateMap.m Day $dateMap.d" //#2
assert out == 'Year 70 Month 0 Day 1'
def tz = TimeZone.getTimeZone('GMT')
def format = 'd MMM YYYY HH:mm:SS z'
out = "Date is ${date.format(format, tz)} !" //#3
assert out == 'Date is 1 Jan 1970 00:00:00 GMT !'
//#4 start
def sql = """
SELECT FROM MyTable
WHERE Year = $dateMap.y
"""
assert sql == """
SELECT FROM MyTable
WHERE Year = 70
"""
//#4 end
out = "my 0.02\$" //#A
assert out == 'my 0.02$' //#B
//#1 Abbreviated dollar syntax
//#2 Extended dot syntax
//#3 Full syntax with braces
//#4 Multiline GStrings
//#A Escaped dollar sign
//#B Literal dollar sign
================================================
FILE: listings/chap03/Listing_03_05_StringOperations.groovy
================================================
String greeting = 'Hello Groovy!'
assert greeting.startsWith('Hello')
assert greeting.getAt(0) == 'H'
assert greeting[0] == 'H'
assert greeting.indexOf('Groovy') >= 0
assert greeting.contains('Groovy')
assert greeting[6..11] == 'Groovy'
assert 'Hi' + greeting - 'Hello' == 'Hi Groovy!'
assert greeting.count('o') == 3
assert 'x'.padLeft(3) == ' x'
assert 'x'.padRight(3,'_') == 'x__'
assert 'x'.center(3) == ' x '
assert 'x' * 3 == 'xxx'
================================================
FILE: listings/chap03/Listing_03_06_RegexGStrings.groovy
================================================
assert "abc" == /abc/
assert "\\d" == /\d/
def reference = "hello"
assert reference == /$reference/
assert "\$" == /$/
================================================
FILE: listings/chap03/Listing_03_07_RegularExpressions.groovy
================================================
def twister = 'she sells sea shells at the sea shore of seychelles'
// twister must contain a substring of size 3
// that starts with s and ends with a
assert twister =~ /s.a/ //#1
def finder = (twister =~ /s.a/) //#2
assert finder instanceof java.util.regex.Matcher //#2
// twister must contain only words delimited by single spaces
assert twister ==~ /(\w+ \w+)*/ //#A
def WORD = /\w+/
matches = (twister ==~ /($WORD $WORD)*/) //#B
assert matches instanceof java.lang.Boolean //#B
assert !(twister ==~ /s.e/) //#C
def wordsByX = twister.replaceAll(WORD, 'x')
assert wordsByX == 'x x x x x x x x x x'
def words = twister.split(/ /) //#D
assert words.size() == 10
assert words[0] == 'she'
//#1 Regex find operator as usable in if
//#2 Find expression evaluates to a matcher object
//#A Regex match operator
//#B Match expression evaluates to a boolean
//#C Match is full unlike find
//#D Split returns a list of words
================================================
FILE: listings/chap03/Listing_03_08_EachMatch.groovy
================================================
def myFairStringy = 'The rain in Spain stays mainly in the plain!'
// words that end with 'ain': \b\w*ain\b
def wordEnding = /\w*ain/
def rhyme = /\b$wordEnding\b/
def found = ''
myFairStringy.eachMatch(rhyme) { match -> //#1
found += match + ' '
}
assert found == 'rain Spain plain '
found = ''
(myFairStringy =~ rhyme).each { match -> //#2
found += match + ' '
}
assert found == 'rain Spain plain '
def cloze = myFairStringy.replaceAll(rhyme){ it-'ain'+'___' } //#3
assert cloze == 'The r___ in Sp___ stays mainly in the pl___!'
//#1 String.eachMatch(regex){}
//#2 Matcher.each {}
//#3 String.replaceAll(regex){}
================================================
FILE: listings/chap03/Listing_03_09_PatternReuse.groovy
================================================
def twister = 'she sells sea shells at the sea shore of seychelles'
// some more complicated regex:
// word that starts and ends with same letter
def regex = /\b(\w)\w*\1\b/
def many = 100 * 1000
start = System.nanoTime()
many.times{
twister =~ regex //#1
}
timeImplicit = System.nanoTime() - start
start = System.nanoTime()
pattern = ~regex //#A
many.times{
pattern.matcher(twister) //#B
}
timePredef = System.nanoTime() - start
assert timeImplicit > timePredef * 2 //#C
//#1 Find operator with implicit pattern construction
//#A Explicit pattern construction
//#B Apply pattern on a string
//#C At least twice as fast (possibly 3–5 times)
================================================
FILE: listings/chap03/Listing_03_10_PatternsClassification.groovy
================================================
def fourLetters = ~/\w{4}/
assert fourLetters.isCase('work')
assert 'love' in fourLetters
switch('beer'){
case fourLetters : assert true; break
default : assert false
}
beasts = ['bear','wolf','tiger','regex']
assert beasts.grep(fourLetters) == ['bear','wolf']
================================================
FILE: listings/chap03/Listing_03_11_NumberMethodsGDK.groovy
================================================
def store = ''
10.times{ //#A
store += 'x'
}
assert store == 'xxxxxxxxxx'
store = ''
1.upto(5) { number -> //#B
store += number
}
assert store == '12345'
store = ''
2.downto(-2) { number -> //#C
store += number + ' '
}
assert store == '2 1 0 -1 -2 '
store = ''
0.step(0.5, 0.1 ){ number -> //#D
store += number + ' '
}
assert store == '0 0.1 0.2 0.3 0.4 '
//#A Repetition
//#B Walking up with loop variable
//#C Walking down
//#D Walking with step width
================================================
FILE: listings/chap03/extra_escaped_characters_table36.groovy
================================================
println "A '\b' Backspace"
println "A '\t' Tab"
println "A '\r' Carriage return"
println "A '\n' Line feed"
println "A '\f' Form feed"
println "A '\\' Backslash"
println "A '\$' Dollar sign"
println "A '\u00A9' (Copyright symbol) - Unicode character U+00A9"
println "A '\54' (Comma) - ASCII code 44 (44 decimal = 54 octal)"
println "A '\'' Single quote"
println "A '\"' Double quote"
================================================
FILE: listings/chap03/extra_method_operators_table34.groovy
================================================
def a = 2
def b = 3
assert a + b == a.plus(b)
assert a - b == a.minus(b)
assert a * b == a.multiply(b)
assert a / b == a.div(b)
assert a % b == a.mod(b)
a = 2
assert ++a == 2.next()
assert a == 3
a = 2
assert a++ == 2
assert a == 3
a = 2
assert --a == 2.previous()
assert a == 1
a = 2
assert a-- == 2
assert a == 1
a = 2
assert -a == a.unaryMinus()
// added in 2.2.0-beta-2
//assert (+a) == a.unaryPlus()
assert a ** b == a.power(b)
assert (a | b) == a.or(b)
assert (a & b) == a.and(b)
assert (a ^ b) == a.xor(b)
// added in 2.2.0-beta-2
//assert ~a == a.bitwiseNegate()
a = [foo:5]
assert a['foo'] == a.getAt('foo')
a['bar'] = 6
assert a == [foo:5, bar:6]
a = [foo:5]
a.putAt('bar', 6)
assert a == [foo:5, bar:6]
a = 2
assert a << b == a.leftShift(b)
assert a >> b == a.rightShift(b)
assert a >>> b == a.rightShiftUnsigned(b)
enum AgeBand {
OLD, YOUNG
def isCase(Person p) {
p.age in 0..21 == (this == AgeBand.YOUNG)
}
}
class Person {
String name
int age
}
def classify(p) {
switch(p) {
case AgeBand.OLD: return "$p.name is old!"
case AgeBand.YOUNG: return "$p.name is young!"
}
}
assert classify(new Person(name: 'Tom', age: 15)) == 'Tom is young!'
assert classify(new Person(name: 'Mary', age: 25)) == 'Mary is old!'
assert a in b == b.isCase(a)
assert (a != b) == !(a == b)
assert a <=> b == a.compareTo(b)
assert a > b == a.compareTo(b) > 0
assert a >= b == a.compareTo(b) >= 0
assert a < b == a.compareTo(b) < 0
assert a <= b == a.compareTo(b) <= 0
assert a as Integer == a.asType(Integer)
================================================
FILE: listings/chap03/extra_numeric_literals_table32.groovy
================================================
[15, 0x1234ffff, 0b00110011, 100_000_000].each {
assert it instanceof Integer
}
[100L, 200l].each{ assert it instanceof Long }
[1.23f, 4.56F].each{ assert it instanceof Float }
[1.23d, 4.56D].each{ assert it instanceof Double }
[123g, 456G, 1G].each{ assert it instanceof BigInteger }
[1.23, 4.56, 1.4E4, 2.8e4, 1.23g, 1.23G, 1.0, 1.0G, 0E1].each{
assert it instanceof BigDecimal
}
================================================
FILE: listings/chap03/extra_numerical_coercion_table310.groovy
================================================
assert 1f*2f instanceof Double
assert (Byte)1+(Byte)2 instanceof Integer
assert 1*2L instanceof Long
assert 1 + 0.5 == 1.5
assert 1/2 instanceof BigDecimal
assert (1/2) == 0.5
assert (int)(1/2) == 0
assert 1.intdiv(2) == 0
// no coercion when exceeding range with +
def a = Integer.MAX_VALUE
assert (a+1) instanceof Integer
assert (a+1) == Integer.MIN_VALUE
assert (a+1L) instanceof Long
assert (a+1G) instanceof BigInteger
// but does coerce with the power operator
assert 2**30 instanceof Integer
assert 2**31 instanceof BigInteger
assert 2**3.5 instanceof Double
assert 2G+1G instanceof BigInteger
assert 2.5G+1G instanceof BigDecimal
assert 0G == 0.0f
assert 1.5G == 1.5f
assert !(1.1G == 1.1f)
================================================
FILE: listings/chap03/extra_optional_typing_table33.groovy
================================================
def a = 1; assert a instanceof Integer //|#1
def b = 1.0f; assert b instanceof Float //|#1
int c = 1; assert c instanceof Integer //|#2
float d = 1; assert d instanceof Float //|#2
Integer e = 1; assert e instanceof Integer //|#3
String f = '1'; assert f instanceof String //|#3
================================================
FILE: listings/chap03/extra_primitive_values_table31.groovy
================================================
byte a = 0 ; assert a instanceof Byte
short b = 0 ; assert b instanceof Short
int c = 0 ; assert c instanceof Integer
long d = 0L ; assert d instanceof Long
float e = 0F ; assert e instanceof Float
double f = 0D ; assert f instanceof Double
char g = 'a' ; assert g instanceof Character
boolean h = true ; assert h instanceof Boolean
================================================
FILE: listings/chap03/regex_dgm.txt
================================================
Matcher
long size()
int getCount()
Object getAt( int idx)
void setIndex( int idx)
boolean hasGroup()
Pattern
boolean isCase(Object switchValue)
String
Pattern bitwiseNegate()
String replaceFirst(Pattern pattern, String replacement)
boolean matches(Pattern pattern)
String minus(Object target) // if (target instanceof Pattern)
Object splitEachLine(String regex) {match -> ... }
String replaceAll(String regex) {match -> ... }
String replaceAll(Pattern pattern, String replacement)
String find(String regex)
String find(Pattern pattern)
String find(String regex) {match -> ... }
String find(Pattern pattern) {match -> ... }
List findAll(String regex)
List findAll(Pattern pattern)
List findAll(String regex) {match -> ... }
List findAll(Pattern pattern) {match -> ... }
String eachMatch(String regex) {match -> ... }
String eachMatch(Pattern pattern) {match -> ... }
File
Object splitEachLine(String sep) {match -> ... }
Reader
Object splitEachLine(String sep) {match -> ... }
InputStream
Object splitEachLine(String sep, String charset) {match -> ... }
Object splitEachLine(String sep) {match -> ... }
================================================
FILE: listings/chap03/snippet0301_autoboxing.groovy
================================================
assert 'ABCDE'.indexOf(67) == 2
================================================
FILE: listings/chap03/snippet0304_GString_internals.groovy
================================================
def me = 'Tarzan'
def you = 'Jane'
def line = "me $me - you $you"
assert line == 'me Tarzan - you Jane'
assert line instanceof GString
assert line.strings[0] == 'me '
assert line.strings[1] == ' - you '
assert line.values[0] == 'Tarzan'
assert line.values[1] == 'Jane'
================================================
FILE: listings/chap03/snippet0304_stringbuffer.groovy
================================================
def greeting = 'Hello'
greeting <<= ' Groovy' //#1
assert greeting instanceof java.lang.StringBuffer
greeting << '!' //#2
assert greeting.toString() == 'Hello Groovy!'
greeting[1..4] = 'i' //#A
assert greeting.toString() == 'Hi Groovy!'
//#1 Left shift and assign
//#2 Left shift on StringBuffer
//#A Substring 'ello' becomes 'i'
================================================
FILE: listings/chap03/snippet0305_matcher_each_group.groovy
================================================
def matcher = 'a:1 b:2 c:3' =~ /(\S+):(\S+)/
matcher.each { full, key, value ->
assert full.size() == 3
assert key.size() == 1 // a,b,c
assert value.size() == 1 // 1,2,3
}
================================================
FILE: listings/chap03/snippet0305_matcher_groups.groovy
================================================
def matcher = 'a:1 b:2 c:3' =~ /(\S+):(\S+)/
assert matcher.hasGroup()
assert matcher[0] == ['a:1', 'a', '1'] // 1st match
assert matcher[1][2] == '2' // 2nd match, 2nd group
================================================
FILE: listings/chap03/snippet0305_matcher_parallel_assignment.groovy
================================================
def (a,b,c) = 'a b c' =~ /\S/
assert a == 'a'
assert b == 'b'
assert c == 'c'
================================================
FILE: listings/chap03/snippet0305_matcher_plain.groovy
================================================
def matcher = 'a b c' =~ /\S/
assert matcher[0] == 'a'
assert matcher[1..2] == ['b','c']
assert matcher.size() == 3
================================================
FILE: listings/chap03/snippet0306_GDK_methods_for_numbers.groovy
================================================
assert 1 == (-1).abs()
assert 2 == 2.5.toInteger() // conversion
assert 2 == 2.5 as Integer // enforced coercion
assert 2 == (int) 2.5 // cast
assert 3 == 2.5f.round()
assert 3.142 == Math.PI.round(3)
assert 4 == 4.5f.trunc()
assert 2.718 == Math.E.trunc(3)
assert '2.718'.isNumber() // String methods
assert 5 == '5'.toInteger()
assert 5 == '5' as Integer
assert 53 == (int) '5' // gotcha!
assert '6 times' == 6 + ' times' // Number + String
================================================
FILE: listings/chap04/Listing_04_01_range_declarations.groovy
================================================
assert (0..10).contains(0) //#A
assert (0..10).contains(5) //#A
assert (0..10).contains(10) //#A
assert (0..10).contains(-1) == false //#A
assert (0..10).contains(11) == false //#A
assert (0..<10).contains(9) //#B
assert (0..<10).contains(10) == false //#B
def a = 0..10 //#1
assert a instanceof Range //#1
assert a.contains(5) //#1
a = new IntRange(0,10) //#C
assert a.contains(5) //#C
assert (0.0..1.0).contains(1.0) //#D
assert (0.0..1.0).containsWithinBounds(0.5) //#D
def today = new Date() //#2
def yesterday = today - 1 //#2
assert (yesterday..today).size() == 2 //#2
assert ('a'..'c').contains('b') //#3
def log = '' //#E
for (element in 5..9){ //#E
log += element //#E
} //#E
assert log == '56789' //#E
log = '' //#F
for (element in 9..5){ //#F
log += element //#F
} //#F
assert log == '98765' //#F
log = '' //#4
(9..<5).each { element -> //#4
log += element //#4
} //#4
assert log == '9876' //#4
//#A Inclusive ranges
//#B Half-exclusive ranges
//#1 References to ranges
//#C Explicit construction
//#D Bounds checking
//#2 Date ranges
//#3 String ranges
//#E for-in-range loop
//#F Loop with reverse range
//#4 Half-exclusive, reverse, each with closure
================================================
FILE: listings/chap04/Listing_04_02_ranges_are_objects.groovy
================================================
def result = '' //#A
(5..9).each { element -> //#A
result += element //#A
} //#A
assert result == '56789' //#A
assert 5 in 0..10 //#1
assert (0..10).isCase(5) //#1
//#1
def age = 36 //#1
switch(age){ //#1
case 16..20 : insuranceRate = 0.05 ; break //#1
case 21..50 : insuranceRate = 0.06 ; break //#1
case 51..65 : insuranceRate = 0.07 ; break //#1
default: throw new IllegalArgumentException() //#1
} //#1
assert insuranceRate == 0.06 //#1
def ages = [20, 36, 42, 56] //#2
def midage = 21..50 //#2
assert ages.grep(midage) == [36, 42] //#2
//#A Iterating over a range
//#1 Ranges for classification
//#2 Filtering with ranges
================================================
FILE: listings/chap04/Listing_04_03_custom_ranges.groovy
================================================
class Weekday implements Comparable {
static final DAYS = [
'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'
]
private int index = 0
Weekday(String day) { //#A
index = DAYS.indexOf(day)
}
Weekday next() {
return new Weekday(DAYS[(index + 1) % DAYS.size()])
}
Weekday previous() {
return new Weekday(DAYS[index - 1]) //#1
}
int compareTo(Object other) {
return this.index <=> other.index
}
String toString() {
return DAYS[index]
}
}
def mon = new Weekday('Mon')
def fri = new Weekday('Fri')
def worklog = ''
for (day in mon..fri) { //#B
worklog += day.toString() + ' '
}
assert worklog == 'Mon Tue Wed Thu Fri '
//#A Allow all values
//#1 Range bound methods
//#B Working through the week
================================================
FILE: listings/chap04/Listing_04_04_list_declarations.groovy
================================================
List myList = [1, 2, 3]
assert myList.size() == 3
assert myList[0] == 1
assert myList instanceof ArrayList
List emptyList = []
assert emptyList.size() == 0
List longList = (0..1000).toList()
assert longList[555] == 555
List explicitList = new ArrayList()
explicitList.addAll(myList) //#1
assert explicitList.size() == 3
explicitList[0] = 10
assert explicitList[0] == 10
explicitList = new LinkedList(myList) //#1
assert explicitList.size() == 3
explicitList[0] = 10
assert explicitList[0] == 10
//#1 Fill from myList
//////////////////////// extra examples:
assert args instanceof String[] //#2
assert args.size() == 0 //#3
List flat = [0, *myList, 4] //#4
assert flat == [0, 1, 2, 3, 4]
//#2 Command-line args
//#3 Array as list
//#4 Spread
================================================
FILE: listings/chap04/Listing_04_05_list_subscript_operator.groovy
================================================
def myList = ['a','b','c','d','e','f']
assert myList[0..2] == ['a','b','c'] //#A
assert myList[0,2,4] == ['a','c','e'] //#B
myList[0..2] = ['x','y','z'] //#C
assert myList == ['x','y','z','d','e','f']
myList[3..5] = [] //#1
assert myList == ['x','y','z']
myList[1..1] = [0, 1, 2] //#2
assert myList == ['x', 0, 1, 2, 'z']
//#A getAt(Range)
//#B getAt(collection of indexes)
//#C putAt(Range)
//#1 Removing elements
//#2 Adding elements
================================================
FILE: listings/chap04/Listing_04_06_list_add_remove.groovy
================================================
myList = []
myList += 'a' //#A
assert myList == ['a']
myList += ['b','c'] //#B
assert myList == ['a','b','c']
myList = []
myList << 'a' << 'b' //#C
assert myList == ['a','b']
assert myList - ['b'] == ['a'] //#D
assert myList * 2 == ['a','b','a','b'] //#E
//#A plus(Object)
//#B plus(Collection)
//#C leftShift is like append
//#D minus(Collection)
//#E Multiply
================================================
FILE: listings/chap04/Listing_04_07_lists_control_structures.groovy
================================================
myList = ['a', 'b', 'c']
assert myList.isCase('a')
assert 'b' in myList
def candidate = 'c'
switch(candidate){
case myList : assert true; break //#1
default : assert false
}
assert ['x','a','z'].grep(myList) == ['a'] //#2
myList = []
if (myList) assert false //#3
// Lists can be iterated with a 'for' loop
def expr = ''
for (i in [1,'*',5]){ //#4
expr += i
}
assert expr == '1*5'
//#1 Classify by containment
//#2 Intersection filter
//#3 Empty lists are false
//#4 for in Collection
================================================
FILE: listings/chap04/Listing_04_08_list_content_manipulation.groovy
================================================
assert [1,[2,3]].flatten() == [1,2,3]
assert [1,2,3].intersect([4,3,1])== [3,1]
assert [1,2,3].disjoint([4,5,6])
list = [1,2,3]
popped = list.pop() //#1
assert popped == 3
assert list == [1,2]
assert [1,2].reverse() == [2,1]
assert [3,1,2].sort() == [1,2,3]
list = [ [1,0], [0,1,2] ]
list = list.sort { a,b -> a[0] <=> b[0] } //#2
assert list == [ [0,1,2], [1,0] ]
list = list.sort { item -> item.size() } //#3
assert list == [ [1,0], [0,1,2] ]
list = ['a','b','c']
list.remove(2) //#4
assert list == ['a','b']
list.remove('b') //#5
assert list == ['a']
list = ['a','b','b','c']
list.removeAll(['b','c'])
assert list == ['a']
def doubled = [1,2,3].collect{ item -> //#6
item*2
}
assert doubled == [2,4,6]
def odd = [1,2,3].findAll{ item -> //#7
item % 2 == 1
}
assert odd == [1,3]
//#1 Treating a list like a stack
//#2 Comparing lists by first element
//#3 Comparing lists by size
//#4 Removing by index
//#5 Removing by value
//#6 Transforming one list into another
//#7 Finding every element matching the closure
================================================
FILE: listings/chap04/Listing_04_09_list_other_methods.groovy
================================================
def list = [1, 2, 3]
assert list.first() == 1
assert list.head() == 1
assert list.tail() == [2, 3]
assert list.last() == 3
assert list.count(2) == 1 //#A
assert list.max() == 3 //#A
assert list.min() == 1 //#A
//#A
def even = list.find { item -> //#A
item % 2 == 0 //#A
} //#A
assert even == 2 //#A
//#A
assert list.every { item -> item < 5 } //#A
assert list.any { item -> item < 2 } //#A
def store = ''
list.each { item -> //#B
store += item //#B
} //#B
assert store == '123' //#B
//#B
store = '' //#B
list.reverseEach { item -> //#B
store += item //#B
} //#B
assert store == '321' //#B
//#B
store = '' //#B
list.eachWithIndex { item, index -> //#B
store += "$index:$item " //#B
} //#B
assert store == '0:1 1:2 2:3 ' //#B
assert list.join('-') == '1-2-3' //#C
//#C
result = list.inject(0) { clinks, guests -> //#C
clinks + guests //#C
} //#C
assert result == 0 + 1 + 2 + 3 //#C
assert list.sum() == 6 //#C
//#C
factorial = list.inject(1) { fac, item -> //#C
fac * item //#C
} //#C
assert factorial == 1 * 1 * 2 * 3 //#C
//#A Querying
//#B Iteration
//#C Accumulation
================================================
FILE: listings/chap04/Listing_04_10_list_quicksort.groovy
================================================
def quickSort(list) {
if (list.size() < 2) return list
def pivot = list[list.size().intdiv(2)]
def left = list.findAll { item -> item < pivot } //#1
def middle = list.findAll { item -> item == pivot } //#1
def right = list.findAll { item -> item > pivot } //#1
return quickSort(left) + middle + quickSort(right) //#A
}
assert quickSort([]) == []
assert quickSort([1]) == [1]
assert quickSort([1,2]) == [1,2]
assert quickSort([2,1]) == [1,2]
assert quickSort([3,1,2]) == [1,2,3]
assert quickSort([3,1,2,2]) == [1,2,2,3]
assert quickSort([1.0f,'a',10,null]) == [null,1.0f,10,'a'] //#2
assert quickSort('bca') == 'abc'.toList() //#3
//#1 Classify by pivot
//#A Recursive calls
//#2 Ducktyped items
//#3 Ducktyped structure
================================================
FILE: listings/chap04/Listing_04_11_list_mapreduce.groovy
================================================
def urls = [
new URL('http', 'myshop.com', 80, 'index.html'),
new URL('https', 'myshop.com', 443, 'buynow.html'),
new URL('ftp', 'myshop.com', 21, 'downloads')
]
assert urls
.findAll{ it.port < 99 }
.collect{ it.file.toUpperCase() }
.sort()
.join(', ') == 'DOWNLOADS, INDEX.HTML'
================================================
FILE: listings/chap04/Listing_04_12_map_declarations.groovy
================================================
def myMap = [a:1, b:2, c:3]
assert myMap instanceof LinkedHashMap
assert myMap.size() == 3
assert myMap['a'] == 1
def emptyMap = [:]
assert emptyMap.size() == 0
def explicitMap = new TreeMap()
explicitMap.putAll(myMap)
assert explicitMap['a'] == 1
def composed = [x:'y', *:myMap] //#A
assert composed == [x:'y', a:1, b:2, c:3]
//#A Spread operator
================================================
FILE: listings/chap04/Listing_04_13_map_accessors.groovy
================================================
def myMap = [a:1, b:2, c:3]
assert myMap['a'] == 1 //#A
assert myMap.a == 1 //#A
assert myMap.get('a') == 1 //#A
assert myMap.get('a',0) == 1 //#A
assert myMap['d'] == null //#B
assert myMap.d == null //#B
assert myMap.get('d') == null //#B
assert myMap.get('d',0) == 0 //#C
assert myMap.d == 0 //#C
myMap['d'] = 1 //#D
assert myMap.d == 1 //#D
myMap.d = 2 //#D
assert myMap.d == 2 //#D
//#A Retrieve existing elements
//#B Attempt to retrieve missing elements
//#C Default value
//#D Single putAt
================================================
FILE: listings/chap04/Listing_04_14_map_query_methods.groovy
================================================
def myMap = [a:1, b:2, c:3]
def other = [b:2, c:3, a:1]
assert myMap == other //#A
assert !myMap.isEmpty() //#B
assert myMap.size() == 3 //#B
assert myMap.containsKey('a') //#B
assert myMap.containsValue(1) //#B
assert myMap.entrySet() instanceof Collection //#B
assert myMap.any {entry -> entry.value > 2 } //#1
assert myMap.every {entry -> entry.key < 'd'} //#1
assert myMap.keySet() == ['a','b','c'] as Set //#C
assert myMap.values().toList() == [1, 2, 3] //#D
//#A Call to equals
//#B JDK methods
//#1 GDK methods
//#C Set equals
//#D List equals
================================================
FILE: listings/chap04/Listing_04_15_map_iteration.groovy
================================================
def myMap = [a:1, b:2, c:3]
def store = ''
myMap.each { entry -> //#A
store += entry.key //#A
store += entry.value //#A
} //#A
assert store == 'a1b2c3'
store = ''
myMap.each { key, value -> //#B
store += key //#B
store += value //#B
} //#B
assert store == 'a1b2c3'
store = ''
for (key in myMap.keySet()) { //#C
store += key //#C
} //#C
assert store == 'abc'
store = ''
for (value in myMap.values()) { //#D
store += value //#D
} //#D
assert store == '123'
//#A Iterate over entries
//#B Iterate over keys/values
//#C Iterate over just the keys
//#D Iterate over just the values
================================================
FILE: listings/chap04/Listing_04_16_map_content.groovy
================================================
def myMap = [a:1, b:2, c:3]
myMap.clear()
assert myMap.isEmpty()
myMap = [a:1, b:2, c:3]
myMap.remove('a')
assert myMap.size() == 2
assert [a:1] + [b:2] == [a:1, b:2]
myMap = [a:1, b:2, c:3]
def abMap = myMap.subMap(['a', 'b']) //#1
assert abMap.size() == 2
abMap = myMap.findAll { entry -> entry.value < 3 }
assert abMap.size() == 2
assert abMap.a == 1
def found = myMap.find { entry -> entry.value < 2 }
assert found.key == 'a'
assert found.value == 1
def doubled = myMap.collect { entry -> entry.value *= 2 }
assert doubled instanceof List
assert doubled.every { item -> item % 2 == 0 }
def addTo = []
myMap.collect(addTo) { entry -> entry.value *= 2 }
assert addTo instanceof List
assert addTo.every { item -> item % 2 == 0 }
//#1 Create a view onto the original map
================================================
FILE: listings/chap04/Listing_04_17_map_example.groovy
================================================
def textCorpus =
"""
Look for the bare necessities
The simple bare necessities
Forget about your worries and your strife
I mean the bare necessities
Old Mother Nature's recipes
That bring the bare necessities of life
"""
def words = textCorpus.tokenize()
def wordFrequency = [:]
words.each { word ->
wordFrequency[word] = wordFrequency.get(word,0) + 1 //#1
}
def wordList = wordFrequency.keySet().toList()
wordList.sort { wordFrequency[it] } //#2
def statistic = "\n"
wordList[-1..-5].each { word ->
statistic += word.padLeft(12) + ': '
statistic += wordFrequency[word] + "\n"
}
assert statistic == """
necessities: 4
bare: 4
the: 3
your: 2
life: 1
"""
//#1 Update frequency count
//#2 Sort by frequency
================================================
FILE: listings/chap04/extra_EnumRange.groovy
================================================
enum Month {
Jan, Feb, Mar, Apr, May, Jun,
Jul, Aug, Sep, Oct, Nov, Dec
}
def noClams = Month.May .. Month.Aug
def thisMonth = Month.Aug
boolean iWarnedYou = false
if (thisMonth in noClams) { //#1
println "Don't eat clams this month,"
println "it has no 'r' in its name!"
iWarnedYou = true
}
assert iWarnedYou
//#1 'in' operator
================================================
FILE: listings/chap04/extra_ListCast.groovy
================================================
Set names = ['Dierk', 'Paul'] as Set
assert names instanceof Set
assert names.toListString() ==~ /\[\w+, \w+\]/
assert names.asList() instanceof List
java.awt.Point p = [10, 20]
assert p.x == 10
================================================
FILE: listings/chap04/extra_ListTable.groovy
================================================
def table = [
[0, 1],
[2, 3]
]
table = table.collectNested { item -> item + 1 }
assert table == [
[1, 2],
[3, 4]
]
assert table.transpose() == [
[1, 3],
[2, 4]
]
assert table.combinations() == [
[1, 3], [2, 3], [1, 4], [2, 4]
]
================================================
FILE: listings/chap04/extra_Map_as.groovy
================================================
def absComp = [
compare: { a,b -> a.abs() <=> b.abs() }
]
def list = [-3, -1, 2]
list.sort(true, absComp as Comparator)
assert list == [-1, 2, -3]
================================================
FILE: listings/chap04/extra_Map_group.groovy
================================================
def tzones = [
dierk: +1, guillaume: +1, jon: 0,
paul: +9, tara: -7
]
assert tzones.groupBy { key, val -> val.intdiv 5 } == [
0: [dierk:1, guillaume:1, jon:0],
1: [paul: 9],
(-1): [tara:-7]
]
================================================
FILE: listings/chap04/extra_MaxMinSum.groovy
================================================
def kings = ['Dierk', 'Paul']
assert kings.max { item -> item.size() } == 'Dierk'
assert kings.min { item -> item.size() } == 'Paul'
assert kings.sum { item -> item.size() } == 9
================================================
FILE: listings/chap04/extra_SplitList.groovy
================================================
def list = [0, 3, 2, 1]
def (small, big) = list.split { it < 2 }
assert small == [0, 1]
assert big == [3, 2]
def group = list.groupBy { it % 2 }
assert group[0] == [0, 2]
assert group[1] == [3, 1]
================================================
FILE: listings/chap04/snippet0402_ListAsSet.groovy
================================================
def x = [1, 1, 1]
assert [1] == new HashSet(x).toList()
assert [1] == x.unique()
assert [1] == [1, '1'].unique { item -> item.toInteger() }
================================================
FILE: listings/chap04/snippet0402_ListRemoveNulls.groovy
================================================
List x = [1, null, null, 2]
assert [1, 2] == x.findAll { it != null }
assert [1, 2] == x.grep { it }
assert [1, 2] == x - [null]
x.removeAll([null])
assert [1, 2] == x
================================================
FILE: listings/chap04/snippet0402_ListStreams_jdk8_plus.groovy
================================================
def urls = [
new URL('http', 'myshop.com', 80, 'index.html'),
new URL('https', 'myshop.com', 443, 'buynow.html'),
new URL('ftp', 'myshop.com', 21, 'downloads')
]
// Groovy with Java 8
import java.util.stream.Collectors
def commaSep = Collectors.joining(", ")
assert urls.stream()
.filter{ it.port < 99 }
.map{ it.file.toUpperCase() }
.sorted()
.collect(commaSep) == 'DOWNLOADS, INDEX.HTML'
================================================
FILE: listings/chap04/snippet0403_Map_Ctor_Expression.groovy
================================================
def x = 'a'
assert ['x':1] == [x:1]
assert ['a':1] == [(x):1]
================================================
FILE: listings/chap04/snippet0403_Map_Ctor_Unquoted.groovy
================================================
assert ['a':1] == [a:1]
================================================
FILE: listings/chap04/snippet0403_Map_MapReduce.groovy
================================================
def people = [peter: 40, paul: 30, mary: 20]
assert people
.findAll{ _, age -> age < 35 }
.collect{ name, _ -> name.toUpperCase() }
.sort()
.join(', ') == 'MARY, PAUL'
================================================
FILE: listings/chap04/snippet0403_Map_String_accessors.groovy
================================================
def myMap = ['a.b':1]
assert myMap.'a.b' == 1
================================================
FILE: listings/chap05/Listing_05_01_closure_simple_declaration.groovy
================================================
def log = ''
(1..10).each { counter -> log += counter }
assert log == '12345678910'
log = ''
(1..10).each { log += it }
assert log == '12345678910'
================================================
FILE: listings/chap05/Listing_05_02_simple_method_closure.groovy
================================================
class SizeFilter {
Integer limit
boolean sizeUpTo(String value) {
return value.size() <= limit
}
}
SizeFilter filter6 = new SizeFilter(limit:6) //#1
SizeFilter filter5 = new SizeFilter(limit:5) //#1
Closure sizeUpTo6 = filter6.&sizeUpTo //#2
def words = ['long string', 'medium', 'short', 'tiny']
assert 'medium' == words.find (sizeUpTo6) //#3
assert 'short' == words.find (filter5.&sizeUpTo) //#4
//#1 GroovyBean constructor calls
//#2 Method closure assignment
//#3 Calling with closure
//#4 Passing a method closure directly
================================================
FILE: listings/chap05/Listing_05_03_multi_method_closure.groovy
================================================
class MultiMethodSample {
int mysteryMethod (String value) {
return value.length()
}
int mysteryMethod (List list) {
return list.size()
}
int mysteryMethod (int x, int y) {
return x+y
}
}
MultiMethodSample instance = new MultiMethodSample()
Closure multi = instance.&mysteryMethod //#1
assert 10 == multi ('string arg') //#2
assert 3 == multi (['list', 'of', 'values']) //#2
assert 14 == multi (6, 8) //#2
//#1 Only a single closure is created
//#2 Different implementations are called based on argument types
================================================
FILE: listings/chap05/Listing_05_04_closure_all_declarations.groovy
================================================
Map map = ['a':1, 'b':2]
map.each{ key, value -> map[key] = value * 2 } //#1
assert map == ['a':2, 'b':4]
Closure doubler = {key, value -> map[key] = value * 2 }//#2
map.each(doubler) //#2
assert map == ['a':4, 'b':8]
def doubleMethod (entry){ //#3
entry.value = entry.value * 2 //#3
}
doubler = this.&doubleMethod //#4
map.each(doubler) //#4
assert map == ['a':8, 'b':16]
//#1 Parameter sequence with commas
//#2 Assign and then call a closure reference
//#3 Usual method declaration
//#4 Reference and call a method as a closure
================================================
FILE: listings/chap05/Listing_05_05_simple_closure_calling.groovy
================================================
def adder = { x, y -> return x+y }
assert adder(4, 3) == 7
assert adder.call(2, 6) == 8
================================================
FILE: listings/chap05/Listing_05_06_calling_closures.groovy
================================================
def benchmark(int repeat, Closure worker) { //#1
def start = System.nanoTime() //#2
repeat.times { worker(it) } //#3
def stop = System.nanoTime() //#4
return stop - start //#4
}
def slow = benchmark(10000) { (int) it / 2 } //#5
def fast = benchmark(10000) { it.intdiv(2) } //#5
assert fast * 2 < slow //#5
//#1 Put closures last
//#2 Some pre-work
//#3 Call closure the given number of times
//#4 Some post-work
//#5 Pass different closures for analysis
================================================
FILE: listings/chap05/Listing_05_07_simple_currying.groovy
================================================
def mult = { x, y -> return x * y }
def twoTimes = mult.curry(2)
assert twoTimes(5) == 10
================================================
FILE: listings/chap05/Listing_05_08_logging_curry_example.groovy
================================================
def configurator = { format, filter, line -> //#1
filter(line) ? format(line) : null //#1
}
def appender = { config, append, line -> //#2
def out = config(line) //#2
if (out) append(out) //#2
}
def dateFormatter = { line -> "${new Date()}: $line" } //#3
def debugFilter = { line -> line.contains('debug') } //#3
def consoleAppender = { line -> println line } //#3
def myConf = configurator.curry(dateFormatter, debugFilter) //#4
def myLog = appender.curry(myConf, consoleAppender) //#4
myLog('here is some debug message')
myLog('this will not be printed')
//#1 Configuration use
//#2 Formatting use
//#3 Filter, format, and output parts
//#4 Putting it all together
================================================
FILE: listings/chap05/Listing_05_09_closure_scope.groovy
================================================
class Mother {
def prop = 'prop'
def method(){ 'method' }
Closure birth (param) { //#1
def local = 'local'
def closure = {
[ this, prop, method(), local, param ]
}
return closure
}
}
Mother julia = new Mother()
def closure = julia.birth('param') //#2
def context = closure.call() //#3
assert context[0] == julia //#4
assert context[1, 2] == ['prop', 'method'] //#5
assert context[3, 4] == ['local', 'param' ] //#6
assert closure.thisObject == julia //|#7
assert closure.owner == julia //|#7
assert closure.delegate == julia //|#8
assert closure.resolveStrategy == Closure.OWNER_FIRST //|#8
//#1 Creation method
//#2 Closure declaration time
//#3 Closure execution time
//#4 What "this" refers to
//#5 Free variables, resolved
//#6 Bound variables
//#7 Read only
//#8 Scope control
================================================
FILE: listings/chap05/Listing_05_10_closure_accumulator.groovy
================================================
def foo(n) {
return { n += it }
}
def accumulator = foo(1)
assert accumulator(2) == 3
assert accumulator(1) == 4
================================================
FILE: listings/chap05/Listing_05_11_visitor_pattern.groovy
================================================
class Drawing {
List shapes
def accept(Closure yield) { shapes.each{it.accept(yield)} }
}
class Shape {
def accept(Closure yield) { yield(this) }
}
class Square extends Shape {
def width
def area() { width**2 }
}
class Circle extends Shape {
def radius
def area() { Math.PI * radius**2 }
}
def picture = new Drawing(shapes: [new Square(width:1), new Circle(radius:1)])
def total = 0
picture.accept { total += it.area() }
println "The shapes in this drawing cover an area of $total units."
println 'The individual contributions are: '
picture.accept { println it.class.name + ":" + it.area() }
================================================
FILE: listings/chap05/extra_ClosureProperty.groovy
================================================
class GrailsController {
def params = [a:1, b:2]
def list = { params.keySet().toList() }
}
def controller = new GrailsController()
assert controller.list() == ['a', 'b']
controller.list = { controller.params.values().toList() }
assert controller.list() == [1, 2]
================================================
FILE: listings/chap05/extra_Closure_delegate.groovy
================================================
def list = []
def expected = [1, 2]
list.with {
add 1
add 2
assert delegate == expected
}
================================================
FILE: listings/chap05/extra_Closure_myWith.groovy
================================================
def with(Closure doit) { // fake implementation
doit.delegate = list
doit()
}
================================================
FILE: listings/chap05/snippet0501_envelope.groovy.txt
================================================
Closure envelope = { person -> new Letter(person).send() }
addressBook.each (envelope)
================================================
FILE: listings/chap05/snippet0504_closure_default_params.groovy
================================================
def adder = { x, y=5 -> return x+y }
assert adder(4, 3) == 7
assert adder.call(7) == 12
================================================
FILE: listings/chap05/snippet0504_closure_isCase.groovy
================================================
def odd = { it % 2 == 1}
assert [1,2,3].grep(odd) == [1, 3]
switch(10) {
case odd : assert false
}
if (2 in odd) assert false
================================================
FILE: listings/chap05/snippet0504_closure_paramcount.groovy
================================================
def numParams (Closure closure){
closure.getMaximumNumberOfParameters()
}
assert numParams { one -> } == 1
assert numParams { one, two -> } == 2
def paramTypes (Closure closure){
closure.getParameterTypes()
}
assert paramTypes { String s -> } == [String]
assert paramTypes { Number n, Date d -> } == [Number, Date]
================================================
FILE: listings/chap05/snippet0505_map_with.groovy
================================================
def map = [:]
map.with {
a = 1
b = 2
}
assert map == [a:1, b:2]
================================================
FILE: listings/chap05/snippet0505_scoping.groovy
================================================
def x = 0
10.times {
x++
}
assert x == 10
================================================
FILE: listings/chap05/snippet0506_closure_return.groovy
================================================
assert [2, 4, 6] == [1, 2, 3].collect { it * 2 }
assert [2, 4, 6] == [1, 2, 3].collect { return it * 2 }
assert [1, 4, 3] == [1, 2, 3].collect {
if (it % 2 == 0) return it * 2
return it
}
================================================
FILE: listings/chap05/snippet0507_closure_composition.groovy
================================================
def mult = { x, y -> return x * y }
def twoTimes = mult.curry(2)
assert twoTimes(5) == 10
def fourTimes = twoTimes >> twoTimes
def eightTimes = twoTimes << fourTimes
assert eightTimes(1) == twoTimes(fourTimes(1))
================================================
FILE: listings/chap05/snippet0508_memoize.groovy
================================================
def fib
fib = { it < 2 ? 1 : fib(it-1) + fib(it-2) }
fib = fib.memoize()
assert fib(40) == 165_580_141
// nano time
// without memoize 22_903_497_000
// with memoize 1_074_000
================================================
FILE: listings/chap05/snippet0509_trampoline.groovy
================================================
def last
last = { it.size() == 1 ? it.head() : last.trampoline(it.tail()) }
last = last.trampoline()
assert last(0..10_000) == 10_000
================================================
FILE: listings/chap06/Listing_06_01_groovy_truth.groovy
================================================
assert true //#A
assert !false //#A
assert ('a' =~ /./) //#B
assert !('a' =~ /b/) //#B
assert [1] //#C
assert ![] //#C
Iterator iter = [1].iterator()
assert iter //#D
iter.next() //#D
assert !iter //#D
assert ['a':1] //#E
assert ![:] //#E
assert 'a' //#F
assert !'' //#F
assert 1 //#G
assert 1.1 //#G
assert 1.2f //#G
assert 1.3g //#G
assert 2L //#G
assert 3G //#G
assert !0 //#G
assert ! null //#H
assert new Object() //#H
class AlwaysFalse {
boolean asBoolean() { false } //#I
}
assert ! new AlwaysFalse() //#J
//#A Boolean values are trivial
//#B Matchers must match
//#C Collections must be nonempty
//#D Iterators must have next element
//#E Maps must be nonempty
//#F Strings must be nonempty
//#G Numbers (any type) must be nonzero
//#H Objects must be non-null
//#I Custom truth
//#J Calls asBoolean()
================================================
FILE: listings/chap06/Listing_06_02_assignment_bug.groovy
================================================
def x = 1
if (x == 2) { //#1
assert false
}
/*******************
if (x = 2) { //#2
println x
}
********************/
if ((x = 3)) { //#3
println x
}
assert x == 3
def store = []
while (x = x - 1) { //#4
store << x
}
assert store == [2, 1]
while (x = 2) { //#5
println x
break
}
//#1 Normal comparison
//#2 Not allowed; compiler error
//#3 Assign and test in nested expression
//#4 Deliberate assign and test in while
//#5 Ouch—this will print 2
================================================
FILE: listings/chap06/Listing_06_03_if_then_else.groovy
================================================
if (true) assert true
else assert false
if (1) {
assert true
} else {
assert false
}
if ('nonempty') assert true
else if (['x']) assert false
else assert false
if (0) assert false
else if ([]) assert false
else assert true
================================================
FILE: listings/chap06/Listing_06_04_conditional_operator.groovy
================================================
def result = (1==1) ? 'ok' : 'failed'
assert result == 'ok'
result = 'some string' ? 10 : ['x']
assert result == 10
================================================
FILE: listings/chap06/Listing_06_05_switch_basic.groovy
================================================
def a = 1
def log = ''
switch (a) {
case 0 : log += '0' //#A
case 1 : log += '1' //#A
case 2 : log += '2' ; break
default : log += 'default'
}
assert log == '12'
//#A Fall through
================================================
FILE: listings/chap06/Listing_06_06_switch_advanced.groovy
================================================
switch (10) {
case 0 : assert false ; break
case 0..9 : assert false ; break
case [8,9,11] : assert false ; break
case Float : assert false ; break //#1
case {it%3 == 0}: assert false ; break //#2
case ~/../ : assert true ; break //#3
default : assert false ; break
}
//#1 Type case
//#2 Closure case
//#3 Regular expression case
================================================
FILE: listings/chap06/Listing_06_07_assert_host.groovy
================================================
def host = /\/\/([a-zA-Z0-9-]+(\.[a-zA-Z0-9-])*?)(:|\/)/ //#A
assertHost 'http://a.b.c:8080/bla', host, 'a.b.c'
assertHost 'http://a.b.c/bla', host, 'a.b.c'
assertHost 'http://127.0.0.1:8080/bla', host, '127.0.0.1'
assertHost 'http://t-online.de/bla', host, 't-online.de'
assertHost 'http://T-online.de/bla', host, 'T-online.de'
def assertHost (candidate, regex, expected){
candidate.eachMatch(regex){ assert it[1] == expected }
}
// ... use host regex ... //#B
//#A Regular expression matching host
//#B Trailing code goes here
================================================
FILE: listings/chap06/Listing_06_08_while.groovy
================================================
def list = [1, 2, 3]
while (list) {
list.remove(0)
}
assert list == []
while (list.size() < 3) list << list.size() + 1
assert list == [1, 2, 3]
================================================
FILE: listings/chap06/Listing_06_09_for.groovy
================================================
def store = '' //#1
for (String s in 'a'..'c') store += s //#1
assert store == 'abc' //#1
store = '' //#2
for (i in [1, 2, 3]) { //#2
store += i //#2
} //#2
assert store == '123' //#2
def myString = 'Old school Java' //#3
store = '' //#3
for (int i=0; i < myString.size(); i++) { //#3
store += myString[i] //#3
} //#3
assert store == myString //#3
myString = 'Java range index' //#4
store = '' //#4
for (int i : 0 ..< myString.size()) { //#4
store += myString[i] //#4
} //#4
assert store == myString //#4
myString = 'Groovy range index' //#5
store = '' //#5
for (i in 0 ..< myString.size()) { //#5
store += myString[i] //#5
} //#5
assert store == myString //#5
myString = 'Java string Iterable' //#6
store = '' //#6
for (String s : myString) { //#6
store += s //#6
} //#6
assert store == myString //#6
myString = 'Groovy iterator' //#7
store = '' //#7
for (s in myString) { //#7
store += s //#7
} //#7
assert store == myString //#7
//#1 Explicit typing, over string range, no braces
//#2 Implicit typing, over list as collection, braces
//#3 Explicit typing, Java-style traditional for loop, braces
//#4 Explicit typing, Java-style iterable index, braces
//#5 Implicit typing, over half-exclusive IntRange, braces
//#6 Explicit typing, Java-style iterable value, braces
//#7 Implicit typing, over string as collection, braces
================================================
FILE: listings/chap06/Listing_06_10_break_continue.groovy
================================================
def a = 1
while (true) { //#A
a++
break //#B
}
assert a == 2
for (i in 0..10) {
if (i==0) continue //#C
a++
if (i > 0) break //#D
}
assert a==3
//#A Do forever
//#B Forever is over now
//#C Proceed with 1
//#D Premature loop end
================================================
FILE: listings/chap06/Listing_06_11_exception_example.groovy
================================================
def myMethod() {
throw new IllegalArgumentException()
}
def log = []
try {
myMethod()
} catch (Exception e) {
log << e.toString()
} finally {
log << 'finally'
}
assert log.size() == 2
================================================
FILE: listings/chap06/extra_if_return.groovy
================================================
def mac() {
if (System.properties.'os.name'.contains('Mac'))
"We're on Mac." // no 'return'
else
"Oh, well ..." // no 'return'
}
println mac()
================================================
FILE: listings/chap06/extra_in_operator.groovy
================================================
assert 1 in [0, 1, 2] // list
assert 1 in 0..3 // range
assert 'Hello' in String // class
assert 'Hello' in ~/H.*/ // pattern
================================================
FILE: listings/chap06/extra_switch_return.groovy
================================================
def mac() {
switch(System.properties.'os.name') {
case 'Mac OS X': "We're on Mac."; break // no 'return'
default: "Oh, well ..." // no 'return'
}
}
println mac()
================================================
FILE: listings/chap06/myFileName.txt
================================================
line one
line two
================================================
FILE: listings/chap06/snippet0602_bad_file_read.groovy
================================================
try {
input = new File('no such file')
assert input.exists()
assert input.canRead()
println input.text
} catch (AssertionError error) {
assert "\n" + error.message == '''
assert input.exists()
| |
| false
no such file'''
}
================================================
FILE: listings/chap06/snippet0602_bad_file_read_with_message.groovy
================================================
try {
input = new File('/no such file')
assert input.exists(), "cannot find: $input.canonicalPath"
assert input.canRead()
println input.text
} catch (AssertionError error) {
def root = new File('/').canonicalPath
assert error.message ==
'cannot find: ' + root + 'no such file. ' +
'Expression: input.exists()'
}
================================================
FILE: listings/chap06/snippet0602_failing_assert.groovy
================================================
def a = 1
try {
assert a == 2
} catch (AssertionError error) {
assert "\n" + error.message =='''
assert a == 2
| |
1 false'''
}
================================================
FILE: listings/chap06/snippet0603_each_loop_iterate.groovy
================================================
(0..9).each { println it }
================================================
FILE: listings/chap06/snippet0603_file_iterate_lines.groovy
================================================
def file = new File('myFileName.txt')
for (line in file) println line
================================================
FILE: listings/chap06/snippet0603_for_loop_iterate.groovy
================================================
for (x in 0..9) { println x }
================================================
FILE: listings/chap06/snippet0603_null_iterate.groovy
================================================
for (x in null) println 'This will not be printed!'
================================================
FILE: listings/chap06/snippet0603_object_iterate.groovy
================================================
for (x in new Object()) println "Printed once for object $x"
================================================
FILE: listings/chap06/snippet0603_regex_iterate_match.groovy
================================================
def matcher = '12xy3'=~/\d/
for (match in matcher) println match
================================================
FILE: listings/chap06/snippet0604_multicatch.groovy
================================================
try {
if (Math.random() < 0.5) 1 / 0
else null.hashCode()
} catch (ArithmeticException | NullPointerException exception) {
println exception.class.name
}
================================================
FILE: listings/chap07/Listing_07_01_Declaring_Variables.groovy
================================================
class ClassWithTypedAndUntypedFieldsAndProperties {
public fieldWithModifier
String typedField
def untypedField
protected field1, field2, field3
private assignedField = new Date()
static classField
public static final String CONSTA = 'a', CONSTB = 'b'
def someMethod(){
def localUntypedMethodVar = 1
int localTypedMethodVar = 1
def localVarWithoutAssignment, andAnotherOne
}
}
def localvar = 1 //#A
boundvar1 = 1 //#B
def someMethod(){ //#C
def localMethodVar = 1 //#C
boundvar2 = 1 //#C
} //#C
someMethod()
//#A Local variable to the script
//#B From the binding
//#C Local method to the script
================================================
FILE: listings/chap07/Listing_07_02_TypeBreaking_Assignment.groovy
================================================
final String PI = '3.14'
assert PI.class.name == 'java.lang.String'
assert PI.size() == 4
GroovyAssert.shouldFail(ClassCastException){
Float areaOfCircleRadiusOne = PI
}
================================================
FILE: listings/chap07/Listing_07_03_Referencing_Fields.groovy
================================================
class Counter {
public count = 0
}
def counter = new Counter()
counter.count = 1
assert counter.count == 1
def fieldName = 'count'
counter[fieldName] = 2
assert counter['count'] == 2
================================================
FILE: listings/chap07/Listing_07_04_Overriding_Field_Access.groovy
================================================
class PretendFieldCounter {
public count = 0
Object get (String name) {
return 'pretend value'
}
void set (String name, Object value) {
count++
}
}
def pretender = new PretendFieldCounter()
assert pretender.isNoField == 'pretend value'
assert pretender.count == 0
pretender.isNoFieldEither = 'just to increase counter'
assert pretender.count == 1
================================================
FILE: listings/chap07/Listing_07_05_Declaring_Methods.groovy
================================================
class ClassWithTypedAndUntypedMethods {
static void main(args) { //#1
def some = new ClassWithTypedAndUntypedMethods()
some.publicVoidMethod()
assert 'hi' == some.publicUntypedMethod()
assert 'ho' == some.publicTypedMethod()
combinedMethod() //#A
}
void publicVoidMethod() { }
def publicUntypedMethod() {
return 'hi'
}
String publicTypedMethod() {
return 'ho'
}
private static final void combinedMethod() { }
}
//#1 Implicit public
//#A Call static method of current class
================================================
FILE: listings/chap07/Listing_07_06_Declaring_Parameters.groovy
================================================
class ClassWithTypedAndUntypedMethodParams {
static void main(args) {
assert 'untyped' == method(1)
assert 'typed' == method('whatever')
assert 'two args' == method(1, 2)
}
static method(arg) {
return 'untyped'
}
static method(String arg) {
return 'typed'
}
static method(arg1, Number arg2) {
return 'two args'
}
}
================================================
FILE: listings/chap07/Listing_07_07_Parameter_Usages.groovy
================================================
class Summer {
def sumWithDefaults(a, b, c=0){ //#1
return a + b + c
}
def sumWithList(List args){ //#2
return args.inject(0){sum,i -> sum += i}
}
def sumWithOptionals(a, b, Object[] optionals){ //#3
return a + b + sumWithList(optionals.toList())
}
def sumNamed(Map args){ //#4
['a','b','c'].each{args.get(it,0)}
return args.a + args.b + args.c
}
}
def summer = new Summer()
assert 2 == summer.sumWithDefaults(1,1)
assert 3 == summer.sumWithDefaults(1,1,1)
assert 2 == summer.sumWithList([1,1])
assert 3 == summer.sumWithList([1,1,1])
assert 2 == summer.sumWithOptionals(1,1)
assert 3 == summer.sumWithOptionals(1,1,1)
assert 2 == summer.sumNamed(a:1, b:1)
assert 3 == summer.sumNamed(a:1, b:1, c:1)
assert 1 == summer.sumNamed(c:1)
//#1 Explicit arguments and a default value
//#2 Define arguments as a list
//#3 Optional arguments as an array
//#4 Define arguments as a map
================================================
FILE: listings/chap07/Listing_07_08_Safe_Dereferencing.groovy
================================================
def map = [a:[b:[c:1]]]
assert map.a.b.c == 1
if (map && map.a && map.a.x){ //#1
assert map.a.x.c == null
}
try {
assert map.a.x.c == null
} catch (NullPointerException ignore){ //#2
}
assert map?.a?.x?.c == null //#3
//#1 Protect with if: short-circuit evaluation
//#2 Protect with try/catch
//#3 Safe dereferencing
================================================
FILE: listings/chap07/Listing_07_09_Instantiation.groovy
================================================
class VendorWithCtor {
String name, product
VendorWithCtor(name, product) { //#A
this.name = name
this.product = product
}
}
def first = new VendorWithCtor('Canoo','ULC') //#B
def second = ['Canoo','ULC'] as VendorWithCtor //#1
VendorWithCtor third = ['Canoo','ULC'] //#2
//#A Constructor definition
//#B Normal constructor use
//#1 Coercion with as
//#2 Coercion in assignment
================================================
FILE: listings/chap07/Listing_07_10_Instantiation_Named.groovy
================================================
class SimpleVendor {
String name, product
}
new SimpleVendor()
new SimpleVendor(name: 'Canoo')
new SimpleVendor(product: 'ULC')
new SimpleVendor(name: 'Canoo', product: 'ULC')
def vendor = new SimpleVendor(name: 'Canoo')
assert 'Canoo' == vendor.name
================================================
FILE: listings/chap07/Listing_07_11_Classes.groovy
================================================
class Vendor {
public String name
public String product
public Address address = new Address()
}
class Address {
public String street, town, state
public int zip
}
def canoo = new Vendor()
canoo.name = 'Canoo Engineering AG'
canoo.product = 'UltraLightClient (ULC)'
canoo.address.street = 'Kirschgartenst. 7'
canoo.address.zip = 4051
canoo.address.town = 'Basel'
canoo.address.state = 'Switzerland'
assert canoo.dump() =~ /ULC/
assert canoo.address.dump() =~ /Basel/
================================================
FILE: listings/chap07/Listing_07_13_Import.groovy
================================================
import business.*
def canoo = new Vendor()
canoo.name = 'Canoo Engineering AG'
canoo.product = 'UltraLightClient (ULC)'
assert canoo.dump() =~ /ULC/
================================================
FILE: listings/chap07/Listing_07_14_Import_As_BugFix.groovy
================================================
import thirdparty.MathLib as OrigMathLib
class MathLib extends OrigMathLib {
Integer twice(Integer value) {
return value * 2
}
}
// nothing changes below here //#A
def mathlib = new MathLib()
assert 10 == mathlib.twice(5) //#B
assert 2 == mathlib.half(5) //#C
//#A Usage code for library remains unchanged
//#B Invoke fixed method
//#C Invoke original method
================================================
FILE: listings/chap07/Listing_07_15_Import_As_NameClash.groovy
================================================
import thirdparty.MathLib as TwiceHalfMathLib
import thirdparty2.MathLib as IncMathLib
def math1 = new TwiceHalfMathLib()
def math2 = new IncMathLib()
assert 3 == math1.half(math2.increment(5))
================================================
FILE: listings/chap07/Listing_07_16_Multimethods.groovy
================================================
def oracle(Object o) { return 'object' }
def oracle(String o) { return 'string' }
Object x = 1
Object y = 'foo'
assert 'object' == oracle(x)
assert 'string' == oracle(y) //#A
//#A This would return object in Java
================================================
FILE: listings/chap07/Listing_07_17_MultiEquals.groovy
================================================
class Equalizer {
boolean equals(Equalizer e){
return true
}
}
Object same = new Equalizer()
Object other = new Object()
assert new Equalizer().equals( same )
assert ! new Equalizer().equals( other )
================================================
FILE: listings/chap07/Listing_07_18_Traits.groovy
================================================
trait HasId { //#1
long id
}
trait HasVersion {
long version
}
trait Persistent {
boolean save() { println "saving ${this.dump()}" }
}
trait Entity implements Persistent, HasId, HasVersion { //#2
boolean save() {
version++
Persistent.super.save() //#3
}
}
class Publication implements Entity { //#4
String title
}
class Book extends Publication {
String isbn
}
Entity gina = new Book(id:1, version:1, title:"gina", isbn:"111111")
gina.save()
assert gina.version == 2
//#1 Defining a trait with state
//#2 Traits can use subtyping
//#3 Use specific methods
//#4 Implementing the trait
================================================
FILE: listings/chap07/Listing_07_19_Declaring_Beans.groovy
================================================
import java.io.Serializable
class MyBean implements Serializable {
def untyped
String typed
def item1, item2
def assigned = 'default value'
}
def bean = new MyBean()
assert 'default value' == bean.getAssigned()
bean.setUntyped('some value')
assert 'some value' == bean.getUntyped()
bean = new MyBean(typed:'another value')
assert 'another value' == bean.getTyped()
================================================
FILE: listings/chap07/Listing_07_20_Calling_Beans.groovy
================================================
class MrBean {
String firstname, lastname //#A
String getName(){ //#1
return "$firstname $lastname"
}
}
def bean = new MrBean(firstname: 'Rowan') //#B
bean.lastname = 'Atkinson' //#2
assert 'Rowan Atkinson' == bean.name //#3
//#A Groovy style properties
//#1 Getter for derived property
//#B Generic constructor
//#2 Call setter
//#3 Call getter
================================================
FILE: listings/chap07/Listing_07_21_Calling_Beans_Advanced.groovy
================================================
class DoublerBean {
public value //#A
void setValue(value){
this.value = value //#1
}
def getValue(){
value * 2 //#2
}
}
def bean = new DoublerBean(value: 100)
assert 200 == bean.value //#3
assert 100 == bean.@value //#B
//#A Visible field
//#1 Inner field access
//#2 Inner field access
//#3 Property access
//#B Outer field access
================================================
FILE: listings/chap07/Listing_07_22_Property_Methods.groovy
================================================
class ClassWithProperties {
def someProperty
public someField
private somePrivateField
}
def obj = new ClassWithProperties()
def store = []
obj.properties.each { property ->
store += property.key
store += property.value
}
assert store.contains('someProperty')
assert store.contains('someField') == false
assert store.contains('somePrivateField') == false
assert store.contains('class')
assert obj.properties.size() == 2
================================================
FILE: listings/chap07/Listing_07_23_Expando.groovy
================================================
def boxer = new Expando()
assert null == boxer.takeThis
boxer.takeThis = 'ouch!'
assert 'ouch!' == boxer.takeThis
boxer.fightBack = {times -> delegate.takeThis * times }
assert 'ouch!ouch!ouch!' == boxer.fightBack(3)
================================================
FILE: listings/chap07/Listing_07_24_GPath.groovy
================================================
class Invoice { //#A
List items //#A
Date date //#A
} //#A
class LineItem { //#A
Product product //#A
int count //#A
int total() { //#A
return product.dollar * count //#A
} //#A
} //#A
class Product { //#A
String name //#A
def dollar //#A
} //#A
def ulcDate = Date.parse('yyyy-MM-dd', '2015-01-01')
def otherDate = Date.parse('yyyy-MM-dd', '2015-02-02')
def ulc = new Product(dollar:1499, name:'ULC') //#B
def ve = new Product(dollar:499, name:'Visual Editor') //#B
//#B
def invoices = [ //#B
new Invoice(date:ulcDate, items: [ //#B
new LineItem(count:5, product:ulc), //#B
new LineItem(count:1, product:ve) //#B
]), //#B
new Invoice(date:otherDate, items: [ //#B
new LineItem(count:4, product:ve) //#B
]) //#B
] //#B
def allItems = invoices.items.flatten()
assert [5*1499, 499, 4*499] == allItems*.total() //#1
assert ['ULC'] == allItems.grep{it.total() > 7000}.product.name //#2
def searchDates = invoices.grep{ //#3
it.items.any{it.product == ulc} //#3
}.date*.toString() //#3
assert [ulcDate.toString()] == searchDates
//#A Set up data structures
//#B Fill with sample data
//#1 Total for each line item
//#2 Query of product names
//#3 Query of invoice date
================================================
FILE: listings/chap07/business/Vendor.groovy
================================================
package business
class Vendor {
public String name
public String product
public Address address = new Address()
}
class Address {
public String street, town, state
public int zip
}
================================================
FILE: listings/chap07/snippet0703_Implicit_Closure_To_SAM.groovy
================================================
import java.awt.event.ActionListener
listeners = []
def addListener(ActionListener al) { listeners << al }
addListener { println "I heard that!" }
listeners*.actionPerformed()
================================================
FILE: listings/chap07/snippet0705_Spread_List.groovy
================================================
def getList(){
return [1,2,3]
}
def sum(a,b,c){
return a + b + c
}
assert 6 == sum(*list)
================================================
FILE: listings/chap07/snippet0705_Spread_Map.groovy
================================================
def map = [a:1,b:2]
assert [a:1, b:2, c:3] == [c:3, *:map]
================================================
FILE: listings/chap07/snippet0705_Spread_Range.groovy
================================================
def range = (1..3)
assert [0,1,2,3] == [0,*range]
================================================
FILE: listings/chap07/thirdparty/MathLib.groovy
================================================
package thirdparty
class MathLib {
Integer twice(Integer value) {
return value * 3 // intentionally wrong!
}
Integer half(Integer value) {
return value / 2
}
}
================================================
FILE: listings/chap07/thirdparty2/MathLib.groovy
================================================
package thirdparty2
class MathLib {
Integer increment(Integer value) { value + 1 }
}
================================================
FILE: listings/chap08/Listing_08_01_method_missing.groovy
================================================
class Pretender {
def methodMissing(String name, Object args) {
"called $name with $args"
}
}
def bounce = new Pretender()
assert bounce.hello('world') == 'called hello with [world]'
================================================
FILE: listings/chap08/Listing_08_02_mini_gorm.groovy
================================================
class MiniGorm {
def db = []
Object methodMissing(String name, Object args) {
println name
db.find { it[name.toLowerCase()-'findby'] == args[0] } //#1
}
}
def people = new MiniGorm() //#2
def dierk = [first: 'Dierk', last:'Koenig']
def paul = [first: 'Paul', last:'King']
people.db << dierk << paul
assert people.findByFirst('Dierk') == dierk //#3
assert people.findByLast('King') == paul
================================================
FILE: listings/chap08/Listing_08_03_property_missing.groovy
================================================
class PropPretender {
def propertyMissing(String name) {
"accessed $name"
}
}
def bounce = new PropPretender()
assert bounce.hello == 'accessed hello'
================================================
FILE: listings/chap08/Listing_08_04_bin_property.groovy
================================================
def propertyMissing(String name) {
int result = 0
name.each {
result <<= 1
if (it == 'I') result++
}
return result
}
assert IIOI +
IOI ==
IOOIO
================================================
FILE: listings/chap08/Listing_08_05_closure_dynamic.groovy
================================================
class DynamicPretender {
Closure whatToDo = { name -> "accessed $name"} //#1
def propertyMissing(String name) {
whatToDo(name) //#2
}
}
def one = new DynamicPretender()
assert one.hello == 'accessed hello'
one.whatToDo = { name -> name.size() } //#3
assert one.hello == 5
================================================
FILE: listings/chap08/Listing_08_06_property_method.groovy
================================================
class NoParens {
def getProperty(String propertyName) {
if (metaClass.hasProperty(this, propertyName)) { //#1
return metaClass.getProperty(this, propertyName)
}
invokeMethod propertyName, null //#2
}
}
class PropUser extends NoParens { //#3
boolean existingProperty = true
}
def user = new PropUser()
assert user.existingProperty
assert user.toString() == user.toString //#4
================================================
FILE: listings/chap08/Listing_08_07_MetaClass_jdk7_only.groovy
================================================
MetaClass mc = String.metaClass
final Object[] NO_ARGS = []
assert 1 == mc.respondsTo("toString", NO_ARGS).size()
assert 3 == mc.properties.size()
assert 74 == mc.methods.size()
assert 176 == mc.metaMethods.size()
assert "" == mc.invokeMethod("","toString", NO_ARGS)
assert null == mc.invokeStaticMethod(String, "println", NO_ARGS)
assert "" == mc.invokeConstructor(NO_ARGS)
================================================
FILE: listings/chap08/Listing_08_07_MetaClass_jdk8_plus.groovy
================================================
MetaClass mc = String.metaClass
final Object[] NO_ARGS = []
assert 1 == mc.respondsTo("toString", NO_ARGS).size()
assert 3 == mc.properties.size()
assert 76 == mc.methods.size()
assert 176 == mc.metaMethods.size()
assert "" == mc.invokeMethod("","toString", NO_ARGS)
assert null == mc.invokeStaticMethod(String, "println", NO_ARGS)
assert "" == mc.invokeConstructor(NO_ARGS)
================================================
FILE: listings/chap08/Listing_08_08_ProxyMetaClass.groovy
================================================
class InspectMe {
int outer(){
return inner()
}
private int inner(){
return 1
}
}
def tracer = new TracingInterceptor(writer: new StringWriter()) //#1
def proxyMetaClass = ProxyMetaClass.getInstance(InspectMe)
proxyMetaClass.interceptor = tracer
InspectMe inspectMe = new InspectMe()
inspectMe.metaClass = proxyMetaClass //#2
assert 1 == inspectMe.outer() //#3
assert "\n" + tracer.writer.toString() == """
before InspectMe.outer()
before InspectMe.inner()
after InspectMe.inner()
after InspectMe.outer()
"""
================================================
FILE: listings/chap08/Listing_08_09_Expando.groovy
================================================
def boxer = new Expando()
boxer.takeThis = 'ouch!'
boxer.fightBack = { times -> takeThis * times }
assert boxer.fightBack(3) == 'ouch!ouch!ouch!'
================================================
FILE: listings/chap08/Listing_08_10_EMC.groovy
================================================
assert String.metaClass =~ /MetaClassImpl/
String.metaClass.low = {-> delegate.toLowerCase() }
assert String.metaClass =~ /ExpandoMetaClass/
assert "DiErK".low() == "dierk"
================================================
FILE: listings/chap08/Listing_08_11_EMC_Groovy_Class.groovy
================================================
class MyGroovy1 { }
def before = new MyGroovy1()
MyGroovy1.metaClass.myProp = "MyGroovy prop"
MyGroovy1.metaClass.test = {-> myProp }
try {
before.test() //#1
assert false, "should throw MME"
} catch(mme) { }
assert new MyGroovy1().test() == "MyGroovy prop"
================================================
FILE: listings/chap08/Listing_08_12_EMC_Groovy_Object.groovy
================================================
class MyGroovy2 { }
def myGroovy = new MyGroovy2()
myGroovy.metaClass.myProp = "MyGroovy prop"
myGroovy.metaClass.test = {-> myProp }
try {
new MyGroovy2().test() //#1
assert false, "should throw MME"
} catch(mme) { }
assert myGroovy.test() == "MyGroovy prop"
================================================
FILE: listings/chap08/Listing_08_13_EMC_Java_Object.groovy
================================================
def myJava = new String()
myJava.metaClass.myProp = "MyJava prop"
myJava.metaClass.test = {-> myProp }
try {
new String().test() //#1
assert false, "should throw MME"
} catch(mme) { }
assert myJava.test() == "MyJava prop"
================================================
FILE: listings/chap08/Listing_08_14_EMC_Builder.groovy
================================================
def move(string, distance) {
string.collect { (it as char) + distance as char }.join()
}
String.metaClass {
shift = -1
encode {-> move delegate, shift }
decode {-> move delegate, -shift }
getCode {-> encode() }
getOrig {-> decode() }
}
assert "IBM".encode() == "HAL"
assert "HAL".orig == "IBM"
def ibm = "IBM"
ibm.shift = 7
assert ibm.code == "PIT"
================================================
FILE: listings/chap08/Listing_08_15_EMC_static.groovy
================================================
Integer.metaClass.static.answer = {-> 42}
assert Integer.answer() == 42
================================================
FILE: listings/chap08/Listing_08_16_EMC_super.groovy
================================================
class MySuperGroovy { }
class MySubGroovy extends MySuperGroovy { }
MySuperGroovy.metaClass.added = {-> true }
assert new MySubGroovy().added()
Map.metaClass.toTable = {->
delegate.collect{ [it.key, it.value] }
}
assert [a:1, b:2].toTable() == [
['a', 1],
['b', 2]
]
================================================
FILE: listings/chap08/Listing_08_17_EMC_hooks.groovy
================================================
String.metaClass {
rightShiftUnsigned = { prefix ->
delegate.replaceAll(~/\w+/) { prefix + it }
}
methodMissing = { String name, args->
delegate.replaceAll name, args[0]
}
}
def people = "Dierk,Guillaume,Paul,Hamlet,Jon"
people >>>= "\n "
people = people.Dierk('Mittie').Guillaume('Mr.G')
assert people == '''
Mittie,
Mr.G,
Paul,
Hamlet,
Jon'''
================================================
FILE: listings/chap08/Listing_08_18_Existing_Categories.groovy
================================================
import groovy.time.TimeCategory
def janFirst1970 = new Date(0)
use TimeCategory, {
Date xmas = janFirst1970 + 1.year - 7.days
assert xmas.month == Calendar.DECEMBER
assert xmas.date == 25
}
use Collections, {
def list = [0, 1, 2, 3]
list.rotate 1
assert list == [3, 0, 1, 2]
}
================================================
FILE: listings/chap08/Listing_08_19_Marshal.groovy
================================================
class Marshal {
static String marshal(Integer self) {
self.toString()
}
static Integer unMarshal(String self) {
self.toInteger()
}
}
use Marshal, {
assert 1.marshal() == "1"
assert "1".unMarshal() == 1
[Integer.MIN_VALUE, -1, 0, Integer.MAX_VALUE].each {
assert it.marshal().unMarshal() == it
}
}
================================================
FILE: listings/chap08/Listing_08_20_MarshalCategory.groovy
================================================
@Category(Integer) //#1
class IntegerMarshal {
String marshal() {
toString() //#2
}
}
@Category(String)
class StringMarshal {
Integer unMarshal() {
this.toInteger() //#3
}
}
use ([IntegerMarshal, StringMarshal]) { //#4
assert 1.marshal() == "1"
assert "1".unMarshal() == 1
}
//#1 Specify the type of self
//#2 Implicit this
//#3 Explicit this
//#4 List variant of use
================================================
FILE: listings/chap08/Listing_08_21_Test_Mixin.groovy
================================================
@Mixin(MessageFeature)
class FirstTest extends GroovyTestCase {
void testWithMixinUsage() {
message = "Called from Test"
assertMessage "Called from Test"
}
}
class MessageFeature {
def message
void assertMessage(String msg) {
assertEquals msg, message
}
}
================================================
FILE: listings/chap08/Listing_08_22_Sieve_Mixin.groovy
================================================
class EvenSieve {
def getNo2() {
removeAll { it % 2 == 0 }
return this
}
}
class MinusSieve {
def minus(int num) {
removeAll { it % num == 0 }
return this
}
}
ArrayList.mixin EvenSieve, MinusSieve
assert (0..10).toList().no2 - 3 - 5 == [1, 7]
================================================
FILE: listings/chap08/Listing_08_23_Millimeter.groovy
================================================
Number.metaClass {
getMm = { delegate }
getCm = { delegate * 10.mm }
getM = { delegate * 100.cm }
}
assert 1.m + 20.cm - 8.mm == 1.192.m
================================================
FILE: listings/chap08/Listing_08_24_create_factory.groovy
================================================
import java.awt.Dimension
Class.metaClass.make = { Object[] args ->
delegate.metaClass.invokeConstructor(*args)
}
assert new HashMap() == HashMap.make()
assert new Integer(42) == Integer.make(42)
assert new Dimension(2, 3) == Dimension.make(2, 3)
================================================
FILE: listings/chap08/Listing_08_25_fake_assign.groovy
================================================
interface ChannelComponent {}
class Producer implements ChannelComponent {
List<Integer> outChannel
}
class Adaptor implements ChannelComponent {
List<Integer> inChannel
List<String> outChannel
}
class Printer implements ChannelComponent {
List<String> inChannel
}
class WiringCategory {
static connections = []
static setInChannel(ChannelComponent self, value){ //#1
connections << [target:self, source:value]
}
static getOutChannel(ChannelComponent self){
self
}
}
Producer producer = new Producer()
Adaptor adaptor = new Adaptor()
Printer printer = new Printer()
use WiringCategory, {
adaptor.inChannel = producer.outChannel //|#2
printer.inChannel = adaptor.outChannel //|#2
}
assert WiringCategory.connections == [
[source: producer, target: adaptor],
[source: adaptor, target: printer]
]
================================================
FILE: listings/chap08/Listing_08_26_restore_emc.groovy
================================================
MetaClass oldMetaClass = String.metaClass //#1
MetaMethod alias = String.metaClass.metaMethods //#2
.find { it.name == 'size' }
String.metaClass {
oldSize = { -> alias.invoke delegate }
size = { -> oldSize() * 2 }
}
assert "abc".size() == 6
assert "abc".oldSize() == 3
if (oldMetaClass.is(String.metaClass)){
String.metaClass { //#3
size = { -> alias.invoke delegate }
oldSize = { -> throw new UnsupportedOperationException() }
}
} else {
String.metaClass = oldMetaClass //#4
}
assert "abc".size() == 3
================================================
FILE: listings/chap08/Listing_08_27_intercept_cache_invoke.groovy
================================================
ArrayList.metaClass.methodMissing = { String name, Object args ->
assert name.startsWith("findBy")
assert args.size() == 1
Object.metaClass."$name" = { value -> //#1
delegate.find { it[name.toLowerCase()-'findby'] == value }
}
delegate."$name"(args[0]) //#2
}
def data = [
[name:'moon', au: 0.0025],
[name:'sun', au: 1 ],
[name:'neptune', au:30 ],
]
assert data.findByName('moon') //#3
assert data.findByName('sun') //#4
assert data.findByAu(1)
================================================
FILE: listings/chap08/custom/Custom.groovy
================================================
package custom
class Custom {
}
================================================
FILE: listings/chap08/custom/useCustom.groovy
================================================
package custom
assert new Custom().metaClass =~ /CustomMetaClass/
================================================
FILE: listings/chap08/failing_Listing_08_15_EMC_static.groovy
================================================
Integer.metaClass.static.answer = 42
assert Integer.answer == 42 // no such property
================================================
FILE: listings/chap08/failing_Listing_08_16_EMC_super.groovy
================================================
ExpandoMetaClass.enableGlobally()
Map.metaClass.getTable = {->
delegate.collect{ [it.key, it.value] }
}
assert [a:1, b:2].table == [['a', 1], ['b', 2]]
================================================
FILE: listings/chap08/groovy/runtime/metaclass/custom/CustomMetaClass.groovy
================================================
package groovy.runtime.metaclass.custom
class CustomMetaClass extends MetaClassImpl {
CustomMetaClass(MetaClassRegistry registry, Class theClass) {
super(registry, theClass)
println "custom meta class is in use"
}
}
================================================
FILE: listings/chap08/markup.html
================================================
================================================
FILE: listings/chap09/.gradle/2.2.1/taskArtifacts/cache.properties
================================================
#Sun Feb 01 17:04:25 CET 2015
================================================
FILE: listings/chap09/Listing_09_01_ToStringDetective.groovy
================================================
import groovy.transform.ToString
@ToString
class Detective {
String firstName, lastName
}
def sherlock = new Detective(firstName: 'Sherlock', lastName: 'Holmes')
assert sherlock .toString() == 'Detective(Sherlock, Holmes)'
================================================
FILE: listings/chap09/Listing_09_02_ToStringSleuth.groovy
================================================
import groovy.transform.ToString
@ToString(includeNames = true, ignoreNulls = true)
class Sleuth {
String firstName, lastName
}
def nancy = new Sleuth(firstName: 'Nancy', lastName: 'Drew')
assert nancy.toString() == 'Sleuth(firstName:Nancy, lastName:Drew)'
nancy.lastName = null
assert nancy.toString() == 'Sleuth(firstName:Nancy)'
================================================
FILE: listings/chap09/Listing_09_03_EqualsAndHashCode.groovy
================================================
import groovy.transform.EqualsAndHashCode
@EqualsAndHashCode
class Actor {
String firstName, lastName
}
def magneto = new Actor(firstName:'Ian', lastName: 'McKellen')
def gandalf = new Actor(firstName:'Ian', lastName: 'McKellen')
assert magneto == gandalf
================================================
FILE: listings/chap09/Listing_09_04_TupleConstructor.groovy
================================================
import groovy.transform.TupleConstructor
@TupleConstructor
class Athlete {
String firstName, lastName
}
def a1 = new Athlete('Michael', 'Jordan')
def a2 = new Athlete('Michael')
assert a1.firstName == a2.firstName
================================================
FILE: listings/chap09/Listing_09_05_Lazy.groovy
================================================
class Resource { //#1
private static alive = 0
private static used = 0
Resource() { alive++ }
def use() { used++ }
static stats() { "$alive alive, $used used" }
}
class ResourceMain {
def res1 = new Resource() //#2
@Lazy res2 = new Resource() //#3
@Lazy static res3 = { new Resource() }() //#4
@Lazy(soft=true) volatile Resource res4 //#5
}
new ResourceMain().with {
assert Resource.stats() == '1 alive, 0 used' //#6
res2.use()
res3.use()
res4.use()
assert Resource.stats() == '4 alive, 3 used' //#7
assert res4 instanceof Resource //#8
def expected = 'res4=java.lang.ref.SoftReference'
assert it.dump().contains(expected) //#9
}
//#1 Define Resource class with inbuilt statistics
//#2 Declare one normal resource
//#3 Declare one @Lazy resource
//#4 Declare static resource
//#5 Thread safe and compatible with garbage collection
//#6 After ResourceMain creation just res1 is alive
//#7 Using res2, res3, res4 creates instances lazily
//#8 Verify res4 class
//#9 Verify soft reference used internally
================================================
FILE: listings/chap09/Listing_09_06_IndexedProperty.groovy
================================================
import groovy.transform.IndexedProperty
class Author {
String name
@IndexedProperty List<String> books
}
def books = ['The Mysterious Affair at Styles',
'The Murder at the Vicarage']
new Author(name: 'Agatha Christie', books: books).with {
books[0] = 'Murder on the Orient Express' //#1
setBooks(0, 'Death on the Nile') //#2
assert getBooks(0) == 'Death on the Nile' //#3
}
//#1 Groovy idiom for setting the first property
//#2 JavaBean approach to setting a single element
//#3 JavaBean approach to reading a single element
================================================
FILE: listings/chap09/Listing_09_07_InheritConstructors.groovy
================================================
import groovy.transform.InheritConstructors
@InheritConstructors
class MyPrintWriter extends PrintWriter { }
def pw1 = new MyPrintWriter(new File('out1.txt')) //#A
def pw2 = new MyPrintWriter('out2.txt', 'US-ASCII') //#B
[pw1, pw2].each {
it << 'foo'
it.close()
}
assert new File('out1.txt').text == new File('out2.txt').text
['out1.txt', 'out2.txt'].each{ new File(it).delete() }
//#A File file variant
//#B String fileName, String charset variant
================================================
FILE: listings/chap09/Listing_09_08_Sortable.groovy
================================================
import groovy.transform.Sortable
@Sortable(includes = 'last,initial') //#1
class Politician {
String first
Character initial
String last
String initials() { first[0] + initial + last[0] }
}
def politicians = [
new Politician(first: 'Margaret', initial: 'H', last: 'Thatcher'),
new Politician(first: 'George', initial: 'W', last: 'Bush')
]
def sorted = politicians.toSorted() //#2
assert sorted*.initials() == ['GWB', 'MHT']
def byInitial = Politician.comparatorByInitial() //#3
sorted = politicians.toSorted(byInitial) //#4
assert sorted*.initials() == ['MHT', 'GWB']
//#1 Sorts by last then initial
//#2 Performs default sort
//#3 Autogenerates comparator based on initial
//#4 Sorts by initial
================================================
FILE: listings/chap09/Listing_09_09_Builder.groovy
================================================
import groovy.transform.builder.Builder
@Builder
class Chemist {
String first
String last
int born
}
def builder = Chemist.builder() //#1
def c = builder.first("Marie").last("Curie").born(1867).build() //#2
assert c.first == "Marie"
assert c.last == "Curie"
assert c.born == 1867
//#1 Accessing a builder instance
//#2 Fluent API style instance creation
================================================
FILE: listings/chap09/Listing_09_10_Canonical.groovy
================================================
import groovy.transform.Canonical
@Canonical
class Inventor {
String firstName, lastName
}
def i1 = new Inventor('Thomas', 'Edison') //#A
def i2 = new Inventor('Thomas')
assert i1 != i2 //#B
assert i1.firstName == i2.firstName //#B
assert i1.toString() == 'Inventor(Thomas, Edison)' //#C
//#A Automatic tuple constructor
//#B Objects not equal despite equal firstName property
//#C Automatic toString method
================================================
FILE: listings/chap09/Listing_09_11_Immutable.groovy
================================================
import groovy.transform.Immutable
import static groovy.test.GroovyAssert.shouldFail
@Immutable
class Genius {
String firstName, lastName
}
def g1 = new Genius(firstName: 'Albert', lastName: "Einstein") //#1
assert g1.toString() == 'Genius(Albert, Einstein)' //#2
def g2 = new Genius('Leonardo', "da Vinci") //#3
assert g2.firstName == 'Leonardo' //#4
assert g1 != g2 //#5
shouldFail(ReadOnlyPropertyException) {
g2.lastName = 'DiCaprio'
}
//#1 Map-based constructor
//#2 toString method
//#3 Tuple constructor
//#4 property getter
//#5 appropriate equals and hashCode
================================================
FILE: listings/chap09/Listing_09_12_Delegate.groovy
================================================
class NoisySet2 {
@Delegate
Set delegate = new HashSet()
@Override
boolean add(item) {
println "adding $item"
delegate.add(item)
}
@Override
boolean addAll(Collection items) {
items.each { println "adding $it" }
delegate.addAll(items)
}
}
Set ns = new NoisySet2()
ns.add(1)
ns.addAll([2, 3])
assert ns.size() == 3
================================================
FILE: listings/chap09/Listing_09_13_Singleton.groovy
================================================
import static groovy.test.GroovyAssert.shouldFail
@Singleton class Zeus { }
assert Zeus.instance
def ex = shouldFail(RuntimeException) { new Zeus() }
assert ex.message ==
"Can't instantiate singleton Zeus. Use Zeus.instance"
================================================
FILE: listings/chap09/Listing_09_14_Memoized.groovy
================================================
import groovy.transform.Memoized
class Calc {
def log = []
@Memoized //#1
int sum(int a, int b) {
log << "$a+$b" //#2
a + b
}
}
new Calc().with {
assert sum(3, 4) == 7 //#3
assert sum(4, 4) == 8
assert sum(3, 4) == 7 //#4
assert log.join(' ') == '3+4 4+4' //#5
}
//#1 Enable memoization by annotating a method
//#2 Log all calculations
//#3 Calculation performed the first time
//#4 Result returned from cache
//#5 Logging shows calculations performed once each
================================================
FILE: listings/chap09/Listing_09_15_TailRecursive.groovy
================================================
import groovy.transform.TailRecursive
class ListUtil {
static reverse(List list) {
doReverse(list, [])
}
@TailRecursive
private static doReverse(List todo, List done) {
if (todo.isEmpty()) done
else doReverse(todo.tail(), [todo.head()] + done)
}
}
assert ListUtil.reverse(['a', 'b', 'c']) == ['c', 'b', 'a']
================================================
FILE: listings/chap09/Listing_09_16_Log.groovy
================================================
import groovy.util.logging.Log
@Log
class Database {
def search() {
log.fine(runLongDatabaseQuery())
}
def runLongDatabaseQuery() {
println 'Calling database'
/* ... */
return 'query result'
}
}
new Database().search()
================================================
FILE: listings/chap09/Listing_09_17_Synchronized.groovy
================================================
import groovy.transform.Synchronized
class PhoneBook1 {
private final phoneNumbers = [:]
@Synchronized
def getNumber(key) {
phoneNumbers[key]
}
@Synchronized
void addNumber(key, value) {
phoneNumbers[key] = value
}
}
def p1 = new PhoneBook1()
(0..99).collect { num ->
Thread.start {
p1.addNumber('Number' + num, '98765' + num) //#A
}
}*.join() //#B
assert p1.getNumber('Number43') == '9876543' //#C
//#A Each thread adds a dummy phonebook entry
//#B Await completion of 99 parallel threads
//#C Check a sample number
================================================
FILE: listings/chap09/Listing_09_18_SynchronizedCustomLock.groovy
================================================
import groovy.transform.Synchronized
import groovy.util.logging.Log
@Log
class PhoneBook2 {
private final phoneNumbers = [:]
private final lock = new Object[0] //#A
@Synchronized('lock') //#B
def getNumber(key) {
phoneNumbers[key]
}
def addNumber(key, value) {
log.info("Adding phone number $value")
synchronized (lock) { //#C
phoneNumbers[key] = value
}
}
}
def p2 = new PhoneBook2()
(0..99).collect { num ->
Thread.start {
p2.addNumber('Number' + num, '98765' + num)
}
}*.join()
assert p2.getNumber('Number43') == '9876543'
//#A Manually create lock
//#B Specify the lock name
//#C Manual synchronized block
================================================
FILE: listings/chap09/Listing_09_19_ReadWriteLock.groovy
================================================
import groovy.transform.*
class PhoneBook3 {
private final phoneNumbers = dummyNums() //#A
private dummyNums() {
(1..8).collectEntries {
['Number' + it, '765432' + it]
}
}
@WithReadLock
def getNumber(key) {
println "reading started for $key"
phoneNumbers[key]
sleep 80
println "reading done for $key"
}
@WithWriteLock
def addNumber(key, value) {
println "writing started for $key"
phoneNumbers[key] = value
sleep 100
println "writing done for $key"
}
}
def p3 = new PhoneBook3()
(3..4).each{ count ->
Thread.start { //#B
sleep 100 * count
p3.addNumber('Number' + count, '9876543')
}
}
(2..6).collect{ count ->
Thread.start { //#C
sleep 100 * count
p3.getNumber('Number' + count)
}
}*.join()
//#A Fill phonebook with dummy numbers
//#B Start some writer threads
//#C Start some interleaved reader threads
/*
reading started for Number2
reading started for Number3
reading done for Number2
reading done for Number3
writing started for Number3
writing done for Number3
reading started for Number4
reading done for Number4
writing started for Number4
writing done for Number4
reading started for Number5
reading started for Number6
reading done for Number6
reading done for Number5
*/
================================================
FILE: listings/chap09/Listing_09_20_AutoClone.groovy
================================================
import groovy.transform.AutoClone
@AutoClone
class Chef1 {
String name
List<String> recipes
Date born
}
def name = 'Heston Blumenthal'
def recipes = ['Snail porridge', 'Bacon & egg ice cream']
def born = Date.parse('yyyy-MM-dd', '1966-05-27')
def c1 = new Chef1(name: name, recipes: recipes, born: born)
def c2 = c1.clone()
assert c2.recipes == recipes
================================================
FILE: listings/chap09/Listing_09_21_AutoCloneCopyConstructor.groovy
================================================
import groovy.transform.*
import static groovy.transform.AutoCloneStyle.*
@TupleConstructor
@AutoClone(style=COPY_CONSTRUCTOR)
class Person {
final String name
final Date born
}
@TupleConstructor(includeSuperProperties=true,
callSuper=true)
@AutoClone(style=COPY_CONSTRUCTOR)
class Chef2 extends Person {
final List<String> recipes
}
def name = 'Jamie Oliver'
def recipes = ['Lentil Soup', 'Crispy Duck']
def born = Date.parse('yyyy-MM-dd', '1975-05-27')
def c1 = new Chef2(name, born, recipes)
def c2 = c1.clone()
assert c2.name == name
assert c2.born == born
assert c2.recipes == recipes
================================================
FILE: listings/chap09/Listing_09_22_AutoExternalize.groovy
================================================
import groovy.transform.*
@AutoExternalize
@ToString
class Composer {
String name
int born
boolean married
}
def c = new Composer(name: 'Wolfgang Amadeus Mozart',
born: 1756, married: true)
def baos = new ByteArrayOutputStream()
baos.withObjectOutputStream{ os -> os.writeObject(c) }
def bais = new ByteArrayInputStream(baos.toByteArray())
def loader = getClass().classLoader
def result
bais.withObjectInputStream(loader) {
result = it.readObject().toString()
}
assert result == 'Composer(Wolfgang Amadeus Mozart, 1756, true)'
================================================
FILE: listings/chap09/Listing_09_23_TimedInterrupt.groovy
================================================
import groovy.transform.TimedInterrupt
import java.util.concurrent.TimeoutException
import static java.util.concurrent.TimeUnit.MILLISECONDS
@TimedInterrupt(value = 480L, unit = MILLISECONDS) //#A
class BlastOff1 {
def log = []
def countdown(n) {
sleep 100
log << n
if (n == 0) log << 'ignition'
else countdown(n - 1)
}
}
def b = new BlastOff1()
Thread.start {
try {
b.countdown(10)
} catch (TimeoutException ignore) {
b.log << 'aborted'
}
}.join()
assert b.log.join(' ') == '10 9 8 7 6 aborted'
//#A Just a little less than 500 milliseconds
================================================
FILE: listings/chap09/Listing_09_24_ThreadInterrupt.groovy
================================================
import groovy.transform.ThreadInterrupt
@ThreadInterrupt
class BlastOff2 {
def log = []
def countdown(n) {
Thread.sleep 100
log << n
if (n == 0) log << 'ignition'
else countdown(n - 1)
}
}
def b = new BlastOff2()
def t1 = Thread.start {
try {
b.countdown(10)
} catch(InterruptedException ignore) {
b.log << 'aborted'
}
}
sleep 590 //#A
t1.interrupt()
t1.join()
assert b.log.join(' ') == '10 9 8 7 6 aborted'
//#A Just a little less than 600 milliseconds
================================================
FILE: listings/chap09/Listing_09_25_ConditionalInterrupt.groovy
================================================
import groovy.transform.ConditionalInterrupt
@ConditionalInterrupt({ count <= 5 })
class BlastOff3 {
def log = []
def count = 10
def countdown() {
while (count != 0) {
log << count
count--
}
log << 'ignition'
}
}
def b = new BlastOff3()
try {
b.countdown()
} catch (InterruptedException ignore) {
b.log << 'aborted'
}
assert b.log.join(' ') == '10 9 8 7 6 aborted'
================================================
FILE: listings/chap09/Listing_09_26_Field.groovy
================================================
import groovy.transform.Field
@Field List awe = [1, 2, 3]
def awesum() { awe.sum() } //#A
assert awesum() == 6
//#A The variable awe is an instance field of our script
================================================
FILE: listings/chap09/Listing_09_27_BaseScript.groovy
================================================
@BaseScript(LoggingScript)
import groovy.transform.BaseScript
abstract class LoggingScript extends Script {
def log = []
void println(args) {
log << args
System.out.println args
}
}
println 'hello'
println 3 * 5
assert log.join(' ') == 'hello 15'
================================================
FILE: listings/chap09/Listing_09_28_AstByHand.groovy
================================================
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.expr.*
import org.codehaus.groovy.ast.stmt.ReturnStatement
def ast = new ReturnStatement(
new ConstructorCallExpression(
ClassHelper.make(Date),
ArgumentListExpression.EMPTY_ARGUMENTS
)
)
assert ast instanceof ReturnStatement
================================================
FILE: listings/chap09/Listing_09_29_AstByHandWithUtils.groovy
================================================
import org.codehaus.groovy.ast.stmt.ReturnStatement
import static org.codehaus.groovy.ast.ClassHelper.make
import static org.codehaus.groovy.ast.tools.GeneralUtils.*
def ast = returnS(ctorX(make(Date)))
assert ast instanceof ReturnStatement
================================================
FILE: listings/chap09/Listing_09_30_AstBuildFromSpec.groovy
================================================
import org.codehaus.groovy.ast.builder.AstBuilder
import org.codehaus.groovy.ast.stmt.ReturnStatement
def ast = new AstBuilder().buildFromSpec {
returnStatement {
constructorCall(Date) {
argumentList {}
}
}
}
assert ast[0] instanceof ReturnStatement
================================================
FILE: listings/chap09/Listing_09_31_AstBuildFromString.groovy
================================================
import org.codehaus.groovy.ast.builder.AstBuilder
import org.codehaus.groovy.ast.stmt.BlockStatement
import org.codehaus.groovy.ast.stmt.ReturnStatement
def ast = new AstBuilder().buildFromString('new Date()')
assert ast[0] instanceof BlockStatement
assert ast[0].statements[0] instanceof ReturnStatement
================================================
FILE: listings/chap09/Listing_09_32_AstBuildFromStringMixed.groovy
================================================
import org.codehaus.groovy.ast.builder.AstBuilder
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.ast.*
def approxPI = 3.14G
def ast = new AstBuilder().buildFromString(
CompilePhase.CLASS_GENERATION,
false,
'static double getTwoPI() { def pi = ' + approxPI + '; pi * 2 }'
)
assert ast[1] instanceof ClassNode
def method = ast[1].methods.find { it.name == 'getTwoPI' }
assert method instanceof MethodNode
================================================
FILE: listings/chap09/Listing_09_33_AstBuildFromCode.groovy
================================================
import org.codehaus.groovy.ast.builder.AstBuilder
import org.codehaus.groovy.ast.stmt.ReturnStatement
def ast = new AstBuilder().buildFromCode {
new Date()
}
assert ast[0].statements[0] instanceof ReturnStatement
================================================
FILE: listings/chap09/Listing_09_34_GreeterMainTransform.groovy
================================================
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.transform.*
import java.lang.annotation.*
import org.codehaus.groovy.control.*
@Retention(RetentionPolicy.SOURCE) //#A
@Target([ElementType.METHOD]) //#A
@GroovyASTTransformationClass(classes = [MainTransformation]) //#A
@interface Main {} //#A
import static groovyjarjarasm.asm.Opcodes.*
import static org.codehaus.groovy.ast.ClassHelper.VOID_TYPE
import static org.codehaus.groovy.ast.tools.GeneralUtils.*
@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
class MainTransformation implements ASTTransformation {
private NO_EXCEPTIONS = ClassNode.EMPTY_ARRAY
private STRING_ARRAY = ClassHelper.STRING_TYPE.makeArray()
void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
if (astNodes?.size() != 2) return //#B
if (!(astNodes[0] instanceof AnnotationNode)) return //#B
if (astNodes[0].classNode.name != Main.name) return //#B
if (!(astNodes[1] instanceof MethodNode)) return //#B
def targetMethod = astNodes[1]
def targetClass = targetMethod.declaringClass
def targetInstance = ctorX(targetClass)
def callTarget = callX(targetInstance, targetMethod.name) //#C
def mainBody = block(stmt(callTarget))
def visibility = ACC_STATIC | ACC_PUBLIC
def parameters = params(param(STRING_ARRAY, 'args'))
targetClass.addMethod('main', visibility, //#D
VOID_TYPE, parameters, NO_EXCEPTIONS, mainBody) //#D
}
}
new GroovyShell(getClass().classLoader).evaluate '''
class Greeter {
@Main
def greet() {
println "Hello from the greet() method!"
}
}
'''
//#A Annotation class definition
//#B Defensive programming via guard clauses
//#C new Greeter().greet()
//#D add public static void main method
================================================
FILE: listings/chap09/Listing_09_35_GreeterMainTransform2.groovy
================================================
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.ast.stmt.BlockStatement
import org.codehaus.groovy.transform.*
import java.lang.annotation.*
import org.codehaus.groovy.control.*
@Retention(RetentionPolicy.SOURCE)
@Target([ElementType.METHOD])
@GroovyASTTransformationClass(classes = [MainTransformation2])
@interface Main2 {
boolean merge() default false //#A
}
import static org.codehaus.groovy.ast.ClassHelper.VOID_TYPE
import static org.codehaus.groovy.ast.tools.GeneralUtils.*
@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
class MainTransformation2 extends AbstractASTTransformation {
private MSG1 = "@Main2 annotation use requires no-arg constructor!"
private MSG2 = "@Main2 annotation used but main already exists!"
private NO_EXCEPTIONS = ClassNode.EMPTY_ARRAY
private NO_PARAMS = Parameter.EMPTY_ARRAY
private STRING_ARRAY = ClassHelper.STRING_TYPE.makeArray()
void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
init(astNodes, sourceUnit)
def (anno, mainMethod) = astNodes
boolean merge = getMemberValue(anno, 'merge') //#B
def mainClass = mainMethod.declaringClass
def callTarget
if (mainMethod.isStatic()) {
callTarget = mainClass
} else {
if (!hasNoArgConstructor(mainClass)) {
addError(MSG1, mainMethod) //#C
return
}
callTarget = ctorX(mainClass)
}
def callStatement = stmt(callX(callTarget, mainMethod.name))
def parameters = params(param(STRING_ARRAY, 'args'))
def existingMain = mainClass.getDeclaredMethod('main', parameters)
if (existingMain && !merge) {
addError(MSG2, mainMethod) //#D
return
}
if (existingMain) {
if (existingMain.code instanceof BlockStatement) {
existingMain.code.addStatement(callStatement) //#E
} else {
block(existingMain.code).addStatement(callStatement) //#F
}
} else {
mainClass.addMethod('main', ACC_STATIC | ACC_PUBLIC,
VOID_TYPE, parameters, NO_EXCEPTIONS, block(callStatement))
}
}
private hasNoArgConstructor(mainClass) {
def constructors = mainClass.declaredConstructors
def explicitNoArg = constructors.find { it.parameters == NO_PARAMS }
def implicitNoArg = constructors.size() == 0
implicitNoArg || explicitNoArg
}
}
new GroovyShell(getClass().classLoader).evaluate '''
class Greeter {
public static void main(String[] args) {
println 'Hello from main()'
}
@Main2(merge=true)
def greet() {
println "Hello from the greet() instance method!"
}
@Main2(merge=true)
static greet2() {
println "Hello from the greet2() static method!"
}
}
'''
//#A Define an annotation attribute
//#B Read annotation attribute value
//#C Indicate error if missing no-arg constructor
//#D Indicate error unless explicit merging
//#E Handle block statement case
//#F Handle single statement case
================================================
FILE: listings/chap09/Listing_09_38_AstTesting1.groovy
================================================
import groovy.transform.WithReadLock
import java.util.concurrent.locks.ReentrantReadWriteLock
import static java.lang.reflect.Modifier.*
class ReadWriteLockTestWithNestedClass extends GroovyTestCase {
static class MyClass { //#A
@WithReadLock
void readerMethod1() {}
}
void testLockFieldDefaultsForReadLock() {
def field = MyClass.getDeclaredField('$reentrantlock')
assert isPrivate(field.modifiers)
assert !isTransient(field.modifiers)
assert isFinal(field.modifiers)
assert !isStatic(field.modifiers)
assert field.type == ReentrantReadWriteLock
}
}
//#A Nested class
================================================
FILE: listings/chap09/Listing_09_39_AstTesting2.groovy
================================================
import java.util.concurrent.locks.ReentrantReadWriteLock
import static java.lang.reflect.Modifier.*
class ReadWriteLockTestClassLoader extends GroovyTestCase {
public void testLockFieldDefaultsForReadLock() {
def tester = new GroovyClassLoader().parseClass('''
class MyClass {
@groovy.transform.WithReadLock
public void readerMethod1() { }
}
''')
def field = tester.getDeclaredField('$reentrantlock')
assert isPrivate(field.modifiers)
assert !isTransient(field.modifiers)
assert isFinal(field.modifiers)
assert !isStatic(field.modifiers)
assert field.type == ReentrantReadWriteLock
}
}
================================================
FILE: listings/chap09/Listing_09_40_AstTesting3.groovy
================================================
import java.lang.reflect.Modifier
class ReadWriteLockTestGroovyShell extends GroovyTestCase {
public void testLockFieldDefaultsForReadLock() {
def tester = new GroovyShell().evaluate('''
import groovy.transform.WithReadLock
class MyClass {
@WithReadLock
public void readerMethod1() { }
}
new MyClass()
''')
def field = tester.getClass().getDeclaredField('$reentrantlock')
assert Modifier.isPrivate(field.modifiers)
// and more assertions...
}
}
================================================
FILE: listings/chap09/Listing_09_41_AstTesting4.groovy
================================================
import org.codehaus.groovy.tools.ast.TransformTestHelper
import static groovy.test.GroovyAssert.shouldFail
import static org.codehaus.groovy.control.CompilePhase.*
def DATE_FMT = /\w{3} \w{3} \d\d \d\d:\d\d:\d\d \S{3,9} \d{4}/
def folder = new File('src/main/groovy/regina')
def source = new File(folder, 'CompiledAtASTTransformation.groovy')
def transform = getClass().classLoader.parseClass(source).newInstance()
def helper = new TransformTestHelper(transform, PARSING)
def clazz = helper.parse(' class MyClass {} ')
shouldFail(MissingMethodException) {
clazz.getCompileTime()
}
helper = new TransformTestHelper(transform, CONVERSION)
clazz = helper.parse(' class MyClass {} ')
assert clazz.getCompiledTime()
assert clazz.getCompiledTime() =~ DATE_FMT
================================================
FILE: listings/chap09/Listing_09_42_AstTesting5.groovy
================================================
import groovy.transform.ASTTest
import org.codehaus.groovy.ast.stmt.ForStatement
import org.codehaus.groovy.control.CompilePhase
@ASTTest(phase=CompilePhase.SEMANTIC_ANALYSIS, value={ //#A
lookup('anchor').each { n -> //#B
assert n instanceof ForStatement //#C
}
})
void doSomething() {
println 'Hello, Groovy!'
anchor: for (int i=0; i<10;i++) { println "Iteration $i" } //#D
}
//#A annotate an enclosing node
//#B call lookup to find a node labeled with “anchor”
//#C perform assertion on each matching node
//#D use a label on the node
================================================
FILE: listings/chap09/Listings.txt
================================================
Listings not in the root folder:
09_36: src/main/groovy/regina/CompiledAtASTTransformation.groovy
09_37: src/test/groovy/regina/CompiledAtASTTransformationTest.groovy
================================================
FILE: listings/chap09/build/reports/tests/classes/regina.CompiledAtASTTransformationTest.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Class regina.CompiledAtASTTransformationTest</title>
<link href="../css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
<script src="../js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Class regina.CompiledAtASTTransformationTest</h1>
<div class="breadcrumbs">
<a href="../index.html">all</a> >
<a href="../packages/regina.html">regina</a> > CompiledAtASTTransformationTest</div>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">2</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">0</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.446s</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox success" id="successRate">
<div class="percent">100%</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Tests</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Tests</h2>
<table>
<thead>
<tr>
<th>Test</th>
<th>Duration</th>
<th>Result</th>
</tr>
</thead>
<tr>
<td class="success">testShouldApplyToScriptAndScriptClasses</td>
<td>0.446s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">testShouldApplyToThisTest</td>
<td>0s</td>
<td class="success">passed</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<p>Generated by
<a href="http://www.gradle.org">Gradle 2.2.1</a> at 01.02.2015 17:04:38</p>
</div>
</div>
</body>
================================================
FILE: listings/chap09/build/reports/tests/css/base-style.css
================================================
body {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 12pt;
}
body, a, a:visited {
color: #303030;
}
#content {
padding-left: 50px;
padding-right: 50px;
padding-top: 30px;
padding-bottom: 30px;
}
#content h1 {
font-size: 160%;
margin-bottom: 10px;
}
#footer {
margin-top: 100px;
font-size: 80%;
white-space: nowrap;
}
#footer, #footer a {
color: #a0a0a0;
}
ul {
margin-left: 0;
}
h1, h2, h3 {
white-space: nowrap;
}
h2 {
font-size: 120%;
}
ul.tabLinks {
padding-left: 0;
padding-top: 10px;
padding-bottom: 10px;
overflow: auto;
min-width: 800px;
width: auto !important;
width: 800px;
}
ul.tabLinks li {
float: left;
height: 100%;
list-style: none;
padding-left: 10px;
padding-right: 10px;
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 0;
-moz-border-radius: 7px;
border-radius: 7px;
margin-right: 25px;
border: solid 1px #d4d4d4;
background-color: #f0f0f0;
}
ul.tabLinks li:hover {
background-color: #fafafa;
}
ul.tabLinks li.selected {
background-color: #c5f0f5;
border-color: #c5f0f5;
}
ul.tabLinks a {
font-size: 120%;
display: block;
outline: none;
text-decoration: none;
margin: 0;
padding: 0;
}
ul.tabLinks li h2 {
margin: 0;
padding: 0;
}
div.tab {
}
div.selected {
display: block;
}
div.deselected {
display: none;
}
div.tab table {
min-width: 350px;
width: auto !important;
width: 350px;
border-collapse: collapse;
}
div.tab th, div.tab table {
border-bottom: solid #d0d0d0 1px;
}
div.tab th {
text-align: left;
white-space: nowrap;
padding-left: 6em;
}
div.tab th:first-child {
padding-left: 0;
}
div.tab td {
white-space: nowrap;
padding-left: 6em;
padding-top: 5px;
padding-bottom: 5px;
}
div.tab td:first-child {
padding-left: 0;
}
div.tab td.numeric, div.tab th.numeric {
text-align: right;
}
span.code {
display: inline-block;
margin-top: 0em;
margin-bottom: 1em;
}
span.code pre {
font-size: 11pt;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
margin: 0;
background-color: #f7f7f7;
border: solid 1px #d0d0d0;
min-width: 700px;
width: auto !important;
width: 700px;
}
================================================
FILE: listings/chap09/build/reports/tests/css/style.css
================================================
#summary {
margin-top: 30px;
margin-bottom: 40px;
}
#summary table {
border-collapse: collapse;
}
#summary td {
vertical-align: top;
}
.breadcrumbs, .breadcrumbs a {
color: #606060;
}
.infoBox {
width: 110px;
padding-top: 15px;
padding-bottom: 15px;
text-align: center;
}
.infoBox p {
margin: 0;
}
.counter, .percent {
font-size: 120%;
font-weight: bold;
margin-bottom: 8px;
}
#duration {
width: 125px;
}
#successRate, .summaryGroup {
border: solid 2px #d0d0d0;
-moz-border-radius: 10px;
border-radius: 10px;
}
#successRate {
width: 140px;
margin-left: 35px;
}
#successRate .percent {
font-size: 180%;
}
.success, .success a {
color: #008000;
}
div.success, #successRate.success {
background-color: #bbd9bb;
border-color: #008000;
}
.failures, .failures a {
color: #b60808;
}
.skipped, .skipped a {
color: #c09853;
}
div.failures, #successRate.failures {
background-color: #ecdada;
border-color: #b60808;
}
ul.linkList {
padding-left: 0;
}
ul.linkList li {
list-style: none;
margin-bottom: 5px;
}
================================================
FILE: listings/chap09/build/reports/tests/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Test Summary</title>
<link href="css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<script src="js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Test Summary</h1>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">2</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">0</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.446s</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox success" id="successRate">
<div class="percent">100%</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Packages</a>
</li>
<li>
<a href="#tab1">Classes</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Packages</h2>
<table>
<thead>
<tr>
<th>Package</th>
<th>Tests</th>
<th>Failures</th>
<th>Ignored</th>
<th>Duration</th>
<th>Success rate</th>
</tr>
</thead>
<tbody>
<tr>
<td class="success">
<a href="packages/regina.html">regina</a>
</td>
<td>2</td>
<td>0</td>
<td>0</td>
<td>0.446s</td>
<td class="success">100%</td>
</tr>
</tbody>
</table>
</div>
<div id="tab1" class="tab">
<h2>Classes</h2>
<table>
<thead>
<tr>
<th>Class</th>
<th>Tests</th>
<th>Failures</th>
<th>Ignored</th>
<th>Duration</th>
<th>Success rate</th>
</tr>
</thead>
<tbody>
<tr>
<td class="success"/>
<a href="classes/regina.CompiledAtASTTransformationTest.html">regina.CompiledAtASTTransformationTest</a>
<td>2</td>
<td>0</td>
<td>0</td>
<td>0.446s</td>
<td class="success">100%</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="footer">
<p>Generated by
<a href="http://www.gradle.org">Gradle 2.2.1</a> at 01.02.2015 17:04:38</p>
</div>
</div>
</body>
================================================
FILE: listings/chap09/build/reports/tests/js/report.js
================================================
var tabs = new Object();
function initTabs() {
var container = document.getElementById('tabs');
tabs.tabs = findTabs(container);
tabs.titles = findTitles(tabs.tabs);
tabs.headers = findHeaders(container);
tabs.select = select;
tabs.deselectAll = deselectAll;
tabs.select(0);
return true;
}
window.onload = initTabs;
function switchTab() {
var id = this.id.substr(1);
for (var i = 0; i < tabs.tabs.length; i++) {
if (tabs.tabs[i].id == id) {
tabs.select(i);
break;
}
}
return false;
}
function select(i) {
this.deselectAll();
changeElementClass(this.tabs[i], 'tab selected');
changeElementClass(this.headers[i], 'selected');
while (this.headers[i].firstChild) {
this.headers[i].removeChild(this.headers[i].firstChi
gitextract_qrfoz67k/ ├── .idea/ │ └── vcs.xml ├── LICENSE ├── README.md ├── alltests.groovy ├── listings/ │ ├── allsources.txt │ ├── appD/ │ │ ├── Listing_D_01_GStrings.groovy │ │ ├── Listing_D_02_Lists.groovy │ │ ├── Listing_D_03_Closures.groovy │ │ ├── Listing_D_04_Regex.groovy │ │ └── Listing_D_05_GPath.groovy │ ├── chap01/ │ │ ├── Listing_01_01_Gold.groovy │ │ ├── customers.xml │ │ ├── data.txt │ │ ├── groovysh.txt │ │ ├── snippet0101_customers.groovy │ │ ├── snippet0101_fileLineNumbers.groovy │ │ ├── snippet0101_newDates.txt │ │ ├── snippet0101_printPackageNames.groovy │ │ ├── snippet0101_printPackageNamesGpath.groovy │ │ ├── snippet0102_printGroovyWebSiteCount.groovy │ │ └── snippet0103_googleIpAdr.groovy │ ├── chap02/ │ │ ├── Book.groovy │ │ ├── Listing_02_01_Assertions.groovy │ │ ├── Listing_02_02_Book.txt │ │ ├── Listing_02_03_BookScript.groovy │ │ ├── Listing_02_04_BookBean.groovy │ │ ├── Listing_02_05_ImmutableBook.groovy │ │ ├── Listing_02_06_Grab.groovy │ │ ├── Listing_02_07_Clinks.groovy │ │ ├── Listing_02_08_ControlStructures.groovy │ │ ├── snippet0201_comments.groovy │ │ ├── snippet0202_failing_assert.groovy │ │ ├── snippet0202_failing_assertion_error.txt │ │ ├── snippet0203_clinks_java.groovy │ │ ├── snippet0203_gstring.groovy │ │ ├── snippet0203_int_usage.groovy │ │ ├── snippet0203_map_usage.groovy │ │ ├── snippet0203_range_usage.groovy │ │ ├── snippet0203_roman.groovy │ │ ├── snippet0204_evaluate_jdk7_only.groovy │ │ ├── snippet0204_evaluate_jdk8_only.groovy │ │ └── snippet0204_failing_typechecked.groovy │ ├── chap03/ │ │ ├── ArrayListSummer.java │ │ ├── Listing_03_01_PrimitiveMethodsObjectOperators.groovy │ │ ├── Listing_03_02_ListMapCast.groovy │ │ ├── Listing_03_03_DefiningOperators.groovy │ │ ├── Listing_03_04_DefiningGStrings.groovy │ │ ├── Listing_03_05_StringOperations.groovy │ │ ├── Listing_03_06_RegexGStrings.groovy │ │ ├── Listing_03_07_RegularExpressions.groovy │ │ ├── Listing_03_08_EachMatch.groovy │ │ ├── Listing_03_09_PatternReuse.groovy │ │ ├── Listing_03_10_PatternsClassification.groovy │ │ ├── Listing_03_11_NumberMethodsGDK.groovy │ │ ├── extra_escaped_characters_table36.groovy │ │ ├── extra_method_operators_table34.groovy │ │ ├── extra_numeric_literals_table32.groovy │ │ ├── extra_numerical_coercion_table310.groovy │ │ ├── extra_optional_typing_table33.groovy │ │ ├── extra_primitive_values_table31.groovy │ │ ├── regex_dgm.txt │ │ ├── snippet0301_autoboxing.groovy │ │ ├── snippet0304_GString_internals.groovy │ │ ├── snippet0304_stringbuffer.groovy │ │ ├── snippet0305_matcher_each_group.groovy │ │ ├── snippet0305_matcher_groups.groovy │ │ ├── snippet0305_matcher_parallel_assignment.groovy │ │ ├── snippet0305_matcher_plain.groovy │ │ └── snippet0306_GDK_methods_for_numbers.groovy │ ├── chap04/ │ │ ├── Listing_04_01_range_declarations.groovy │ │ ├── Listing_04_02_ranges_are_objects.groovy │ │ ├── Listing_04_03_custom_ranges.groovy │ │ ├── Listing_04_04_list_declarations.groovy │ │ ├── Listing_04_05_list_subscript_operator.groovy │ │ ├── Listing_04_06_list_add_remove.groovy │ │ ├── Listing_04_07_lists_control_structures.groovy │ │ ├── Listing_04_08_list_content_manipulation.groovy │ │ ├── Listing_04_09_list_other_methods.groovy │ │ ├── Listing_04_10_list_quicksort.groovy │ │ ├── Listing_04_11_list_mapreduce.groovy │ │ ├── Listing_04_12_map_declarations.groovy │ │ ├── Listing_04_13_map_accessors.groovy │ │ ├── Listing_04_14_map_query_methods.groovy │ │ ├── Listing_04_15_map_iteration.groovy │ │ ├── Listing_04_16_map_content.groovy │ │ ├── Listing_04_17_map_example.groovy │ │ ├── extra_EnumRange.groovy │ │ ├── extra_ListCast.groovy │ │ ├── extra_ListTable.groovy │ │ ├── extra_Map_as.groovy │ │ ├── extra_Map_group.groovy │ │ ├── extra_MaxMinSum.groovy │ │ ├── extra_SplitList.groovy │ │ ├── snippet0402_ListAsSet.groovy │ │ ├── snippet0402_ListRemoveNulls.groovy │ │ ├── snippet0402_ListStreams_jdk8_plus.groovy │ │ ├── snippet0403_Map_Ctor_Expression.groovy │ │ ├── snippet0403_Map_Ctor_Unquoted.groovy │ │ ├── snippet0403_Map_MapReduce.groovy │ │ └── snippet0403_Map_String_accessors.groovy │ ├── chap05/ │ │ ├── Listing_05_01_closure_simple_declaration.groovy │ │ ├── Listing_05_02_simple_method_closure.groovy │ │ ├── Listing_05_03_multi_method_closure.groovy │ │ ├── Listing_05_04_closure_all_declarations.groovy │ │ ├── Listing_05_05_simple_closure_calling.groovy │ │ ├── Listing_05_06_calling_closures.groovy │ │ ├── Listing_05_07_simple_currying.groovy │ │ ├── Listing_05_08_logging_curry_example.groovy │ │ ├── Listing_05_09_closure_scope.groovy │ │ ├── Listing_05_10_closure_accumulator.groovy │ │ ├── Listing_05_11_visitor_pattern.groovy │ │ ├── extra_ClosureProperty.groovy │ │ ├── extra_Closure_delegate.groovy │ │ ├── extra_Closure_myWith.groovy │ │ ├── snippet0501_envelope.groovy.txt │ │ ├── snippet0504_closure_default_params.groovy │ │ ├── snippet0504_closure_isCase.groovy │ │ ├── snippet0504_closure_paramcount.groovy │ │ ├── snippet0505_map_with.groovy │ │ ├── snippet0505_scoping.groovy │ │ ├── snippet0506_closure_return.groovy │ │ ├── snippet0507_closure_composition.groovy │ │ ├── snippet0508_memoize.groovy │ │ └── snippet0509_trampoline.groovy │ ├── chap06/ │ │ ├── Listing_06_01_groovy_truth.groovy │ │ ├── Listing_06_02_assignment_bug.groovy │ │ ├── Listing_06_03_if_then_else.groovy │ │ ├── Listing_06_04_conditional_operator.groovy │ │ ├── Listing_06_05_switch_basic.groovy │ │ ├── Listing_06_06_switch_advanced.groovy │ │ ├── Listing_06_07_assert_host.groovy │ │ ├── Listing_06_08_while.groovy │ │ ├── Listing_06_09_for.groovy │ │ ├── Listing_06_10_break_continue.groovy │ │ ├── Listing_06_11_exception_example.groovy │ │ ├── extra_if_return.groovy │ │ ├── extra_in_operator.groovy │ │ ├── extra_switch_return.groovy │ │ ├── myFileName.txt │ │ ├── snippet0602_bad_file_read.groovy │ │ ├── snippet0602_bad_file_read_with_message.groovy │ │ ├── snippet0602_failing_assert.groovy │ │ ├── snippet0603_each_loop_iterate.groovy │ │ ├── snippet0603_file_iterate_lines.groovy │ │ ├── snippet0603_for_loop_iterate.groovy │ │ ├── snippet0603_null_iterate.groovy │ │ ├── snippet0603_object_iterate.groovy │ │ ├── snippet0603_regex_iterate_match.groovy │ │ └── snippet0604_multicatch.groovy │ ├── chap07/ │ │ ├── Listing_07_01_Declaring_Variables.groovy │ │ ├── Listing_07_02_TypeBreaking_Assignment.groovy │ │ ├── Listing_07_03_Referencing_Fields.groovy │ │ ├── Listing_07_04_Overriding_Field_Access.groovy │ │ ├── Listing_07_05_Declaring_Methods.groovy │ │ ├── Listing_07_06_Declaring_Parameters.groovy │ │ ├── Listing_07_07_Parameter_Usages.groovy │ │ ├── Listing_07_08_Safe_Dereferencing.groovy │ │ ├── Listing_07_09_Instantiation.groovy │ │ ├── Listing_07_10_Instantiation_Named.groovy │ │ ├── Listing_07_11_Classes.groovy │ │ ├── Listing_07_13_Import.groovy │ │ ├── Listing_07_14_Import_As_BugFix.groovy │ │ ├── Listing_07_15_Import_As_NameClash.groovy │ │ ├── Listing_07_16_Multimethods.groovy │ │ ├── Listing_07_17_MultiEquals.groovy │ │ ├── Listing_07_18_Traits.groovy │ │ ├── Listing_07_19_Declaring_Beans.groovy │ │ ├── Listing_07_20_Calling_Beans.groovy │ │ ├── Listing_07_21_Calling_Beans_Advanced.groovy │ │ ├── Listing_07_22_Property_Methods.groovy │ │ ├── Listing_07_23_Expando.groovy │ │ ├── Listing_07_24_GPath.groovy │ │ ├── business/ │ │ │ └── Vendor.groovy │ │ ├── snippet0703_Implicit_Closure_To_SAM.groovy │ │ ├── snippet0705_Spread_List.groovy │ │ ├── snippet0705_Spread_Map.groovy │ │ ├── snippet0705_Spread_Range.groovy │ │ ├── thirdparty/ │ │ │ └── MathLib.groovy │ │ └── thirdparty2/ │ │ └── MathLib.groovy │ ├── chap08/ │ │ ├── Listing_08_01_method_missing.groovy │ │ ├── Listing_08_02_mini_gorm.groovy │ │ ├── Listing_08_03_property_missing.groovy │ │ ├── Listing_08_04_bin_property.groovy │ │ ├── Listing_08_05_closure_dynamic.groovy │ │ ├── Listing_08_06_property_method.groovy │ │ ├── Listing_08_07_MetaClass_jdk7_only.groovy │ │ ├── Listing_08_07_MetaClass_jdk8_plus.groovy │ │ ├── Listing_08_08_ProxyMetaClass.groovy │ │ ├── Listing_08_09_Expando.groovy │ │ ├── Listing_08_10_EMC.groovy │ │ ├── Listing_08_11_EMC_Groovy_Class.groovy │ │ ├── Listing_08_12_EMC_Groovy_Object.groovy │ │ ├── Listing_08_13_EMC_Java_Object.groovy │ │ ├── Listing_08_14_EMC_Builder.groovy │ │ ├── Listing_08_15_EMC_static.groovy │ │ ├── Listing_08_16_EMC_super.groovy │ │ ├── Listing_08_17_EMC_hooks.groovy │ │ ├── Listing_08_18_Existing_Categories.groovy │ │ ├── Listing_08_19_Marshal.groovy │ │ ├── Listing_08_20_MarshalCategory.groovy │ │ ├── Listing_08_21_Test_Mixin.groovy │ │ ├── Listing_08_22_Sieve_Mixin.groovy │ │ ├── Listing_08_23_Millimeter.groovy │ │ ├── Listing_08_24_create_factory.groovy │ │ ├── Listing_08_25_fake_assign.groovy │ │ ├── Listing_08_26_restore_emc.groovy │ │ ├── Listing_08_27_intercept_cache_invoke.groovy │ │ ├── custom/ │ │ │ ├── Custom.groovy │ │ │ └── useCustom.groovy │ │ ├── failing_Listing_08_15_EMC_static.groovy │ │ ├── failing_Listing_08_16_EMC_super.groovy │ │ ├── groovy/ │ │ │ └── runtime/ │ │ │ └── metaclass/ │ │ │ └── custom/ │ │ │ └── CustomMetaClass.groovy │ │ └── markup.html │ ├── chap09/ │ │ ├── .gradle/ │ │ │ └── 2.2.1/ │ │ │ └── taskArtifacts/ │ │ │ └── cache.properties │ │ ├── Listing_09_01_ToStringDetective.groovy │ │ ├── Listing_09_02_ToStringSleuth.groovy │ │ ├── Listing_09_03_EqualsAndHashCode.groovy │ │ ├── Listing_09_04_TupleConstructor.groovy │ │ ├── Listing_09_05_Lazy.groovy │ │ ├── Listing_09_06_IndexedProperty.groovy │ │ ├── Listing_09_07_InheritConstructors.groovy │ │ ├── Listing_09_08_Sortable.groovy │ │ ├── Listing_09_09_Builder.groovy │ │ ├── Listing_09_10_Canonical.groovy │ │ ├── Listing_09_11_Immutable.groovy │ │ ├── Listing_09_12_Delegate.groovy │ │ ├── Listing_09_13_Singleton.groovy │ │ ├── Listing_09_14_Memoized.groovy │ │ ├── Listing_09_15_TailRecursive.groovy │ │ ├── Listing_09_16_Log.groovy │ │ ├── Listing_09_17_Synchronized.groovy │ │ ├── Listing_09_18_SynchronizedCustomLock.groovy │ │ ├── Listing_09_19_ReadWriteLock.groovy │ │ ├── Listing_09_20_AutoClone.groovy │ │ ├── Listing_09_21_AutoCloneCopyConstructor.groovy │ │ ├── Listing_09_22_AutoExternalize.groovy │ │ ├── Listing_09_23_TimedInterrupt.groovy │ │ ├── Listing_09_24_ThreadInterrupt.groovy │ │ ├── Listing_09_25_ConditionalInterrupt.groovy │ │ ├── Listing_09_26_Field.groovy │ │ ├── Listing_09_27_BaseScript.groovy │ │ ├── Listing_09_28_AstByHand.groovy │ │ ├── Listing_09_29_AstByHandWithUtils.groovy │ │ ├── Listing_09_30_AstBuildFromSpec.groovy │ │ ├── Listing_09_31_AstBuildFromString.groovy │ │ ├── Listing_09_32_AstBuildFromStringMixed.groovy │ │ ├── Listing_09_33_AstBuildFromCode.groovy │ │ ├── Listing_09_34_GreeterMainTransform.groovy │ │ ├── Listing_09_35_GreeterMainTransform2.groovy │ │ ├── Listing_09_38_AstTesting1.groovy │ │ ├── Listing_09_39_AstTesting2.groovy │ │ ├── Listing_09_40_AstTesting3.groovy │ │ ├── Listing_09_41_AstTesting4.groovy │ │ ├── Listing_09_42_AstTesting5.groovy │ │ ├── Listings.txt │ │ ├── build/ │ │ │ ├── reports/ │ │ │ │ └── tests/ │ │ │ │ ├── classes/ │ │ │ │ │ └── regina.CompiledAtASTTransformationTest.html │ │ │ │ ├── css/ │ │ │ │ │ ├── base-style.css │ │ │ │ │ └── style.css │ │ │ │ ├── index.html │ │ │ │ ├── js/ │ │ │ │ │ └── report.js │ │ │ │ └── packages/ │ │ │ │ └── regina.html │ │ │ ├── resources/ │ │ │ │ └── main/ │ │ │ │ └── META-INF/ │ │ │ │ └── services/ │ │ │ │ └── org.codehaus.groovy.transform.ASTTransformation │ │ │ └── test-results/ │ │ │ ├── TEST-regina.CompiledAtASTTransformationTest.xml │ │ │ └── binary/ │ │ │ └── test/ │ │ │ └── output.bin.idx │ │ ├── build.gradle │ │ ├── gradle/ │ │ │ └── wrapper/ │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradle.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── settings.gradle │ │ ├── snippet0902_autoCloneDefault.txt │ │ ├── snippet0902_autoCloneSerialization.txt │ │ ├── snippet0902_autoExternalize.txt │ │ ├── snippet0902_fieldEquivalent.txt │ │ ├── snippet0902_mapCreation.txt │ │ ├── snippet0902_noisySetDelegateByHand.txt │ │ ├── snippet0902_noisySetInheritance.txt │ │ ├── snippet0902_nonTailCallReverseList.txt │ │ ├── snippet0902_readWriteByHand.txt │ │ ├── snippet0902_readWriteLock.txt │ │ ├── snippet0902_singletonByHand.txt │ │ ├── snippet0902_toStringEquivalent.txt │ │ ├── snippet0903_greeterExpanded.txt │ │ ├── snippet0903_greeterScript.txt │ │ ├── snippet0903_localMain.txt │ │ ├── snippet0903_localMainTransformation.txt │ │ ├── snippet0905_GetCompiledTimeScript.txt │ │ └── src/ │ │ ├── main/ │ │ │ ├── groovy/ │ │ │ │ └── regina/ │ │ │ │ └── CompiledAtASTTransformation.groovy │ │ │ └── resources/ │ │ │ └── META-INF/ │ │ │ └── services/ │ │ │ └── org.codehaus.groovy.transform.ASTTransformation │ │ └── test/ │ │ └── groovy/ │ │ └── regina/ │ │ └── CompiledAtASTTransformationTest.groovy │ ├── chap10/ │ │ ├── Greeter.java │ │ ├── Listing_10_01_Duck.groovy │ │ ├── Listing_10_02_failing_Typo.groovy │ │ ├── Listing_10_03_ClassTC.groovy │ │ ├── Listing_10_04_OneMethodTC.groovy │ │ ├── Listing_10_05_CompileTimeTypo.groovy │ │ ├── Listing_10_06_MethodNameTypo.groovy │ │ ├── Listing_10_07_MethodArgsFlipped.groovy │ │ ├── Listing_10_08_InvalidAssignments.groovy │ │ ├── Listing_10_09_AssignmentsWithCoercion.groovy │ │ ├── Listing_10_10_DefField.groovy │ │ ├── Listing_10_11_InPlaceList.groovy │ │ ├── Listing_10_12_Generics.groovy │ │ ├── Listing_10_13_ListStyleCtorRuntime.groovy │ │ ├── Listing_10_14_ListStyleCtorTC.groovy │ │ ├── Listing_10_15_MapStyleCtorBad.groovy │ │ ├── Listing_10_16_ListStyleCtor.groovy │ │ ├── Listing_10_17_ListStyleCtorFixed.groovy │ │ ├── Listing_10_18_CodeAsData.groovy │ │ ├── Listing_10_19_ClosuresBadReturnType.groovy │ │ ├── Listing_10_20_UserValidation.groovy │ │ ├── Listing_10_21_UserValidationTC.groovy │ │ ├── Listing_10_22_UserValidation_ExplicitTypes.groovy │ │ ├── Listing_10_23_UserValidation_SAM.groovy │ │ ├── Listing_10_24_UserValidation_ClosureParams.groovy │ │ ├── Listing_10_25_UserValidation_DSL.groovy │ │ ├── Listing_10_26_UserValidation_DelegatesTo.groovy │ │ ├── Listing_10_27_UserValidation_DelegatesToTarget.groovy │ │ ├── Listing_10_28_Category.groovy │ │ ├── Listing_10_29_EMC.groovy │ │ ├── Listing_10_30_Builder.groovy │ │ ├── Listing_10_31_MixedTypeChecking.groovy │ │ ├── Listing_10_32_Skip.groovy │ │ ├── Listing_10_33_FlowTyping.groovy │ │ ├── Listing_10_34_FlowTypingOk.groovy │ │ ├── Listing_10_35_LUB.groovy │ │ ├── Listing_10_36_Condition.groovy │ │ ├── Listing_10_37_ClosureSharedVar.groovy │ │ ├── Listing_10_38_LubError.groovy │ │ ├── Listing_10_39_LubOk.groovy │ │ ├── Listing_10_40_FibBench.groovy │ │ ├── Listing_10_41_JavaGreeter.txt │ │ ├── Listing_10_42_StaticCompileDispatch.groovy │ │ ├── Listing_10_43_MonkeyPatching.groovy │ │ ├── Listing_10_44_BookingDSL.groovy │ │ ├── Listing_10_45_MultiValidation.groovy │ │ ├── Listing_10_46_RobotExtension.groovy │ │ ├── Listing_10_47_SQLExtension.groovy │ │ ├── User.groovy │ │ ├── extra1004_JavaDispatch.java │ │ ├── extra1004_RuntimeGroovyDispatch.groovy │ │ ├── markup.html │ │ ├── snippet1003_GroovyGreeter.groovy │ │ ├── snippet1005_RobotMainTC.groovy │ │ └── snippet1005_SqlMainTC.groovy │ ├── chap11/ │ │ ├── Listing_11_01_SquaresFactors.xml │ │ ├── Listing_11_02_SquaresFactors.java │ │ ├── Listing_11_03_MarkupBuilderPlain.groovy │ │ ├── Listing_11_04_NodeBuilder.groovy │ │ ├── Listing_11_05_NodeBuilderLogic.groovy │ │ ├── Listing_11_06_MarkupBuilderLogic.groovy │ │ ├── Listing_11_07_MarkupBuilderHtml.groovy │ │ ├── Listing_11_08_StreamingMarkupBuilderLogic.groovy │ │ ├── Listing_11_09_ExampleBuild.xml │ │ ├── Listing_11_10_PW_SwingBuilder.groovy │ │ ├── Listing_11_11_Swing_Widgets.groovy │ │ ├── Listing_11_12_Swing_Layout.groovy │ │ ├── Listing_11_13_Table_Demo.groovy │ │ ├── Listing_11_14_Binding.groovy │ │ ├── Listing_11_15_Plotter.groovy │ │ ├── Listing_11_16_Groovyfx.groovy │ │ ├── Listing_11_17_CalorieCounterBuilderSupport.groovy │ │ ├── Listing_11_18_CalorieCounterFactoryBuilderSupport.groovy │ │ ├── Listing_11_19_CalorieCounterByHand.groovy │ │ ├── markup.html │ │ ├── snippet1103_MarkupBuilderOutput.html │ │ ├── snippet1103_MarkupWithHyphen.groovy │ │ ├── snippet1106_AntBuilderIf.groovy │ │ ├── snippet1106_AntIf.xml │ │ ├── snippet1107_Printer.groovy │ │ └── snippet1107_binding.txt │ ├── chap12/ │ │ ├── Listing_12_01_info_jdk6_only.groovy │ │ ├── Listing_12_01_info_jdk7_only.groovy │ │ ├── Listing_12_01_info_jdk8_plus.groovy │ │ ├── Listing_12_02_properties.groovy │ │ ├── Listing_12_03_File_Iteration.groovy │ │ ├── Listing_12_04_Filesystem.groovy │ │ ├── Listing_12_05_Traversal.groovy │ │ ├── Listing_12_06_File_Read.groovy │ │ ├── Listing_12_07_File_Write.groovy │ │ ├── Listing_12_08_Writer_LeftShift.groovy │ │ ├── Listing_12_09_File_Transform_jdk7_plus.groovy │ │ ├── Listing_12_10_File_ObjectStreams.groovy │ │ ├── Listing_12_11_Temp_Dir.groovy │ │ ├── Listing_12_12_Threads.groovy │ │ ├── Listing_12_13_Processes_UnixCommands.groovy │ │ ├── Listing_12_14_Processes_ZipUnzip.groovy │ │ ├── Listing_12_15_SimpleTemplateEngine.groovy │ │ ├── Listing_12_16_GroovletExample.groovy │ │ ├── Listing_12_17_HelloWorldGroovlet.groovy │ │ ├── Listing_12_19_InspectGroovlet.groovy │ │ ├── Listing_12_20_HiLowGame.groovy │ │ ├── Listing_12_21_NumberTemplate.txt │ │ ├── Listing_12_22_TemplateGroovlet.groovy │ │ ├── Number.template.html │ │ ├── data/ │ │ │ └── example.txt │ │ ├── objects.dta │ │ ├── snippet1201_SlowTyping.groovy │ │ ├── snippet1201_UseCategory.groovy │ │ ├── snippet1202_base64.groovy │ │ └── web.xml │ ├── chap13/ │ │ ├── Listing_13_01_Connecting.groovy │ │ ├── Listing_13_02_ConnectingDataSource.groovy │ │ ├── Listing_13_03_Creating.groovy │ │ ├── Listing_13_04_DbUtilClass.txt │ │ ├── Listing_13_05_Inserting.groovy │ │ ├── Listing_13_06_Reading.groovy │ │ ├── Listing_13_07_Updating.groovy │ │ ├── Listing_13_08_Delete.groovy │ │ ├── Listing_13_09_Transactions.groovy │ │ ├── Listing_13_10_Batching.groovy │ │ ├── Listing_13_11_Paging.groovy │ │ ├── Listing_13_12_Metadata.groovy │ │ ├── Listing_13_13_MoreMetadata.groovy │ │ ├── Listing_13_14_NamedOrdinal.groovy │ │ ├── Listing_13_15_StoredProcBasic.groovy │ │ ├── Listing_13_16_StoredProcParam.groovy │ │ ├── Listing_13_17_StoredProcInOut.groovy │ │ ├── Listing_13_18_DataSetBasics.groovy │ │ ├── Listing_13_19_DataSetFiltering.groovy │ │ ├── Listing_13_20_DataSetViews.groovy │ │ ├── Listing_13_21_DbHelper.txt │ │ ├── Listing_13_22_DataAccessObject.txt │ │ ├── Listing_13_23_AthleteDAO.txt │ │ ├── Listing_13_24_AthleteApplication.txt │ │ ├── Listing_13_25_AthleteAppMain.groovy │ │ ├── Listing_13_26_AthleteAppTest.groovy │ │ ├── Listing_13_27_MongoAthletes.groovy │ │ ├── Listing_13_28_NeoAthletes.groovy │ │ ├── Listing_13_29_NeoGremlin.groovy │ │ ├── extra_NeoGremlinGraph.groovy │ │ ├── layering/ │ │ │ ├── AthleteApplication.groovy │ │ │ ├── AthleteDAO.groovy │ │ │ ├── DataAccessObject.groovy │ │ │ └── DbHelper.groovy │ │ ├── marathon/ │ │ │ ├── active_tx_log │ │ │ ├── index/ │ │ │ │ ├── lucene.log.active │ │ │ │ ├── lucene.log.v0 │ │ │ │ ├── lucene.log.v1 │ │ │ │ ├── lucene.log.v2 │ │ │ │ ├── lucene.log.v3 │ │ │ │ ├── lucene.log.v4 │ │ │ │ ├── lucene.log.v5 │ │ │ │ ├── lucene.log.v6 │ │ │ │ ├── lucene.log.v7 │ │ │ │ └── lucene.log.v8 │ │ │ ├── messages.log │ │ │ ├── neostore │ │ │ ├── neostore.id │ │ │ ├── neostore.labeltokenstore.db.id │ │ │ ├── neostore.labeltokenstore.db.names │ │ │ ├── neostore.labeltokenstore.db.names.id │ │ │ ├── neostore.nodestore.db.id │ │ │ ├── neostore.nodestore.db.labels │ │ │ ├── neostore.nodestore.db.labels.id │ │ │ ├── neostore.propertystore.db.arrays │ │ │ ├── neostore.propertystore.db.arrays.id │ │ │ ├── neostore.propertystore.db.id │ │ │ ├── neostore.propertystore.db.index │ │ │ ├── neostore.propertystore.db.index.id │ │ │ ├── neostore.propertystore.db.index.keys │ │ │ ├── neostore.propertystore.db.index.keys.id │ │ │ ├── neostore.propertystore.db.strings │ │ │ ├── neostore.propertystore.db.strings.id │ │ │ ├── neostore.relationshipgroupstore.db.id │ │ │ ├── neostore.relationshipstore.db.id │ │ │ ├── neostore.relationshiptypestore.db.id │ │ │ ├── neostore.relationshiptypestore.db.names │ │ │ ├── neostore.relationshiptypestore.db.names.id │ │ │ ├── neostore.schemastore.db.id │ │ │ ├── nioneo_logical.log.active │ │ │ ├── nioneo_logical.log.v6 │ │ │ ├── nioneo_logical.log.v7 │ │ │ ├── nioneo_logical.log.v8 │ │ │ ├── schema/ │ │ │ │ └── label/ │ │ │ │ └── lucene/ │ │ │ │ ├── segments.gen │ │ │ │ └── segments_1 │ │ │ ├── store_lock │ │ │ └── tm_tx_log.1 │ │ ├── snippet1301_ConnectingWithGrab.groovy │ │ ├── snippet1301_ConnectingWithInstance.groovy │ │ ├── snippet1301_ConnectingWithMap.groovy │ │ ├── snippet1301_ReadEachRow.groovy │ │ ├── snippet1301_ReadEachRowList.groovy │ │ ├── snippet1301_ReadQuery.groovy │ │ ├── snippet1301_ReadRows.groovy │ │ └── util/ │ │ ├── DbUtil.groovy │ │ ├── MarathonRelationships.groovy │ │ └── Neo4jUtil.groovy │ ├── chap14/ │ │ ├── Listing_14_01_Plan.txt │ │ ├── Listing_14_02_DOM.groovy │ │ ├── Listing_14_03_DOM_Category.groovy │ │ ├── Listing_14_04_XmlParser.groovy │ │ ├── Listing_14_05_XmlSlurper.groovy │ │ ├── Listing_14_06_SAX.groovy │ │ ├── Listing_14_07_StAX.groovy │ │ ├── Listing_14_08_XmlBoiler.groovy │ │ ├── Listing_14_09_XmlStreamer.groovy │ │ ├── Listing_14_10_StreamedHtml.groovy │ │ ├── Listing_14_11_UpdateDomCategory.groovy │ │ ├── Listing_14_12_UpdateParser.groovy │ │ ├── Listing_14_13_UpdateSlurper.groovy │ │ ├── Listing_14_14_XPath.groovy │ │ ├── Listing_14_15_GroovyPlansTemplate.txt │ │ ├── Listing_14_16_XPathTemplate.groovy │ │ ├── Listing_14_17_JsonParser.groovy │ │ ├── Listing_14_18_JsonBuilder.groovy │ │ ├── Listing_14_19_JsonBuilderLogic.groovy │ │ ├── Listing_14_20_JsonOutputAthlete.groovy │ │ ├── UpdateChecker.groovy │ │ ├── data/ │ │ │ ├── GroovyPlans.html │ │ │ ├── GroovyPlans.template.html │ │ │ ├── StreamedGroovyPlans.html │ │ │ ├── XPathGroovyPlans.html │ │ │ ├── plan.json │ │ │ ├── plan.xml │ │ │ └── style.css │ │ └── log4j.xml │ ├── chap15/ │ │ ├── Listing_15_01_RSS_bbcnews.groovy │ │ ├── Listing_15_02_ATOM_devworks.groovy │ │ ├── Listing_15_03_REST_jira_url.groovy │ │ ├── Listing_15_04_REST_jira_httpb_get.groovy │ │ ├── Listing_15_05_REST_currency_httpb_get.groovy │ │ ├── Listing_15_06_REST_currency_httpb_post.groovy │ │ ├── Listing_15_07_REST_currency_jaxrs.groovy │ │ ├── Listing_15_08_REST_currency_jaxrs_proxy.groovy │ │ ├── Listing_15_09_XMLRPC_echo.groovy │ │ ├── Listing_15_10_XMLRPC_jira.groovy │ │ ├── Listing_15_11_SOAP_wsdl.groovy │ │ ├── Listing_15_12_SOAP11_currency_url.groovy │ │ ├── Listing_15_13_SOAP12_currency_httpb.groovy │ │ ├── Listing_15_14_SOAP11_currency_wslite.groovy │ │ ├── Listing_15_15_SOAP12_currency_wslite.groovy │ │ └── data/ │ │ └── conv.templ.xml │ ├── chap16/ │ │ ├── HelloIntegrationWorld.java │ │ ├── Listing_16_01_HelloIntegration.groovy │ │ ├── Listing_16_02_HelloIntegrationJava.txt │ │ ├── Listing_16_03_MultilineScript.groovy │ │ ├── Listing_16_04_UsingEval.groovy │ │ ├── Listing_16_05_Binding.groovy │ │ ├── Listing_16_06_BindingTwoWay.groovy │ │ ├── Listing_16_07_ClassInScript.groovy │ │ ├── Listing_16_08_Payment_calculator.groovy │ │ ├── Listing_16_09_MethodsInBinding.groovy │ │ ├── Listing_16_10_ShapeInfoMain.txt │ │ ├── Listing_16_11_SpringConfig.txt │ │ ├── Listing_16_12_BeanToString.groovy │ │ ├── shapes/ │ │ │ ├── Circle.groovy │ │ │ ├── MaxAreaInfo.groovy │ │ │ ├── MaxPerimeterInfo.java │ │ │ ├── Shape.java │ │ │ ├── ShapeInfo.java │ │ │ ├── ShapeInfoMain.java │ │ │ └── Square.java │ │ └── spring/ │ │ ├── common/ │ │ │ ├── Shape.java │ │ │ └── ShapeInfo.java │ │ ├── groovy/ │ │ │ ├── Circle.groovy │ │ │ └── MaxAreaInfo.groovy │ │ ├── java/ │ │ │ ├── MaxPerimeterInfo.java │ │ │ ├── ShapeInfoFactoryMain.java │ │ │ ├── ShapeInfoMain.java │ │ │ ├── ShapeInfoSpringMain.java │ │ │ └── Square.java │ │ ├── lib/ │ │ │ ├── commons-logging.jar │ │ │ ├── spring-beans.jar │ │ │ ├── spring-core.jar │ │ │ └── spring.jar │ │ └── resources/ │ │ └── beans.xml │ ├── chap17/ │ │ ├── .classpath │ │ ├── .project │ │ ├── Converter.groovy │ │ ├── Counter.groovy │ │ ├── Farm.groovy │ │ ├── Listing_17_01_Celsius.groovy │ │ ├── Listing_17_02_CounterTest.groovy │ │ ├── Listing_17_03_HashMapTest.groovy │ │ ├── Listing_17_04_GroovyTestSuite.groovy │ │ ├── Listing_17_05_AllTestSuite.groovy │ │ ├── Listing_17_06_DataDrivenJUnitTest.groovy │ │ ├── Listing_17_07_PropertyBased.groovy │ │ ├── Listing_17_08_Balancer.groovy │ │ ├── Listing_17_09_BalancerStub.groovy │ │ ├── Listing_17_10_BalancerMock.groovy │ │ ├── Listing_17_11_LoggingCounterTest.groovy │ │ ├── Listing_17_12_JUnitPerf.groovy │ │ ├── Listing_17_13_SpockSimple.groovy │ │ ├── Listing_17_14_SpockMock.groovy │ │ ├── Listing_17_15_SpockMockWildcards.groovy │ │ ├── Listing_17_16_SpockMockClosureChecks.groovy │ │ ├── Listing_17_17_SpockDataDriven.groovy │ │ ├── LoggingCounter.groovy │ │ ├── MovieTheater.groovy │ │ ├── Purchase.groovy │ │ ├── automation/ │ │ │ ├── build.gradle │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── groovy/ │ │ │ │ └── Calculator.groovy │ │ │ └── test/ │ │ │ └── groovy/ │ │ │ └── CalculatorTest.groovy │ │ ├── cobertura/ │ │ │ ├── build.gradle │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── groovy/ │ │ │ │ ├── BiggestPairCalc.groovy │ │ │ │ └── BiggestPairCalcFixed.groovy │ │ │ └── test/ │ │ │ └── groovy/ │ │ │ └── BiggestPairCalcTest.groovy │ │ ├── extra_ParameterizedTestNG.groovy │ │ ├── extra_TestNG.groovy │ │ ├── snippet1701_JUnit4.groovy │ │ ├── snippet1704_listPropertyCheck.groovy │ │ └── test-output/ │ │ ├── Command line suite/ │ │ │ ├── Command line test.html │ │ │ └── Command line test.xml │ │ ├── emailable-report.html │ │ ├── index.html │ │ ├── junitreports/ │ │ │ ├── TEST-extra_ParameterizedTestNG.xml │ │ │ └── TEST-extra_TestNG.xml │ │ ├── old/ │ │ │ ├── Command line suite/ │ │ │ │ ├── Command line test.properties │ │ │ │ ├── classes.html │ │ │ │ ├── groups.html │ │ │ │ ├── index.html │ │ │ │ ├── main.html │ │ │ │ ├── methods-alphabetical.html │ │ │ │ ├── methods-not-run.html │ │ │ │ ├── methods.html │ │ │ │ ├── reporter-output.html │ │ │ │ ├── testng.xml.html │ │ │ │ └── toc.html │ │ │ └── index.html │ │ ├── testng-reports.css │ │ ├── testng-reports.js │ │ ├── testng-results.xml │ │ └── testng.css │ ├── chap18/ │ │ ├── Listing_18_01_ConcurrentSquares.groovy │ │ ├── Listing_18_02_ConcurrentSquaresTransparent.groovy │ │ ├── Listing_18_03_ConcurrentSquaresTransitive.groovy │ │ ├── Listing_18_04_MapFilterReduce.groovy │ │ ├── Listing_18_05_SquaresMapReduce.groovy │ │ ├── Listing_18_06_Dataflow.groovy │ │ ├── Listing_18_07_DataflowStreams.groovy │ │ ├── Listing_18_08_Actors.groovy │ │ ├── Listing_18_09_ActorsLifecycle.groovy │ │ ├── Listing_18_10_ActorsMessageAware.groovy │ │ ├── Listing_18_11_Agent.groovy │ │ ├── Listing_18_12.txt │ │ ├── Listing_18_13_YahooForkJoin.groovy │ │ ├── Listing_18_14_YahooMapReduce.groovy │ │ ├── Listing_18_15_YahooDataflow.groovy │ │ ├── YahooService.groovy │ │ ├── snippet1801_startThread.groovy │ │ ├── snippet1803_java_parallel_streams_jdk8_only.groovy │ │ ├── snippet1804_deadlock.groovy │ │ └── snippet1804_nondeterministic.groovy │ ├── chap19/ │ │ ├── FetchOptions.groovy │ │ ├── FetchOptionsBuilder.groovy │ │ ├── Listing_19_06_Binding.groovy │ │ ├── Listing_19_29_OrderDSL.groovy │ │ ├── Listing_19_30_WhenIfControlStructure.groovy │ │ ├── Listing_19_31_Until_failing_.groovy │ │ ├── Listing_19_32_UntilControlStructure.groovy │ │ ├── Listing_19_39_GivenWhenThen.groovy │ │ ├── Listing_19_43_FetchOptionsScript.groovy │ │ ├── Listing_19_44_RubyStyleNewify.groovy │ │ ├── Listing_19_45_PythonStyleNewify.groovy │ │ ├── Listing_19_46_Terms.groovy │ │ ├── Listing_19_47_NewifyInjected.txt │ │ ├── Listing_19_48_No_IO.groovy │ │ ├── Listing_19_49_ArithmeticShell.groovy │ │ ├── Listing_19_50_TimedInterrupt.groovy │ │ ├── Listing_19_51_SystemExitGuard.groovy │ │ ├── Listing_19_53_QueryCustomizer.groovy │ │ ├── Listings.txt │ │ ├── Query.groovy │ │ ├── extra_FetchOptions_traditional.groovy │ │ ├── v01/ │ │ │ └── Listing_19_01_SelfContainedScript.groovy │ │ ├── v02/ │ │ │ ├── Listing_19_04_MainSimple.groovy │ │ │ ├── Listing_19_05_MainGroovyShell.groovy │ │ │ ├── Listing_19_07_MainBinding.groovy │ │ │ ├── Listing_19_08_MainDirectionConstants.groovy │ │ │ ├── Listing_19_09_MainDirectionsSpread.groovy │ │ │ ├── Listing_19_10_MainImplicitMethod.groovy │ │ │ ├── Listing_19_12_MainBaseScript.groovy │ │ │ ├── Listing_19_13_MainImportCustomizer.groovy │ │ │ ├── Listing_19_14_MainCustomBaseScriptClass.groovy │ │ │ ├── Listing_19_16_MainMethodClosure.groovy │ │ │ ├── Listing_19_19_MainLowerCase.groovy │ │ │ ├── integration/ │ │ │ │ ├── CaseRobotBaseScript.groovy │ │ │ │ ├── CustomBinding.groovy │ │ │ │ └── RobotBaseScript.groovy │ │ │ ├── model/ │ │ │ │ ├── Direction.groovy │ │ │ │ └── Robot.groovy │ │ │ └── snippet1901_MainFileRunner.groovy │ │ ├── v03/ │ │ │ ├── Listing_19_27_SimpleCommandChain.groovy │ │ │ ├── Listing_19_40_Robot_With.groovy │ │ │ ├── integration/ │ │ │ │ ├── DistanceCategory.groovy │ │ │ │ ├── RobotBaseScript.groovy │ │ │ │ └── SuperBotBaseScript.groovy │ │ │ └── model/ │ │ │ ├── Direction.groovy │ │ │ ├── Distance.groovy │ │ │ ├── Duration.groovy │ │ │ ├── Robot.groovy │ │ │ ├── Speed.groovy │ │ │ ├── SuperBot.groovy │ │ │ └── Unit.groovy │ │ └── xform/ │ │ ├── BusinessLogicScript.groovy │ │ ├── CustomControlStructure.groovy │ │ ├── Listing_19_36_WhenTransformation.groovy │ │ ├── WhenUntilTransform.groovy │ │ ├── extra_WhenTransformationWorksWithoutBraces.groovy │ │ └── snippet1906_WhenUntilXform_Structure.groovy │ └── chap20/ │ ├── Listing_20_01_Grapes_for_twitter_urls.groovy │ ├── Listing_20_02_Scriptom_Windows_only.groovy │ ├── Listing_20_03_ActivX_Windows_only.groovy │ ├── Listing_20_10_SquaringMapValue.groovy │ ├── Listing_20_11_Synchronized.groovy │ └── Listing_20_12_DbC_invariants.groovy └── test.groovy
SYMBOL INDEX (63 symbols across 19 files)
FILE: listings/chap03/ArrayListSummer.java
class ArrayListSummer (line 1) | public class ArrayListSummer {
method main (line 2) | public static void main(String[] args) {
FILE: listings/chap09/build/reports/tests/js/report.js
function initTabs (line 3) | function initTabs() {
function switchTab (line 16) | function switchTab() {
function select (line 27) | function select(i) {
function deselectAll (line 39) | function deselectAll() {
function changeElementClass (line 55) | function changeElementClass(element, classValue) {
function findTabs (line 64) | function findTabs(container) {
function findHeaders (line 68) | function findHeaders(container) {
function findTitles (line 73) | function findTitles(tabs) {
function findChildElements (line 88) | function findChildElements(container, name, targetClass) {
FILE: listings/chap10/Greeter.java
class Greeter (line 1) | public class Greeter { // Java!
method greet (line 2) | static void greet(Object o) {
method greet (line 6) | static void greet(String s) {
method main (line 10) | public static void main(String... args) {
FILE: listings/chap10/extra1004_JavaDispatch.java
class JavaDispatch (line 3) | class JavaDispatch {
method prettify (line 4) | public static String prettify(Object o) {
method doPrettify (line 10) | static String doPrettify(Object o) { return "Value:"+o.toString(); }
method doPrettify (line 11) | static String doPrettify(String s) { return "String:"+s; }
method doPrettify (line 12) | static String doPrettify(Date d) { return "Date:"+d.getTime(); }
FILE: listings/chap11/Listing_11_02_SquaresFactors.java
class Listing_11_02_SquaresFactors (line 4) | public class Listing_11_02_SquaresFactors {
method process (line 5) | public void process(Document doc) {
FILE: listings/chap16/HelloIntegrationWorld.java
class HelloIntegrationWorld (line 4) | public class HelloIntegrationWorld {
method main (line 5) | public static void main(String[] args) {
FILE: listings/chap16/shapes/MaxPerimeterInfo.java
class MaxPerimeterInfo (line 3) | public class MaxPerimeterInfo {
method displayInfo (line 4) | void displayInfo(Square s, Circle c) {
FILE: listings/chap16/shapes/Shape.java
type Shape (line 3) | public interface Shape {
method area (line 4) | double area();
method perimeter (line 5) | double perimeter();
FILE: listings/chap16/shapes/ShapeInfo.java
type ShapeInfo (line 3) | public interface ShapeInfo {
method displayInfo (line 4) | void displayInfo(Shape s1, Shape s2);
FILE: listings/chap16/shapes/ShapeInfoMain.java
class ShapeInfoMain (line 4) | public class ShapeInfoMain {
method main (line 5) | public static void main(String[] args) {
FILE: listings/chap16/shapes/Square.java
class Square (line 3) | public class Square implements Shape {
method Square (line 5) | Square(double side) { this.side = side; }
method area (line 6) | public double area() { return side * side; }
method perimeter (line 7) | public double perimeter() { return 4 * side; }
FILE: listings/chap16/spring/common/Shape.java
type Shape (line 3) | public interface Shape {
method area (line 4) | double area();
method perimeter (line 5) | double perimeter();
FILE: listings/chap16/spring/common/ShapeInfo.java
type ShapeInfo (line 3) | public interface ShapeInfo {
method displayInfo (line 4) | void displayInfo(Shape s1, Shape s2);
FILE: listings/chap16/spring/java/MaxPerimeterInfo.java
class MaxPerimeterInfo (line 6) | public class MaxPerimeterInfo implements ShapeInfo {
method getPrefix (line 7) | public String getPrefix() {
method setPrefix (line 11) | public void setPrefix(String value) {
method displayInfo (line 14) | public void displayInfo(Shape s1, Shape s2) {
FILE: listings/chap16/spring/java/ShapeInfoFactoryMain.java
class ShapeInfoFactoryMain (line 8) | public class ShapeInfoFactoryMain
method main (line 10) | public static void main(String[] args) {
FILE: listings/chap16/spring/java/ShapeInfoMain.java
class ShapeInfoMain (line 7) | public class ShapeInfoMain
method main (line 9) | public static void main(String[] args) {
FILE: listings/chap16/spring/java/ShapeInfoSpringMain.java
class ShapeInfoSpringMain (line 13) | public class ShapeInfoSpringMain
method main (line 15) | public static void main(String[] args) {
FILE: listings/chap16/spring/java/Square.java
class Square (line 5) | public class Square implements Shape {
method Square (line 8) | public Square(double side) { this.side = side; }
method area (line 9) | public double area() { return side * side; }
method perimeter (line 10) | public double perimeter() { return 4 * side; }
method toString (line 11) | public String toString(){ return color + " Java Square"; }
FILE: listings/chap17/test-output/testng-reports.js
function installMethodHandlers (line 39) | function installMethodHandlers(name, hide) {
function getHashForMethod (line 83) | function getHashForMethod(element) {
function getPanelName (line 87) | function getPanelName(element) {
function showPanel (line 91) | function showPanel(panelName) {
function showMethod (line 97) | function showMethod(element) {
function drawTable (line 108) | function drawTable() {
Condensed preview — 719 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (766K chars).
[
{
"path": ".idea/vcs.xml",
"chars": 167,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"VcsDirectoryMappings\">\n <mapping dire"
},
{
"path": "LICENSE",
"chars": 11358,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 1312,
"preview": "# Groovy In Action\nSource code of the book [Groovy in Action, 2nd edition (manning,](http://manning.com/koenig2/?a_aid=r"
},
{
"path": "alltests.groovy",
"chars": 964,
"preview": "for (number in 1..20) {\n def ant = new AntBuilder()\n def dir = 'listings/chap' + number.toString().padLeft(2, '0')"
},
{
"path": "listings/allsources.txt",
"chars": 26222,
"preview": "./appD/Listing_D_01_GStrings.groovy\n./appD/Listing_D_02_Lists.groovy\n./appD/Listing_D_03_Closures.groovy\n./appD/Listing_"
},
{
"path": "listings/appD/Listing_D_01_GStrings.groovy",
"chars": 432,
"preview": "\n// normal use\ndef g1 = \"1 + 1 equals ${1 + 1}\"\nassert g1 == '1 + 1 equals 2'\nassert g1 instanceof CharSequence\nasse"
},
{
"path": "listings/appD/Listing_D_02_Lists.groovy",
"chars": 1585,
"preview": "assert [1,2,3,4] == (1..4)\nassert [1,2,3] + [1] == [1,2,3,1]\nassert [1,2,3] << 1 == [1,2,3,1]\nassert [1,2,3,1"
},
{
"path": "listings/appD/Listing_D_03_Closures.groovy",
"chars": 885,
"preview": "def add = { x, y -> x + y }\ndef mult = { x, y -> x * y }\nassert add(1,3) == 4\nassert mult(1,3) == 3\ndef min = { x, y -"
},
{
"path": "listings/appD/Listing_D_04_Regex.groovy",
"chars": 1330,
"preview": "def twister = 'she sells sea shells by the sea shore'\n\n// contains word 'shore'\nassert twister =~ 'shore'\n\n// contains '"
},
{
"path": "listings/appD/Listing_D_05_GPath.groovy",
"chars": 1721,
"preview": "import groovy.xml.dom.DOMCategory\n\ndef recipeXml = '''\n<recipe>\n <ingredients>\n <ingredient amount='2 cups'>Self-"
},
{
"path": "listings/chap01/Listing_01_01_Gold.groovy",
"chars": 886,
"preview": "List fibo = [1, 1] //#A\nList gold = [1, 2] //#B\n\nwhile ( ! isGolden( g"
},
{
"path": "listings/chap01/customers.xml",
"chars": 350,
"preview": "<?xml version=\"1.0\" ?>\n<customers>\n <corporate>\n <customer name=\"Bill Gates\" company=\"Microsoft\" />\n <custom"
},
{
"path": "listings/chap01/data.txt",
"chars": 22,
"preview": "first line\nsecond line"
},
{
"path": "listings/chap01/groovysh.txt",
"chars": 224,
"preview": "Groovy Shell (2.4.0, JVM: 1.7.0_75)\nType ':help' or ':h' for help.\n-----------------------------------------------------"
},
{
"path": "listings/chap01/snippet0101_customers.groovy",
"chars": 179,
"preview": "def customers = new XmlSlurper().parse(new File('customers.xml'))\nfor (customer in customers.corporate.customer) {\n p"
},
{
"path": "listings/chap01/snippet0101_fileLineNumbers.groovy",
"chars": 98,
"preview": "def number = 0\nnew File('data.txt').eachLine { line ->\n number++\n println \"$number: $line\"\n}"
},
{
"path": "listings/chap01/snippet0101_newDates.txt",
"chars": 368,
"preview": "import java.util.*; // Java\nDate today = new Date(); // Java\n\ntoday = new Date() // Groovy\n\nrequire 'date'"
},
{
"path": "listings/chap01/snippet0101_printPackageNames.groovy",
"chars": 92,
"preview": "def classes = [String, List, File]\nfor (clazz in classes) {\n println clazz.package.name\n}"
},
{
"path": "listings/chap01/snippet0101_printPackageNamesGpath.groovy",
"chars": 46,
"preview": "println( [String, List, File]*.package*.name )"
},
{
"path": "listings/chap01/snippet0102_printGroovyWebSiteCount.groovy",
"chars": 276,
"preview": "import static groovyx.gpars.GParsPool.withPool\n\ndef urls = [\n 'http://www.groovy-lang.org',\n 'http://gpars"
},
{
"path": "listings/chap01/snippet0103_googleIpAdr.groovy",
"chars": 83,
"preview": "InetAddress.getAllByName(\"google.com\").collect {\n it.toString().split('/')[1]\n}\n"
},
{
"path": "listings/chap02/Book.groovy",
"chars": 149,
"preview": "class Book {\n private String title\n Book (String theTitle) {\n title = theTitle\n }\n String getTitle(){"
},
{
"path": "listings/chap02/Listing_02_01_Assertions.groovy",
"chars": 84,
"preview": "assert(true)\nassert 1 == 1\ndef x = 1\nassert x == 1\ndef y = 1 ; assert y == 1"
},
{
"path": "listings/chap02/Listing_02_02_Book.txt",
"chars": 15,
"preview": "see Book.groovy"
},
{
"path": "listings/chap02/Listing_02_03_BookScript.groovy",
"chars": 246,
"preview": "Book gina = new Book('Groovy in Action')\n\nassert gina.getTitle() == 'Groovy in Action'\nassert getTitleBackwards("
},
{
"path": "listings/chap02/Listing_02_04_BookBean.groovy",
"chars": 465,
"preview": "class BookBean {\n String title //#A\n}\n\ndef groovyBook = new BookBean()\n\ngroovyB"
},
{
"path": "listings/chap02/Listing_02_05_ImmutableBook.groovy",
"chars": 660,
"preview": "import groovy.transform.Immutable\n\n@Immutable class FixedBook { //#A\n String title\n}\n\ndef g"
},
{
"path": "listings/chap02/Listing_02_06_Grab.groovy",
"chars": 199,
"preview": "@Grab('commons-lang:commons-lang:2.4')\nimport org.apache.commons.lang.ClassUtils\n\nclass Outer {\n class Inner {}\n}\n\nasse"
},
{
"path": "listings/chap02/Listing_02_07_Clinks.groovy",
"chars": 260,
"preview": "def totalClinks = 0\ndef partyPeople = 100\n1.upto(partyPeople) { guestNumber ->\n clinksWithGuest = guestNumber-1\n t"
},
{
"path": "listings/chap02/Listing_02_08_ControlStructures.groovy",
"chars": 1744,
"preview": "if (false) assert false //#A\n\nif (null) //#B"
},
{
"path": "listings/chap02/snippet0201_comments.groovy",
"chars": 76,
"preview": "#!/usr/bin/env groovy\n// some line comment\n/* some multi-\n line comment */"
},
{
"path": "listings/chap02/snippet0202_failing_assert.groovy",
"chars": 102,
"preview": "def a = 5\ndef b = 9\nassert b == a + a //#A\n//#A expected to fail\n"
},
{
"path": "listings/chap02/snippet0202_failing_assertion_error.txt",
"chars": 424,
"preview": "Assertion failed:\n\nassert b == a + a //#A\n | | | | |\n 9 | 5 | 5 "
},
{
"path": "listings/chap02/snippet0203_clinks_java.groovy",
"chars": 224,
"preview": "// Java snippet\nint totalClinks = 0;\nint partyPeople = 100;\nfor(int guestNumber = 1;\n guestNumber <= partyPeople;"
},
{
"path": "listings/chap02/snippet0203_gstring.groovy",
"chars": 123,
"preview": "def nick = 'ReGina'\ndef book = 'Groovy in Action, 2nd ed.'\nassert \"$nick is $book\" == 'ReGina is Groovy in Action, 2nd e"
},
{
"path": "listings/chap02/snippet0203_int_usage.groovy",
"chars": 91,
"preview": "def x = 1\ndef y = 2\nassert x + y == 3\nassert x.plus(y) == 3\nassert x instanceof Integer"
},
{
"path": "listings/chap02/snippet0203_map_usage.groovy",
"chars": 173,
"preview": "def http = [\n 100 : 'CONTINUE',\n 200 : 'OK',\n 400 : 'BAD REQUEST'\n]\nassert http[200] == 'OK'\nhttp[5"
},
{
"path": "listings/chap02/snippet0203_range_usage.groovy",
"chars": 144,
"preview": "def x = 1..10\nassert x.contains(5)\nassert !x.contains(15)\nassert x.size() == 10\nassert x.from == 1\nassert x.to == 10\nass"
},
{
"path": "listings/chap02/snippet0203_roman.groovy",
"chars": 286,
"preview": "def roman = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII'] //#A\nassert roman[4] == 'IV' "
},
{
"path": "listings/chap02/snippet0204_evaluate_jdk7_only.groovy",
"chars": 191,
"preview": "//java.class.version\n//jdk5=49.0\n//jdk6=50.0\n//jdk7=51.0\n//jdk8=52.0\ndef code = '1 + '\ncode += System.getProperty('java."
},
{
"path": "listings/chap02/snippet0204_evaluate_jdk8_only.groovy",
"chars": 191,
"preview": "//java.class.version\n//jdk5=49.0\n//jdk6=50.0\n//jdk7=51.0\n//jdk8=52.0\ndef code = '1 + '\ncode += System.getProperty('java."
},
{
"path": "listings/chap02/snippet0204_failing_typechecked.groovy",
"chars": 115,
"preview": "class Universe {\n @groovy.transform.TypeChecked\n int answer() { \"forty two\" }\n}\n\nprintln new Universe().answer()\n"
},
{
"path": "listings/chap03/ArrayListSummer.java",
"chars": 263,
"preview": "public class ArrayListSummer {\n public static void main(String[] args) {\n // (60 * 60 * 24 * 365).toString();\n"
},
{
"path": "listings/chap03/Listing_03_01_PrimitiveMethodsObjectOperators.groovy",
"chars": 254,
"preview": "(60 * 60 * 24 * 365).toString(); // invalid Java\n\nint secondsPerYear = 60 * 60 * 24 * 365;\nsecondsPerYear.toStri"
},
{
"path": "listings/chap03/Listing_03_02_ListMapCast.groovy",
"chars": 342,
"preview": "import java.awt.*\n\nPoint topLeft = new Point(0, 0) // classic\nPoint botRight = [100, 100] // List cast\nPoint cente"
},
{
"path": "listings/chap03/Listing_03_03_DefiningOperators.groovy",
"chars": 750,
"preview": "import groovy.transform.Immutable\n\n@Immutable //#1\nclass Money {\n int "
},
{
"path": "listings/chap03/Listing_03_04_DefiningGStrings.groovy",
"chars": 1190,
"preview": "import static java.util.Calendar.*\n\ndef me = 'Tarzan'\ndef you = 'Jane'\ndef line = \"me $me - you $you\" "
},
{
"path": "listings/chap03/Listing_03_05_StringOperations.groovy",
"chars": 476,
"preview": "String greeting = 'Hello Groovy!'\n\nassert greeting.startsWith('Hello')\n\nassert greeting.getAt(0) == 'H'\nassert greeting["
},
{
"path": "listings/chap03/Listing_03_06_RegexGStrings.groovy",
"chars": 121,
"preview": "assert \"abc\" == /abc/\nassert \"\\\\d\" == /\\d/ \n\ndef reference = \"hello\"\nassert reference == /$reference/\n\nassert \"\\$\" == /$"
},
{
"path": "listings/chap03/Listing_03_07_RegularExpressions.groovy",
"chars": 1149,
"preview": "def twister = 'she sells sea shells at the sea shore of seychelles'\n\n// twister must contain a substring of size 3 \n// t"
},
{
"path": "listings/chap03/Listing_03_08_EachMatch.groovy",
"chars": 669,
"preview": "def myFairStringy = 'The rain in Spain stays mainly in the plain!'\n\n// words that end with 'ain': \\b\\w*ain\\b\ndef wordEnd"
},
{
"path": "listings/chap03/Listing_03_09_PatternReuse.groovy",
"chars": 770,
"preview": "def twister = 'she sells sea shells at the sea shore of seychelles'\n// some more complicated regex: \n// word that starts"
},
{
"path": "listings/chap03/Listing_03_10_PatternsClassification.groovy",
"chars": 282,
"preview": "def fourLetters = ~/\\w{4}/\n\nassert fourLetters.isCase('work')\n\nassert 'love' in fourLetters\n\nswitch('beer'){\n case fo"
},
{
"path": "listings/chap03/Listing_03_11_NumberMethodsGDK.groovy",
"chars": 607,
"preview": "def store = ''\n10.times{ //#A\n store += 'x'\n}\nassert store == 'xxxxxxxxx"
},
{
"path": "listings/chap03/extra_escaped_characters_table36.groovy",
"chars": 384,
"preview": "println \"A '\\b' Backspace\"\nprintln \"A '\\t' Tab\"\nprintln \"A '\\r' Carriage return\"\nprintln \"A '\\n' Line feed\"\nprintln \"A '"
},
{
"path": "listings/chap03/extra_method_operators_table34.groovy",
"chars": 1537,
"preview": "def a = 2\ndef b = 3\n\nassert a + b == a.plus(b)\nassert a - b == a.minus(b)\nassert a * b == a.multiply(b)\nassert a / b == "
},
{
"path": "listings/chap03/extra_numeric_literals_table32.groovy",
"chars": 386,
"preview": "[15, 0x1234ffff, 0b00110011, 100_000_000].each {\n assert it instanceof Integer\n}\n[100L, 200l].each{ assert it instanceo"
},
{
"path": "listings/chap03/extra_numerical_coercion_table310.groovy",
"chars": 716,
"preview": "assert 1f*2f instanceof Double\nassert (Byte)1+(Byte)2 instanceof Integer\nassert 1*2L instanceof Long\n\nassert 1 + 0.5 "
},
{
"path": "listings/chap03/extra_optional_typing_table33.groovy",
"chars": 313,
"preview": "def a = 1; assert a instanceof Integer //|#1\ndef b = 1.0f; assert b instanceof Float //|#1\n\nint c = 1; "
},
{
"path": "listings/chap03/extra_primitive_values_table31.groovy",
"chars": 392,
"preview": "byte a = 0 ; assert a instanceof Byte \nshort b = 0 ; assert b instanceof Short\nint c = 0 ; as"
},
{
"path": "listings/chap03/regex_dgm.txt",
"chars": 1116,
"preview": "Matcher\nlong size()\nint getCount()\nObject getAt( int idx)\nvoid setIndex( int idx)\nboolean hasGroup()\n\nPattern\nboolean is"
},
{
"path": "listings/chap03/snippet0301_autoboxing.groovy",
"chars": 32,
"preview": "assert 'ABCDE'.indexOf(67) == 2\n"
},
{
"path": "listings/chap03/snippet0304_GString_internals.groovy",
"chars": 282,
"preview": "def me = 'Tarzan'\ndef you = 'Jane'\ndef line = \"me $me - you $you\"\nassert line == 'me Tarzan - you Jane'\nasse"
},
{
"path": "listings/chap03/snippet0304_stringbuffer.groovy",
"chars": 441,
"preview": "def greeting = 'Hello'\n\ngreeting <<= ' Groovy' //#1\n\nassert greeting instanceof java.lan"
},
{
"path": "listings/chap03/snippet0305_matcher_each_group.groovy",
"chars": 189,
"preview": "def matcher = 'a:1 b:2 c:3' =~ /(\\S+):(\\S+)/\nmatcher.each { full, key, value ->\n assert full.size() == 3\n assert"
},
{
"path": "listings/chap03/snippet0305_matcher_groups.groovy",
"chars": 188,
"preview": "def matcher = 'a:1 b:2 c:3' =~ /(\\S+):(\\S+)/\n\nassert matcher.hasGroup()\nassert matcher[0] == ['a:1', 'a', '1'] // 1st m"
},
{
"path": "listings/chap03/snippet0305_matcher_parallel_assignment.groovy",
"chars": 81,
"preview": "def (a,b,c) = 'a b c' =~ /\\S/ \n\nassert a == 'a' \nassert b == 'b' \nassert c == 'c'"
},
{
"path": "listings/chap03/snippet0305_matcher_plain.groovy",
"chars": 121,
"preview": "def matcher = 'a b c' =~ /\\S/\n\nassert matcher[0] == 'a'\nassert matcher[1..2] == ['b','c']\nassert matcher.size() == "
},
{
"path": "listings/chap03/snippet0306_GDK_methods_for_numbers.groovy",
"chars": 501,
"preview": "assert 1 == (-1).abs()\nassert 2 == 2.5.toInteger() // conversion\nassert 2 == 2.5 as Integer // enforced"
},
{
"path": "listings/chap04/Listing_04_01_range_declarations.groovy",
"chars": 2249,
"preview": "assert (0..10).contains(0) //#A\nassert (0..10).contains(5) //#A\n"
},
{
"path": "listings/chap04/Listing_04_02_ranges_are_objects.groovy",
"chars": 1278,
"preview": "def result = '' //#A\n(5..9).each { element -> //#A\n"
},
{
"path": "listings/chap04/Listing_04_03_custom_ranges.groovy",
"chars": 825,
"preview": "class Weekday implements Comparable {\n static final DAYS = [\n 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'\n ]\n"
},
{
"path": "listings/chap04/Listing_04_04_list_declarations.groovy",
"chars": 877,
"preview": "List myList = [1, 2, 3]\n\nassert myList.size() == 3\nassert myList[0] == 1\nassert myList instanceof ArrayList\n\nList em"
},
{
"path": "listings/chap04/Listing_04_05_list_subscript_operator.groovy",
"chars": 568,
"preview": "def myList = ['a','b','c','d','e','f']\n\nassert myList[0..2] == ['a','b','c'] //#A\nassert myList[0,2,4]"
},
{
"path": "listings/chap04/Listing_04_06_list_add_remove.groovy",
"chars": 517,
"preview": "myList = []\n\nmyList += 'a' //#A\nassert myList == ['a']\n\nmyList += ['b','c'] "
},
{
"path": "listings/chap04/Listing_04_07_lists_control_structures.groovy",
"chars": 599,
"preview": "myList = ['a', 'b', 'c']\n\nassert myList.isCase('a')\nassert 'b' in myList\n\ndef candidate = 'c'\nswitch(candidate){\n cas"
},
{
"path": "listings/chap04/Listing_04_08_list_content_manipulation.groovy",
"chars": 1205,
"preview": "assert [1,[2,3]].flatten() == [1,2,3]\nassert [1,2,3].intersect([4,3,1])== [3,1]\nassert [1,2,3].disjoint([4,5,6])\n\nlist ="
},
{
"path": "listings/chap04/Listing_04_09_list_other_methods.groovy",
"chars": 2534,
"preview": "def list = [1, 2, 3]\n\nassert list.first() == 1\nassert list.head() == 1\nassert list.tail() == [2, 3]\nassert list.las"
},
{
"path": "listings/chap04/Listing_04_10_list_quicksort.groovy",
"chars": 854,
"preview": "def quickSort(list) {\n if (list.size() < 2) return list\n def pivot = list[list.size().intdiv(2)]\n def left = list."
},
{
"path": "listings/chap04/Listing_04_11_list_mapreduce.groovy",
"chars": 309,
"preview": "def urls = [\n new URL('http', 'myshop.com', 80, 'index.html'),\n new URL('https', 'myshop.com', 443, 'buynow.html')"
},
{
"path": "listings/chap04/Listing_04_12_map_declarations.groovy",
"chars": 377,
"preview": "def myMap = [a:1, b:2, c:3]\n\nassert myMap instanceof LinkedHashMap\nassert myMap.size() == 3\nassert myMap['a'] == 1\n\nde"
},
{
"path": "listings/chap04/Listing_04_13_map_accessors.groovy",
"chars": 923,
"preview": "def myMap = [a:1, b:2, c:3]\n\nassert myMap['a'] == 1 //#A\nassert myMap.a == 1 "
},
{
"path": "listings/chap04/Listing_04_14_map_query_methods.groovy",
"chars": 746,
"preview": "def myMap = [a:1, b:2, c:3]\ndef other = [b:2, c:3, a:1]\n\nassert myMap == other //#A\n\nas"
},
{
"path": "listings/chap04/Listing_04_15_map_iteration.groovy",
"chars": 1136,
"preview": "def myMap = [a:1, b:2, c:3]\n\ndef store = ''\nmyMap.each { entry -> //#A\n store += ent"
},
{
"path": "listings/chap04/Listing_04_16_map_content.groovy",
"chars": 819,
"preview": "def myMap = [a:1, b:2, c:3]\nmyMap.clear()\nassert myMap.isEmpty()\n\nmyMap = [a:1, b:2, c:3]\nmyMap.remove('a')\nassert myMap"
},
{
"path": "listings/chap04/Listing_04_17_map_example.groovy",
"chars": 770,
"preview": "def textCorpus = \n\"\"\"\nLook for the bare necessities\nThe simple bare necessities\nForget about your worries and your strif"
},
{
"path": "listings/chap04/extra_EnumRange.groovy",
"chars": 379,
"preview": "enum Month {\n Jan, Feb, Mar, Apr, May, Jun,\n Jul, Aug, Sep, Oct, Nov, Dec\n}\ndef noClams = Month.May .. Month.Aug"
},
{
"path": "listings/chap04/extra_ListCast.groovy",
"chars": 196,
"preview": "Set names = ['Dierk', 'Paul'] as Set\nassert names instanceof Set\n\nassert names.toListString() ==~ /\\[\\w+, \\w+\\]/\nassert "
},
{
"path": "listings/chap04/extra_ListTable.groovy",
"chars": 255,
"preview": "def table = [\n [0, 1],\n [2, 3]\n]\ntable = table.collectNested { item -> item + 1 }\nassert table == [\n [1, 2],\n "
},
{
"path": "listings/chap04/extra_Map_as.groovy",
"chars": 151,
"preview": "def absComp = [\n compare: { a,b -> a.abs() <=> b.abs() } \n]\ndef list = [-3, -1, 2]\nlist.sort(true, absComp as Compara"
},
{
"path": "listings/chap04/extra_Map_group.groovy",
"chars": 212,
"preview": "def tzones = [\n dierk: +1, guillaume: +1, jon: 0,\n paul: +9, tara: -7\n]\nassert tzones.groupBy { key, val -> val.i"
},
{
"path": "listings/chap04/extra_MaxMinSum.groovy",
"chars": 179,
"preview": "def kings = ['Dierk', 'Paul']\nassert kings.max { item -> item.size() } == 'Dierk'\nassert kings.min { item -> item.size()"
},
{
"path": "listings/chap04/extra_SplitList.groovy",
"chars": 200,
"preview": "def list = [0, 3, 2, 1]\ndef (small, big) = list.split { it < 2 }\nassert small == [0, 1]\nassert big == [3, 2]\n\ndef grou"
},
{
"path": "listings/chap04/snippet0402_ListAsSet.groovy",
"chars": 139,
"preview": "def x = [1, 1, 1]\nassert [1] == new HashSet(x).toList()\nassert [1] == x.unique()\nassert [1] == [1, '1'].unique { item ->"
},
{
"path": "listings/chap04/snippet0402_ListRemoveNulls.groovy",
"chars": 170,
"preview": "List x = [1, null, null, 2]\n\nassert [1, 2] == x.findAll { it != null }\nassert [1, 2] == x.grep { it }\n\nassert [1, 2] == "
},
{
"path": "listings/chap04/snippet0402_ListStreams_jdk8_plus.groovy",
"chars": 419,
"preview": "def urls = [\n new URL('http', 'myshop.com', 80, 'index.html'),\n new URL('https', 'myshop.com', 443, 'buynow.html')"
},
{
"path": "listings/chap04/snippet0403_Map_Ctor_Expression.groovy",
"chars": 61,
"preview": "def x = 'a'\nassert ['x':1] == [x:1]\nassert ['a':1] == [(x):1]"
},
{
"path": "listings/chap04/snippet0403_Map_Ctor_Unquoted.groovy",
"chars": 23,
"preview": "assert ['a':1] == [a:1]"
},
{
"path": "listings/chap04/snippet0403_Map_MapReduce.groovy",
"chars": 184,
"preview": "def people = [peter: 40, paul: 30, mary: 20]\nassert people\n .findAll{ _, age -> age < 35 }\n .collect{ name, _ -> n"
},
{
"path": "listings/chap04/snippet0403_Map_String_accessors.groovy",
"chars": 45,
"preview": "def myMap = ['a.b':1]\nassert myMap.'a.b' == 1"
},
{
"path": "listings/chap05/Listing_05_01_closure_simple_declaration.groovy",
"chars": 148,
"preview": "def log = ''\n(1..10).each { counter -> log += counter }\nassert log == '12345678910'\n\nlog = ''\n(1..10).each { log += it }"
},
{
"path": "listings/chap05/Listing_05_02_simple_method_closure.groovy",
"chars": 609,
"preview": "class SizeFilter {\n Integer limit\n\n boolean sizeUpTo(String value) {\n return value.size() <= limit\n }\n}\n"
},
{
"path": "listings/chap05/Listing_05_03_multi_method_closure.groovy",
"chars": 640,
"preview": "class MultiMethodSample {\n \n int mysteryMethod (String value) {\n return value.length()\n }\n int myster"
},
{
"path": "listings/chap05/Listing_05_04_closure_all_declarations.groovy",
"chars": 695,
"preview": "Map map = ['a':1, 'b':2]\nmap.each{ key, value -> map[key] = value * 2 } //#1\nassert map == ['a':2, 'b':4]\n\nClosu"
},
{
"path": "listings/chap05/Listing_05_05_simple_closure_calling.groovy",
"chars": 89,
"preview": "def adder = { x, y -> return x+y }\n\nassert adder(4, 3) == 7\nassert adder.call(2, 6) == 8\n"
},
{
"path": "listings/chap05/Listing_05_06_calling_closures.groovy",
"chars": 631,
"preview": "def benchmark(int repeat, Closure worker) { //#1\n def start = System.nanoTime() //#2\n"
},
{
"path": "listings/chap05/Listing_05_07_simple_currying.groovy",
"chars": 90,
"preview": "def mult = { x, y -> return x * y }\ndef twoTimes = mult.curry(2)\nassert twoTimes(5) == 10"
},
{
"path": "listings/chap05/Listing_05_08_logging_curry_example.groovy",
"chars": 837,
"preview": "def configurator = { format, filter, line -> //#1\n filter(line) ? format(line) : null "
},
{
"path": "listings/chap05/Listing_05_09_closure_scope.groovy",
"chars": 1012,
"preview": "class Mother {\n def prop = 'prop'\n def method(){ 'method' }\n Closure birth (param) { //#"
},
{
"path": "listings/chap05/Listing_05_10_closure_accumulator.groovy",
"chars": 117,
"preview": "def foo(n) {\n return { n += it }\n}\n\ndef accumulator = foo(1)\nassert accumulator(2) == 3\nassert accumulator(1) == 4"
},
{
"path": "listings/chap05/Listing_05_11_visitor_pattern.groovy",
"chars": 622,
"preview": "class Drawing {\n List shapes\n def accept(Closure yield) { shapes.each{it.accept(yield)} }\n}\nclass Shape {\n def "
},
{
"path": "listings/chap05/extra_ClosureProperty.groovy",
"chars": 274,
"preview": "class GrailsController {\n def params = [a:1, b:2]\n def list = { params.keySet().toList() }\n}\n\ndef controller = n"
},
{
"path": "listings/chap05/extra_Closure_delegate.groovy",
"chars": 102,
"preview": "def list = []\ndef expected = [1, 2]\n\nlist.with {\n add 1\n add 2\n assert delegate == expected\n}"
},
{
"path": "listings/chap05/extra_Closure_myWith.groovy",
"chars": 86,
"preview": "def with(Closure doit) { // fake implementation\n doit.delegate = list\n doit()\n}"
},
{
"path": "listings/chap05/snippet0501_envelope.groovy.txt",
"chars": 87,
"preview": "Closure envelope = { person -> new Letter(person).send() }\naddressBook.each (envelope)\n"
},
{
"path": "listings/chap05/snippet0504_closure_default_params.groovy",
"chars": 92,
"preview": "def adder = { x, y=5 -> return x+y }\n\nassert adder(4, 3) == 7 \nassert adder.call(7) == 12\n"
},
{
"path": "listings/chap05/snippet0504_closure_isCase.groovy",
"chars": 133,
"preview": "def odd = { it % 2 == 1}\n\nassert [1,2,3].grep(odd) == [1, 3]\n\nswitch(10) {\n case odd : assert false\n}\n\nif (2 in odd) "
},
{
"path": "listings/chap05/snippet0504_closure_paramcount.groovy",
"chars": 327,
"preview": "def numParams (Closure closure){\n closure.getMaximumNumberOfParameters()\n}\n\nassert numParams { one -> } == 1\nasser"
},
{
"path": "listings/chap05/snippet0505_map_with.groovy",
"chars": 76,
"preview": "def map = [:]\nmap.with {\n a = 1\n b = 2 \n} \nassert map == [a:1, b:2]"
},
{
"path": "listings/chap05/snippet0505_scoping.groovy",
"chars": 44,
"preview": "def x = 0\n10.times {\n x++\n}\nassert x == 10\n"
},
{
"path": "listings/chap05/snippet0506_closure_return.groovy",
"chars": 194,
"preview": "assert [2, 4, 6] == [1, 2, 3].collect { it * 2 }\n\nassert [2, 4, 6] == [1, 2, 3].collect { return it * 2 }\n\nassert [1, 4,"
},
{
"path": "listings/chap05/snippet0507_closure_composition.groovy",
"chars": 216,
"preview": "def mult = { x, y -> return x * y }\ndef twoTimes = mult.curry(2)\nassert twoTimes(5) == 10\n\ndef fourTimes = twoTimes >>"
},
{
"path": "listings/chap05/snippet0508_memoize.groovy",
"chars": 187,
"preview": "def fib \nfib = { it < 2 ? 1 : fib(it-1) + fib(it-2) }\nfib = fib.memoize()\n\nassert fib(40) == 165_580_141\n\n\n// nano time\n"
},
{
"path": "listings/chap05/snippet0509_trampoline.groovy",
"chars": 135,
"preview": "def last\nlast = { it.size() == 1 ? it.head() : last.trampoline(it.tail()) }\n\nlast = last.trampoline()\n\nassert last(0..10"
},
{
"path": "listings/chap06/Listing_06_01_groovy_truth.groovy",
"chars": 1798,
"preview": "assert true //#A\nassert !false //#A\n"
},
{
"path": "listings/chap06/Listing_06_02_assignment_bug.groovy",
"chars": 669,
"preview": "def x = 1\n\nif (x == 2) { //#1\n assert false\n}\n/*******************\nif (x = "
},
{
"path": "listings/chap06/Listing_06_03_if_then_else.groovy",
"chars": 289,
"preview": "if (true) assert true\nelse assert false\n\nif (1) {\n assert true\n} else {\n assert false\n} \n\nif ("
},
{
"path": "listings/chap06/Listing_06_04_conditional_operator.groovy",
"chars": 117,
"preview": "def result = (1==1) ? 'ok' : 'failed'\nassert result == 'ok'\n\nresult = 'some string' ? 10 : ['x']\nassert result == 10\n"
},
{
"path": "listings/chap06/Listing_06_05_switch_basic.groovy",
"chars": 259,
"preview": "def a = 1\ndef log = ''\nswitch (a) {\n case 0 : log += '0' //#A\n case 1 : log += '1'"
},
{
"path": "listings/chap06/Listing_06_06_switch_advanced.groovy",
"chars": 448,
"preview": "switch (10) {\n case 0 : assert false ; break\n case 0..9 : assert false ; break\n case [8,9,11] "
},
{
"path": "listings/chap06/Listing_06_07_assert_host.groovy",
"chars": 600,
"preview": "def host = /\\/\\/([a-zA-Z0-9-]+(\\.[a-zA-Z0-9-])*?)(:|\\/)/ //#A\n\nassertHost 'http://a.b.c:8080/bla', host, 'a.b"
},
{
"path": "listings/chap06/Listing_06_08_while.groovy",
"chars": 148,
"preview": "def list = [1, 2, 3]\nwhile (list) {\n list.remove(0)\n}\nassert list == []\n\nwhile (list.size() < 3) list << list.size() "
},
{
"path": "listings/chap06/Listing_06_09_for.groovy",
"chars": 2680,
"preview": "def store = '' //#1\nfor (String s in 'a'..'c') store += s //#1\n"
},
{
"path": "listings/chap06/Listing_06_10_break_continue.groovy",
"chars": 401,
"preview": "def a = 1\nwhile (true) { //#A\n a++\n break "
},
{
"path": "listings/chap06/Listing_06_11_exception_example.groovy",
"chars": 200,
"preview": "def myMethod() {\n throw new IllegalArgumentException()\n}\n\ndef log = []\ntry {\n myMethod()\n} catch (Exception e) {\n "
},
{
"path": "listings/chap06/extra_if_return.groovy",
"chars": 167,
"preview": "def mac() {\n if (System.properties.'os.name'.contains('Mac'))\n \"We're on Mac.\" // no 'return'\n else\n "
},
{
"path": "listings/chap06/extra_in_operator.groovy",
"chars": 148,
"preview": "assert 1 in [0, 1, 2] // list\nassert 1 in 0..3 // range\nassert 'Hello' in String // class\nassert 'He"
},
{
"path": "listings/chap06/extra_switch_return.groovy",
"chars": 204,
"preview": "def mac() {\n switch(System.properties.'os.name') {\n case 'Mac OS X': \"We're on Mac.\"; break // no 'return'\n "
},
{
"path": "listings/chap06/myFileName.txt",
"chars": 17,
"preview": "line one\nline two"
},
{
"path": "listings/chap06/snippet0602_bad_file_read.groovy",
"chars": 271,
"preview": "try {\n input = new File('no such file')\n assert input.exists()\n assert input.canRead()\n println input.text\n}"
},
{
"path": "listings/chap06/snippet0602_bad_file_read_with_message.groovy",
"chars": 352,
"preview": "try {\n input = new File('/no such file')\n assert input.exists(), \"cannot find: $input.canonicalPath\"\n assert in"
},
{
"path": "listings/chap06/snippet0602_failing_assert.groovy",
"chars": 149,
"preview": "def a = 1\ntry {\n assert a == 2\n} catch (AssertionError error) {\n assert \"\\n\" + error.message =='''\nassert a == 2\n "
},
{
"path": "listings/chap06/snippet0603_each_loop_iterate.groovy",
"chars": 27,
"preview": "(0..9).each { println it }\n"
},
{
"path": "listings/chap06/snippet0603_file_iterate_lines.groovy",
"chars": 70,
"preview": "def file = new File('myFileName.txt')\nfor (line in file) println line\n"
},
{
"path": "listings/chap06/snippet0603_for_loop_iterate.groovy",
"chars": 30,
"preview": "for (x in 0..9) { println x }\n"
},
{
"path": "listings/chap06/snippet0603_null_iterate.groovy",
"chars": 52,
"preview": "for (x in null) println 'This will not be printed!'\n"
},
{
"path": "listings/chap06/snippet0603_object_iterate.groovy",
"chars": 61,
"preview": "for (x in new Object()) println \"Printed once for object $x\"\n"
},
{
"path": "listings/chap06/snippet0603_regex_iterate_match.groovy",
"chars": 65,
"preview": "def matcher = '12xy3'=~/\\d/\nfor (match in matcher) println match\n"
},
{
"path": "listings/chap06/snippet0604_multicatch.groovy",
"chars": 160,
"preview": "try {\n if (Math.random() < 0.5) 1 / 0\n else null.hashCode()\n} catch (ArithmeticException | NullPointerException except"
},
{
"path": "listings/chap07/Listing_07_01_Declaring_Variables.groovy",
"chars": 920,
"preview": "class ClassWithTypedAndUntypedFieldsAndProperties {\n\n public fieldWithModifier\n String typedField\n def "
},
{
"path": "listings/chap07/Listing_07_02_TypeBreaking_Assignment.groovy",
"chars": 173,
"preview": "final String PI = '3.14'\nassert PI.class.name == 'java.lang.String'\nassert PI.size() == 4\nGroovyAssert.shouldFail(ClassC"
},
{
"path": "listings/chap07/Listing_07_03_Referencing_Fields.groovy",
"chars": 189,
"preview": "class Counter {\n public count = 0\n}\n\ndef counter = new Counter()\n\ncounter.count = 1\nassert counter.count == 1\n\ndef fi"
},
{
"path": "listings/chap07/Listing_07_04_Overriding_Field_Access.groovy",
"chars": 396,
"preview": "class PretendFieldCounter {\n public count = 0\n\n Object get (String name) {\n return 'pretend value'\n }\n "
},
{
"path": "listings/chap07/Listing_07_05_Declaring_Methods.groovy",
"chars": 584,
"preview": "class ClassWithTypedAndUntypedMethods {\n\n static void main(args) { //#1\n def some = new "
},
{
"path": "listings/chap07/Listing_07_06_Declaring_Parameters.groovy",
"chars": 357,
"preview": "class ClassWithTypedAndUntypedMethodParams {\n static void main(args) {\n assert 'untyped' == method(1)\n assert 'ty"
},
{
"path": "listings/chap07/Listing_07_07_Parameter_Usages.groovy",
"chars": 1037,
"preview": "class Summer {\n def sumWithDefaults(a, b, c=0){ //#1\n return a + b + c\n }\n def sum"
},
{
"path": "listings/chap07/Listing_07_08_Safe_Dereferencing.groovy",
"chars": 408,
"preview": "def map = [a:[b:[c:1]]] \n\nassert map.a.b.c == 1\n\nif (map && map.a && map.a.x){ //#1\n "
},
{
"path": "listings/chap07/Listing_07_09_Instantiation.groovy",
"chars": 465,
"preview": "class VendorWithCtor {\n String name, product\n\n VendorWithCtor(name, product) { //#A\n thi"
},
{
"path": "listings/chap07/Listing_07_10_Instantiation_Named.groovy",
"chars": 257,
"preview": "class SimpleVendor {\n String name, product\n}\n\nnew SimpleVendor()\nnew SimpleVendor(name: 'Canoo')\nnew SimpleVendor(pro"
},
{
"path": "listings/chap07/Listing_07_11_Classes.groovy",
"chars": 550,
"preview": "class Vendor {\n public String name\n public String product\n public Address address = new Address()\n}\n"
},
{
"path": "listings/chap07/Listing_07_13_Import.groovy",
"chars": 165,
"preview": "import business.*\n\ndef canoo = new Vendor()\ncanoo.name = 'Canoo Engineering AG'\ncanoo.product = 'UltraLig"
},
{
"path": "listings/chap07/Listing_07_14_Import_As_BugFix.groovy",
"chars": 455,
"preview": "import thirdparty.MathLib as OrigMathLib\n\nclass MathLib extends OrigMathLib {\n Integer twice(Integer value) {\n "
},
{
"path": "listings/chap07/Listing_07_15_Import_As_NameClash.groovy",
"chars": 195,
"preview": "import thirdparty.MathLib as TwiceHalfMathLib\nimport thirdparty2.MathLib as IncMathLib\n\ndef math1 = new TwiceHalfMathLib"
},
{
"path": "listings/chap07/Listing_07_16_Multimethods.groovy",
"chars": 241,
"preview": "def oracle(Object o) { return 'object' }\ndef oracle(String o) { return 'string' }\n\nObject x = 1\nObject y = 'foo'\n\nassert"
},
{
"path": "listings/chap07/Listing_07_17_MultiEquals.groovy",
"chars": 221,
"preview": "class Equalizer {\n boolean equals(Equalizer e){\n return true\n }\n}\n\nObject same = new Equalizer()\nObject ot"
},
{
"path": "listings/chap07/Listing_07_18_Traits.groovy",
"chars": 609,
"preview": "trait HasId { //#1\n long id\n}\ntrait HasVersion {\n long version\n}\ntrait Persistent {\n boolean save() { println \"saving"
},
{
"path": "listings/chap07/Listing_07_19_Declaring_Beans.groovy",
"chars": 382,
"preview": "import java.io.Serializable\n\nclass MyBean implements Serializable {\n def untyped\n String typed\n def item1, item"
},
{
"path": "listings/chap07/Listing_07_20_Calling_Beans.groovy",
"chars": 489,
"preview": "class MrBean {\n String firstname, lastname //#A\n \n String getName(){ "
},
{
"path": "listings/chap07/Listing_07_21_Calling_Beans_Advanced.groovy",
"chars": 572,
"preview": "class DoublerBean {\n public value //#A\n \n void setValue(value){\n t"
},
{
"path": "listings/chap07/Listing_07_22_Property_Methods.groovy",
"chars": 461,
"preview": "class ClassWithProperties {\n def someProperty\n public someField\n private somePrivateField\n}\n\ndef obj"
},
{
"path": "listings/chap07/Listing_07_23_Expando.groovy",
"chars": 223,
"preview": "def boxer = new Expando()\n\nassert null == boxer.takeThis\n\nboxer.takeThis = 'ouch!'\n\nassert 'ouch!' == boxer.takeThis\n\nbo"
},
{
"path": "listings/chap07/Listing_07_24_GPath.groovy",
"chars": 2336,
"preview": "class Invoice { //#A\n List items /"
},
{
"path": "listings/chap07/business/Vendor.groovy",
"chars": 210,
"preview": "package business\n\nclass Vendor {\n public String name\n public String product\n public Address address = new Add"
},
{
"path": "listings/chap07/snippet0703_Implicit_Closure_To_SAM.groovy",
"chars": 176,
"preview": "import java.awt.event.ActionListener\nlisteners = []\ndef addListener(ActionListener al) { listeners << al }\naddListener {"
},
{
"path": "listings/chap07/snippet0705_Spread_List.groovy",
"chars": 97,
"preview": "def getList(){\n return [1,2,3]\n}\ndef sum(a,b,c){\n return a + b + c\n}\nassert 6 == sum(*list)"
},
{
"path": "listings/chap07/snippet0705_Spread_Map.groovy",
"chars": 58,
"preview": "def map = [a:1,b:2]\nassert [a:1, b:2, c:3] == [c:3, *:map]"
},
{
"path": "listings/chap07/snippet0705_Spread_Range.groovy",
"chars": 49,
"preview": "def range = (1..3)\nassert [0,1,2,3] == [0,*range]"
},
{
"path": "listings/chap07/thirdparty/MathLib.groovy",
"chars": 185,
"preview": "package thirdparty\n\nclass MathLib {\n Integer twice(Integer value) {\n return value * 3 // intentionally wrong"
},
{
"path": "listings/chap07/thirdparty2/MathLib.groovy",
"chars": 88,
"preview": "package thirdparty2\n\nclass MathLib {\n Integer increment(Integer value) { value + 1 }\n}\n"
},
{
"path": "listings/chap08/Listing_08_01_method_missing.groovy",
"chars": 198,
"preview": "class Pretender {\n def methodMissing(String name, Object args) {\n \"called $name with $args\"\n }\n}\ndef bounce"
},
{
"path": "listings/chap08/Listing_08_02_mini_gorm.groovy",
"chars": 456,
"preview": "class MiniGorm {\n def db = []\n Object methodMissing(String name, Object args) {\n println name\n db.fi"
},
{
"path": "listings/chap08/Listing_08_03_property_missing.groovy",
"chars": 166,
"preview": "class PropPretender {\n def propertyMissing(String name) {\n \"accessed $name\"\n }\n}\ndef bounce = new PropPrete"
},
{
"path": "listings/chap08/Listing_08_04_bin_property.groovy",
"chars": 191,
"preview": "def propertyMissing(String name) {\n int result = 0\n name.each {\n result <<= 1\n if (it == 'I') result"
},
{
"path": "listings/chap08/Listing_08_05_closure_dynamic.groovy",
"chars": 334,
"preview": "class DynamicPretender {\n Closure whatToDo = { name -> \"accessed $name\"} //#1\n def propertyMissing(String name) {"
},
{
"path": "listings/chap08/Listing_08_06_property_method.groovy",
"chars": 430,
"preview": "class NoParens {\n def getProperty(String propertyName) {\n if (metaClass.hasProperty(this, propertyName)) { //#"
},
{
"path": "listings/chap08/Listing_08_07_MetaClass_jdk7_only.groovy",
"chars": 387,
"preview": "MetaClass mc = String.metaClass\nfinal Object[] NO_ARGS = []\nassert 1 == mc.respondsTo(\"toString\", NO_ARGS).size()\nass"
},
{
"path": "listings/chap08/Listing_08_07_MetaClass_jdk8_plus.groovy",
"chars": 387,
"preview": "MetaClass mc = String.metaClass\nfinal Object[] NO_ARGS = []\nassert 1 == mc.respondsTo(\"toString\", NO_ARGS).size()\nass"
},
{
"path": "listings/chap08/Listing_08_08_ProxyMetaClass.groovy",
"chars": 567,
"preview": "class InspectMe {\n int outer(){\n return inner() \n }\n private int inner(){\n return 1\n }\n"
},
{
"path": "listings/chap08/Listing_08_09_Expando.groovy",
"chars": 149,
"preview": "def boxer = new Expando()\n\nboxer.takeThis = 'ouch!'\nboxer.fightBack = { times -> takeThis * times }\n\nassert boxer.figh"
},
{
"path": "listings/chap08/Listing_08_10_EMC.groovy",
"chars": 176,
"preview": "assert String.metaClass =~ /MetaClassImpl/\nString.metaClass.low = {-> delegate.toLowerCase() }\nassert String.metaClas"
},
{
"path": "listings/chap08/Listing_08_11_EMC_Groovy_Class.groovy",
"chars": 287,
"preview": "class MyGroovy1 { }\n\ndef before = new MyGroovy1()\n\nMyGroovy1.metaClass.myProp = \"MyGroovy prop\"\nMyGroovy1.metaClass.test"
},
{
"path": "listings/chap08/Listing_08_12_EMC_Groovy_Object.groovy",
"chars": 280,
"preview": "class MyGroovy2 { }\n\ndef myGroovy = new MyGroovy2()\n\nmyGroovy.metaClass.myProp = \"MyGroovy prop\"\nmyGroovy.metaClass.test"
},
{
"path": "listings/chap08/Listing_08_13_EMC_Java_Object.groovy",
"chars": 244,
"preview": "def myJava = new String()\n\nmyJava.metaClass.myProp = \"MyJava prop\"\nmyJava.metaClass.test = {-> myProp }\n\ntry {\n new S"
},
{
"path": "listings/chap08/Listing_08_14_EMC_Builder.groovy",
"chars": 382,
"preview": "def move(string, distance) {\n string.collect { (it as char) + distance as char }.join()\n}\n\nString.metaClass {\n shi"
},
{
"path": "listings/chap08/Listing_08_15_EMC_static.groovy",
"chars": 72,
"preview": "Integer.metaClass.static.answer = {-> 42}\n\nassert Integer.answer() == 42"
},
{
"path": "listings/chap08/Listing_08_16_EMC_super.groovy",
"chars": 288,
"preview": "class MySuperGroovy { }\nclass MySubGroovy extends MySuperGroovy { }\n\nMySuperGroovy.metaClass.added = {-> true }\n\nassert "
},
{
"path": "listings/chap08/Listing_08_17_EMC_hooks.groovy",
"chars": 407,
"preview": "String.metaClass {\n rightShiftUnsigned = { prefix ->\n delegate.replaceAll(~/\\w+/) { prefix + it }\n }\n me"
},
{
"path": "listings/chap08/Listing_08_18_Existing_Categories.groovy",
"chars": 309,
"preview": "import groovy.time.TimeCategory\n\ndef janFirst1970 = new Date(0)\nuse TimeCategory, {\n Date xmas = janFirst1970 + 1.y"
},
{
"path": "listings/chap08/Listing_08_19_Marshal.groovy",
"chars": 357,
"preview": "class Marshal {\n static String marshal(Integer self) {\n self.toString()\n }\n static Integer unMarshal(Str"
},
{
"path": "listings/chap08/Listing_08_20_MarshalCategory.groovy",
"chars": 519,
"preview": "@Category(Integer) //#1\nclass IntegerMarshal {\n String marshal() {\n toString() "
}
]
// ... and 519 more files (download for full content)
About this extraction
This page contains the full source code of the Dierk/GroovyInAction GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 719 files (676.3 KB), approximately 244.1k tokens, and a symbol index with 63 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.