Coalesce module inits with the same module name and function name and no 
arguments


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/0a3e456f
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/0a3e456f
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/0a3e456f

Branch: refs/heads/5.4-js-rewrite
Commit: 0a3e456ffe4e7a2ba2aedd047d79d2aab57b3e09
Parents: c7ba52c
Author: Howard M. Lewis Ship <[email protected]>
Authored: Mon Aug 13 14:35:12 2012 -0700
Committer: Howard M. Lewis Ship <[email protected]>
Committed: Mon Aug 13 14:35:12 2012 -0700

----------------------------------------------------------------------
 .../internal/services/DocumentLinkerImpl.java      |   39 +------
 .../internal/services/ModuleInitsManager.java      |   81 +++++++++++++++
 .../services/PartialMarkupDocumentLinker.java      |   49 ++-------
 .../services/javascript/Initialization.java        |   18 +++-
 .../services/javascript/JavaScriptSupport.java     |    4 +-
 .../services/DocumentLinkerImplTest.groovy         |   28 +++++
 6 files changed, 143 insertions(+), 76 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
index b51a896..80235f3 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
@@ -17,21 +17,18 @@ package org.apache.tapestry5.internal.services;
 import org.apache.tapestry5.dom.Document;
 import org.apache.tapestry5.dom.Element;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.services.javascript.InitializationPriority;
 import org.apache.tapestry5.services.javascript.ModuleManager;
 import org.apache.tapestry5.services.javascript.StylesheetLink;
 
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 public class DocumentLinkerImpl implements DocumentLinker
 {
     private final List<String> libraryURLs = CollectionFactory.newList();
 
-    private final Map<InitializationPriority, List<JSONArray>> 
priorityToModuleInit = CollectionFactory.newMap();
+    private final ModuleInitsManager initsManager = new ModuleInitsManager();
 
     private final List<StylesheetLink> includedStylesheets = 
CollectionFactory.newList();
 
@@ -44,8 +41,6 @@ public class DocumentLinkerImpl implements DocumentLinker
     // Initially false; set to true when a scriptURL or any kind of 
initialization is added.
     private boolean hasScriptsOrInitializations;
 
-    private int initCount;
-
     /**
      * @param moduleManager
      *         used to identify the root folder for dynamically loaded modules
@@ -81,19 +76,9 @@ public class DocumentLinkerImpl implements DocumentLinker
 
     public void addInitialization(InitializationPriority priority, String 
moduleName, String functionName, JSONArray arguments)
     {
-        JSONArray init = new JSONArray();
-
-        String name = functionName == null ? moduleName : moduleName + ":" + 
functionName;
-
-        init.put(name);
-
-        init.putAll(arguments);
-
-        InternalUtils.addToMapList(priorityToModuleInit, priority, init);
+        initsManager.addInitialization(priority, moduleName, functionName, 
arguments);
 
         hasScriptsOrInitializations = true;
-
-        initCount++;
     }
 
     /**
@@ -189,22 +174,6 @@ public class DocumentLinkerImpl implements DocumentLinker
         return container;
     }
 
-    private List<JSONArray> forPriority(InitializationPriority... priorities)
-    {
-        List<JSONArray> result = new ArrayList<JSONArray>(initCount);
-
-        for (InitializationPriority p : priorities)
-        {
-            List<JSONArray> inits = priorityToModuleInit.get(p);
-
-            if (inits != null)
-            {
-                result.addAll(inits);
-            }
-        }
-
-        return result;
-    }
 
     /**
      * Adds {@code <script>} elements for the RequireJS library, then any 
statically includes JavaScript libraries
@@ -220,8 +189,8 @@ public class DocumentLinkerImpl implements DocumentLinker
         // Eventually, (nearly) everything will be loaded as modules.
 
         moduleManager.writeInitialization(body, libraryURLs,
-                forPriority(InitializationPriority.IMMEDIATE),
-                forPriority(InitializationPriority.EARLY, 
InitializationPriority.NORMAL, InitializationPriority.LATE));
+                initsManager.forPriority(InitializationPriority.IMMEDIATE),
+                initsManager.forPriority(InitializationPriority.EARLY, 
InitializationPriority.NORMAL, InitializationPriority.LATE));
     }
 
     private static Element createTemporaryContainer(Element headElement, 
String existingElementName, String newElementName)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ModuleInitsManager.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ModuleInitsManager.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ModuleInitsManager.java
new file mode 100644
index 0000000..1442ab9
--- /dev/null
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ModuleInitsManager.java
@@ -0,0 +1,81 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// 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.
+
+package org.apache.tapestry5.internal.services;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.json.JSONArray;
+import org.apache.tapestry5.services.javascript.InitializationPriority;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ModuleInitsManager
+{
+    private final Set<String> pureInits = CollectionFactory.newSet();
+
+    private final Map<InitializationPriority, List<JSONArray>> inits = 
CollectionFactory.newMap();
+
+    private int initCount;
+
+    public void addInitialization(InitializationPriority priority, String 
moduleName, String functionName, JSONArray arguments)
+    {
+        assert priority != null;
+        assert InternalUtils.isNonBlank(moduleName);
+
+        String name = functionName == null ? moduleName : moduleName + ":" + 
functionName;
+
+        if ((arguments == null || arguments.length() == 0))
+        {
+            if (pureInits.contains(name))
+            {
+                // A degenerate case is a pure init added repeatedly with 
different priorities. That isn't handled:
+                // the first priority wins.
+                return;
+            }
+
+            pureInits.add(name);
+        }
+
+        JSONArray init = new JSONArray();
+
+        init.put(name);
+
+        init.putAll(arguments);
+
+        InternalUtils.addToMapList(inits, priority, init);
+
+        initCount++;
+    }
+
+    public List<JSONArray> forPriority(InitializationPriority... priorities)
+    {
+        List<JSONArray> result = new ArrayList<JSONArray>(initCount);
+
+        for (InitializationPriority p : priorities)
+        {
+            List<JSONArray> initsForPriority = inits.get(p);
+
+            if (initsForPriority != null)
+            {
+                result.addAll(initsForPriority);
+            }
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
index 0560f6b..fe64a04 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
@@ -15,23 +15,18 @@
 package org.apache.tapestry5.internal.services;
 
 import org.apache.tapestry5.internal.InternalConstants;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.json.JSONObject;
 import org.apache.tapestry5.services.javascript.InitializationPriority;
 import org.apache.tapestry5.services.javascript.StylesheetLink;
 
-import java.util.List;
-import java.util.Map;
-
 public class PartialMarkupDocumentLinker implements DocumentLinker
 {
     private final JSONArray libraryURLs = new JSONArray();
 
     private final JSONArray stylesheets = new JSONArray();
 
-    private final Map<InitializationPriority, List<JSONArray>> initsByPriority 
= CollectionFactory.newMap();
+    private final ModuleInitsManager initsManager = new ModuleInitsManager();
 
     public void addLibrary(String libraryURL)
     {
@@ -58,13 +53,7 @@ public class PartialMarkupDocumentLinker implements 
DocumentLinker
     @Override
     public void addInitialization(InitializationPriority priority, String 
moduleName, String functionName, JSONArray arguments)
     {
-        String qualifiedName = functionName == null ? moduleName : moduleName 
+ ":" + functionName;
-
-        JSONArray init = new JSONArray().put(qualifiedName);
-
-        init.putAll(arguments);
-
-        InternalUtils.addToMapList(initsByPriority, priority, init);
+        initsManager.addInitialization(priority, moduleName, functionName, 
arguments);
     }
 
     /**
@@ -75,44 +64,26 @@ public class PartialMarkupDocumentLinker implements 
DocumentLinker
      */
     public void commit(JSONObject reply)
     {
-        JSONArray fullInits = new JSONArray();
-
-        for (InitializationPriority p : InitializationPriority.values())
+        if (libraryURLs.length() > 0)
         {
-            List<JSONArray> priorityInits = initsByPriority.get(p);
-
-            if (priorityInits != null)
-            {
-                for (JSONArray init : priorityInits)
-                {
-                    fullInits.put(init);
-                }
-            }
+            reply.in(InternalConstants.PARTIAL_KEY).put("libraries", 
libraryURLs);
         }
 
-        boolean hasWork = libraryURLs.length() > 0 || stylesheets.length() > 0 
|| fullInits.length() > 0;
-
-        if (!hasWork)
+        if (stylesheets.length() > 0)
         {
-            return;
+            reply.in(InternalConstants.PARTIAL_KEY).put("stylesheets", 
stylesheets);
         }
 
-        JSONObject partial = reply.in(InternalConstants.PARTIAL_KEY);
-
-
-        if (libraryURLs.length() > 0)
-        {
-            partial.put("libraries", libraryURLs);
-        }
+        JSONArray fullInits = new JSONArray();
 
-        if (stylesheets.length() > 0)
+        for (InitializationPriority p : InitializationPriority.values())
         {
-            partial.put("stylesheets", stylesheets);
+            fullInits.putAll(initsManager.forPriority(p));
         }
 
         if (fullInits.length() > 0)
         {
-            partial.put("inits", fullInits);
+            reply.in(InternalConstants.PARTIAL_KEY).put("inits", fullInits);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java
index 9fafcf6..b201de8 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java
@@ -1,3 +1,17 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// 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.
+
 package org.apache.tapestry5.services.javascript;
 
 /**
@@ -30,7 +44,9 @@ public interface Initialization
 
     /**
      * Specifies the arguments to be passed to the function. Normally, just a 
single {@link org.apache.tapestry5.json.JSONObject}
-     * is passed.
+     * is passed. When multiple Initializations exist with the same function 
name (or no function name), and no arguments,
+     * they are coalesced into a single Initialization: it is assumed that an 
initialization with no parameters needs to
+     * only be invoked once.
      *
      * @param arguments
      *         any number of values. Each value may be one of: null, String, 
Boolean, Number,

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java
index 2fc30bc..f9db282 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java
@@ -226,7 +226,9 @@ public interface JavaScriptSupport
 
 
     /**
-     * Requires a JavaScript module by name. On the c
+     * Requires a JavaScript module by name. On the client, this will 
<code>require()</code> the module and
+     * (optionally) de-reference a function exported by the module (or, treat 
the module as exporting a single
+     * implicit function). The function will be invoked.
      *
      * @param moduleName
      *         the name of the module to require

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy
 
b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy
index 4f5efad..f23f1ab 100644
--- 
a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy
+++ 
b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy
@@ -361,6 +361,34 @@ class DocumentLinkerImplTest extends InternalBaseTestCase {
         verify()
     }
 
+    @Test
+    void module_initialization_with_no_parameters_coalesce() throws Exception {
+        Document document = new Document()
+
+        Element head = document.newRootElement("html").element("head")
+
+        head.element("meta")
+
+        def manager = mockModuleManager([], [], [new 
JSONArray("['my/module']"),
+            new JSONArray("my/other/module:normal", 111, 222)])
+
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, 
"1.2.3")
+
+        replay()
+
+        linker.addInitialization(InitializationPriority.NORMAL, "my/module", 
null, null)
+        linker.addInitialization(InitializationPriority.NORMAL, 
"my/other/module", "normal", new JSONArray(111, 222))
+        linker.addInitialization(InitializationPriority.NORMAL, "my/module", 
null, new JSONArray());
+
+        linker.updateDocument(document)
+
+        check document, '''
+<html><head><meta/></head><body><!--MODULE-MANAGER-INITIALIZATION--></body></html>
+'''
+
+        verify()
+    }
+
     private ModuleManager mockModuleManager(scripts, immediateInits, 
deferredInits) {
 
         ModuleManager mock = newMock(ModuleManager);

Reply via email to