Author: hlship
Date: Fri Oct 20 08:00:38 2006
New Revision: 466136

URL: http://svn.apache.org/viewvc?view=rev&rev=466136
Log:
Extend the prop: binding with a type of literal representing an integer range.

Added:
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/IntegerRange.java
    
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IntegerRangeTest.java
Modified:
    
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html
    tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml
    
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Count.java
    
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
    
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=466136&r1=466135&r2=466136
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
 Fri Oct 20 08:00:38 2006
@@ -59,6 +59,7 @@
 import org.apache.tapestry.services.WebRequest;
 import org.apache.tapestry.services.WebRequestFilter;
 import org.apache.tapestry.services.WebResponse;
+import org.apache.tapestry.util.IntegerRange;
 
 /**
  * 
@@ -383,6 +384,31 @@
             }
         };
 
+        BindingFactory intRangeFactory = new BindingFactory()
+        {
+            private final Pattern _pattern = Pattern
+                    .compile("^\\s*(-?\\d+)\\s*\\.\\.\\s*(-?\\d+)\\s*$");
+
+            @SuppressNullCheck
+            public Binding newBinding(String description, ComponentResources 
component,
+                    String expression, Location location)
+            {
+                Matcher matcher = _pattern.matcher(expression);
+
+                if (matcher.matches())
+                {
+                    int start = Integer.parseInt(matcher.group(1));
+                    int finish = Integer.parseInt(matcher.group(2));
+
+                    IntegerRange range = new IntegerRange(start, finish);
+
+                    return new LiteralBinding(description, range, location);
+                }
+
+                return null;
+            }
+        };
+
         BindingFactory doubleFactory = new BindingFactory()
         {
             // So, either 1234. or 1234.56 or .78
@@ -434,6 +460,7 @@
         configuration.add("Keyword", keywordFactory);
         configuration.add("This", thisFactory);
         configuration.add("Long", longFactory);
+        configuration.add("IntRange", intRangeFactory);
         configuration.add("Double", doubleFactory);
         configuration.add("StringLiteral", stringFactory);
     }

Added: 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/IntegerRange.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/IntegerRange.java?view=auto&rev=466136
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/IntegerRange.java
 (added)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/util/IntegerRange.java
 Fri Oct 20 08:00:38 2006
@@ -0,0 +1,129 @@
+// Copyright 2006 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.tapestry.util;
+
+import java.util.Iterator;
+
+/**
+ * Represents a sequence of integer values, either ascending or descending. 
The sequence is always
+ * inclusive (of the finish value).
+ */
+public final class IntegerRange implements Iterable<Integer>
+{
+    private final int _start;
+
+    private final int _finish;
+
+    private class RangeIterator implements Iterator<Integer>
+    {
+        private final int _increment;
+
+        private int _value = _start;
+
+        private boolean _hasNext = true;
+
+        RangeIterator()
+        {
+            _increment = _start < _finish ? +1 : -1;
+        }
+
+        public boolean hasNext()
+        {
+            return _hasNext;
+        }
+
+        public Integer next()
+        {
+            if (!_hasNext)
+                throw new IllegalStateException();
+
+            int result = _value;
+
+            _hasNext = _value != _finish;
+
+            _value += _increment;
+
+            return result;
+        }
+
+        public void remove()
+        {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    public IntegerRange(final int start, final int finish)
+    {
+        _start = start;
+        _finish = finish;
+    }
+
+    public int getFinish()
+    {
+        return _finish;
+    }
+
+    public int getStart()
+    {
+        return _start;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%d..%d", _start, _finish);
+    }
+
+    /**
+     * The main puprose of a range object is to produce an Iterator. Since 
IntegerRange is iterable,
+     * it is useful with the Tapestry Loop component, but also with the Java 
for loop!
+     */
+    public Iterator<Integer> iterator()
+    {
+        return new RangeIterator();
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int PRIME = 31;
+
+        int result = PRIME + _finish;
+
+        result = PRIME * result + _start;
+
+        return result;
+    }
+
+    /** Returns true if the other object is an IntegerRange with the same 
start and finish values. */
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final IntegerRange other = (IntegerRange) obj;
+        if (_finish != other._finish)
+            return false;
+        if (_start != other._start)
+            return false;
+        return true;
+    }
+
+}

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt?view=diff&rev=466136&r1=466135&r2=466136
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt 
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt 
Fri Oct 20 08:00:38 2006
@@ -134,9 +134,7 @@
   
   Property bindings are normally either simple names of properties 
("prop:userName")
   or paths to properties ("prop:user.address.city").
-  
-  <<Note: Property paths are not yet implemented.>>    
-  
+    
   In addition, a few special cases are also supported. These are especially 
useful inside
   Java annotations, since prop: is the default binding prefix outside the 
component template.
   In most cases, these special values save you the trouble of adding a 
"literal:" prefix to
@@ -151,6 +149,7 @@
   * Simple numeric values are also accepted. These will be parsed into Long or 
Double objects.
     Ex: "prop:3.14".
     
+  * A range of integers separated by two periods. Ex: "prop:1..10".  
   
   * Literal strings, inside single quotes.  Ex: "prop:'Hello World'"
   

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html?view=diff&rev=466136&r1=466135&r2=466136
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html 
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html 
Fri Oct 20 08:00:38 2006
@@ -5177,7 +5177,7 @@
 <div tiddler="MasterIndex" modifier="HowardLewisShip" modified="200610071244" 
created="200609202214" tags="">Top level concepts within Tapestry 5.\n\n* 
PropBinding -- Notes on the workhorse &quot;prop:&quot; binding prefix\n* 
TypeCoercion -- How Tapestry 5 extensibly addresses type conversion\n* 
FormProcessing\n* DynamicPageState -- tracking changes to page state during the 
render\n* EnvironmentalServices -- how components cooperate during page 
render\n* ComponentMixins -- A new fundamental way to build web 
functionality\n* RequestTypes -- Requests, request processing, URL formats</div>
 <div tiddler="OGNL" modifier="HowardLewisShip" modified="200610071249" 
created="200609202254" tags="">The [[Object Graph Navigation 
Library|http://ognl.org]] was an essential part of Tapestry 4.\n\nOGNL is both 
exceptionally powerful (especially the higher order things it can do, such as 
list selections and projections). However, for the highest\nend sites, it is 
also a performance problem, both because of its heavy use of reflection, and 
because it uses a lot of code inside synchronized blocks.\n\nIt will be 
optional in Tapestry 5. I believe it will not be part of the tapestry-core, but 
may be packaged as tapestry-ognl.\n\nThe &quot;prop:&quot; binding prefix is an 
effective replacement for OGNL in Tapestry 5.   See PropBinding.\n</div>
 <div tiddler="PageRenderRequest" modifier="HowardLewisShip" 
modified="200610081333" created="200610071313" tags="">Page render requests are 
requests used to render a specific page.  //render// is the term meaning to 
compose the HTML response to be sent to the client. Note: HTML is used here 
only as the most common case, other markups are entirely possible.\n\nIn many 
cases, pages are stand-alone.  No extra information in the URL is necesarry to 
render them.  PersistentProperties of the page will factor in to the rendering 
of the page.\n\nIn specific cases, a page needs to render within a particular 
context. The most common example of this is a page that is used to present a 
specific instance of a database persistent entity. In such a case, the page 
must be combined with additional data, in the URL, to identify the specific 
entity to access and render.\n\n! URI 
Format\n\n{{{\n/page-name.html/id\n}}}\n\nHere &quot;page-name&quot; is the 
LogicalPageName for the page. \n\nThe &q
 uot;.html&quot; file extension is used as a delimiter between the page name 
portion of the URI, and the context portion of the URI. This is necessary 
because it is not possible (given the plethora of libraries and folders) to 
determine how many slashes will appear in the URI.\n\nThe context consists of 
one ore more ids (though a single id is the normal case). The id is used to 
identify the specific data to be displayed. Further, a page may require 
multiple ids, which will separated with slashes. Example: 
/admin/DisplayDetail.html/loginfailures/2006\n\nNote that these context values, 
the ids, are simply //strings//. Tapestry 4 had a mechanism, the DataSqueezer, 
that would encode the type of object with its value, as a single string, and 
convert it back. While seemingly desirable, this facility was easy to abuse, 
resulting in long and extremely ugly URIs.\n\nAny further information needed by 
Tapestry will be added to the URI as query parameters. This may include things 
like us
 er locale, persistent page properties, applicaition flow identifiers, or 
anything else we come up with.\n\n! Request Processing\n\nOnce the page and id 
parameters are identified, the corresponding page will be loaded.\n\nTapestry 
will fire two events before rendering the page.\n\nThe first event is of type 
&quot;setupPageRender&quot;.  This allows the page to process the context (the 
set of ids). This typically involves reading objects from an external 
persistent store (a database)\nand storing those objects into transient page 
properties, in expectaion of the render.\n\nThe @SetupPageRender annotation 
marks a method to be invoked when this event is triggered.  The method may take 
one or more strings, or an array of strings, as parameters; these will be\nthe 
context values.  The method will normally return void.  Other values are 
''TBD''. It may also take other simple types, which will be coerced from the 
string [EMAIL PROTECTED] setup(long id)\n{\n  . .
  .\n}\n}}}\n\n\n\nThe second event is of type &quot;pageValidate&quot;.  It 
allows the page to decide whether the page is valid for rendering at this time. 
This most often involves a check to see if the user is logged into the 
application, and has the necessary privileges to display the contents of the 
page.  User identity and privileges are //not// concepts built into Tapestry, 
but are fundamental to the majority of Tapestry applications.</div>
-<div tiddler="PropBinding" modifier="HowardLewisShip" modified="200610071247" 
created="200609202203" tags="bindings">The &quot;prop:&quot; binding prefix is 
the default in a  lot of cases, i.e., in any Java code (annotations).\n\nThis 
binding prefix  supports several common idioms even though they are not, 
precisely, the names of properties.  In many cases, this will save developers 
the bother of using a &quot;literal:&quot; prefix.\n\nThe goal of the 
&quot;prop:&quot; prefix is to be highly efficient and useful in 90%+ of the 
cases. [[OGNL]], or synthetic properties in the component class, will pick up 
the remaining cases.\n\n!Numeric literals\n\nSimple numeric literals should be 
parsed into read-only, invariant 
bindings.\n{{{\nprop:5\n\nprop:-22.7\n}}}\n\n\nThe resulting objects will be of 
type Long or type Double. TypeCoercion will ensure that component parameters 
get values (say, int or float) of the correct type.\n\n!Boolean 
literals\n\n&quot;true&quot; and &quot;false&
 quot; should also be converted to invariant 
bindings.\n{{{\nprop:true\n\nprop:false\n}}}\n\n!String literals\n\n//Simple// 
string literals, enclosed in single quotes.  Example:\n{{{\nprop:'Hello 
World'\n}}}\n\n//Remember that the binding expression will always be enclosed 
in double quotes.//\n\n!This literal\n\nIn some cases, it is useful to be able 
to identify the current component:\n{{{\nprop:this\n}}}\n\nEven though a 
component is not immutable, the value of //this// does not ever change,\nand 
this binding is also invariant.\n\n!Null literal\n\n{{{\nprop:null\n}}}\n\nThis 
value is always exactly null. This can be used to set a parameter who'se 
default value is non-null to the explicit value null.\n\n!Property 
paths\n\nMulti-step property paths are extremely 
important.\n\n{{{\nprop:poll.title\n\nprop:identity.user.name\n}}}\n\nThe 
initial terms need to be readable, they are never updated. Only the final 
property name must be read/write, and in fact, it is valid to be read-
 only or write-only.\n\nThe prop: binding factory builds a Java expression to 
read and update properties. It does not use reflection at runtime. Therefore, 
the properties of the //declared// type are used. By contrast, [[OGNL]] uses 
the //actual// type, which is reflection-intensive. Also, unlike OGNL, errors 
(such as missing properties in the property path) are identified when the page 
is loaded, rather than when the expression is evaluated.\n</div>
+<div tiddler="PropBinding" modifier="HowardLewisShip" modified="200610201450" 
created="200609202203" tags="bindings">The &quot;prop:&quot; binding prefix is 
the default in a  lot of cases, i.e., in any Java code (annotations).\n\nThis 
binding prefix  supports several common idioms even though they are not, 
precisely, the names of properties.  In many cases, this will save developers 
the bother of using a &quot;literal:&quot; prefix.\n\nThe goal of the 
&quot;prop:&quot; prefix is to be highly efficient and useful in 90%+ of the 
cases. [[OGNL]], or synthetic properties in the component class, will pick up 
the remaining cases.\n\n!Numeric literals\n\nSimple numeric literals should be 
parsed into read-only, invariant 
bindings.\n{{{\nprop:5\n\nprop:-22.7\n}}}\n\nThe resulting objects will be of 
type Long or type Double. TypeCoercion will ensure that component parameters 
get values (say, int or float) of the correct type.\n\n!Range 
literals\n\nExpresses a range of integer values, 
 either ascending or descending.\n{{{\nprop:1..10\n\nprop:100..-100\n}}}\n\nThe 
value of such a binding is Iterable; it can be used by the Loop 
component.\n\n!Boolean literals\n\n&quot;true&quot; and &quot;false&quot; 
should also be converted to invariant 
bindings.\n{{{\nprop:true\n\nprop:false\n}}}\n\n!String literals\n\n//Simple// 
string literals, enclosed in single quotes.  Example:\n{{{\nprop:'Hello 
World'\n}}}\n\n//Remember that the binding expression will always be enclosed 
in double quotes.//\n\n!This literal\n\nIn some cases, it is useful to be able 
to identify the current component:\n{{{\nprop:this\n}}}\n\nEven though a 
component is not immutable, the value of //this// does not ever change,\nand 
this binding is also invariant.\n\n!Null literal\n\n{{{\nprop:null\n}}}\n\nThis 
value is always exactly null. This can be used to set a parameter who'se 
default value is non-null to the explicit value null.\n\n!Property 
paths\n\nMulti-step property paths are extremely importa
 nt.\n\n{{{\nprop:poll.title\n\nprop:identity.user.name\n}}}\n\nThe initial 
terms need to be readable, they are never updated. Only the final property name 
must be read/write, and in fact, it is valid to be read-only or 
write-only.\n\nThe prop: binding factory builds a Java expression to read and 
update properties. It does not use reflection at runtime. Therefore, the 
properties of the //declared// type are used. By contrast, [[OGNL]] uses the 
//actual// type, which is reflection-intensive. Also, unlike OGNL, errors (such 
as missing properties in the property path) are identified when the page is 
loaded, rather than when the expression is evaluated.\n</div>
 <div tiddler="RequestTypes" modifier="HowardLewisShip" modified="200610081334" 
created="200610071243" tags="request">There are three broad categories of user 
requests (requests from the client web browser):\n\n* PageRenderRequest -- 
requests to render a specific page, possibly with some configuration\n* 
ComponentActionRequest -- requests that trigger behaivor within a specific 
component\n* ResourceRequest -- requests that access a resource file within the 
classpath\n\nEach of these requests has a specific URI format.</div>
 <div tiddler="SideBarTabs" modifier="HowardLewisShip" modified="200609210652" 
created="200609210651" tags="">&lt;&lt;tabs txtMainTab Timeline Timeline 
TabTimeline All 'All tiddlers' TabAll Tags 'All tags' TabTags More 'More lists' 
TabMore&gt;&gt;\n</div>
 <div tiddler="SiteSubtitle" modifier="HowardLewisShip" modified="200609202249" 
created="200609202155" tags="">\nThe quick and dirty one-stop shopping of 
random ideas for Tapestry 5.</div>

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml?view=diff&rev=466136&r1=466135&r2=466136
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml 
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml 
Fri Oct 20 08:00:38 2006
@@ -6,42 +6,49 @@
 <description>The quick and dirty one-stop shopping of random ideas for 
Tapestry 5.</description>
 <language>en-us</language>
 <copyright>Copyright 2006 HowardLewisShip</copyright>
-<pubDate>Sun, 08 Oct 2006 14:00:49 GMT</pubDate>
-<lastBuildDate>Sun, 08 Oct 2006 14:00:49 GMT</lastBuildDate>
+<pubDate>Fri, 20 Oct 2006 14:50:21 GMT</pubDate>
+<lastBuildDate>Fri, 20 Oct 2006 14:50:21 GMT</lastBuildDate>
 <docs>http://blogs.law.harvard.edu/tech/rss</docs>
 <generator>TiddlyWiki 2.0.11</generator>
 <item>
+<title>PropBinding</title>
+<description>The &quot;prop:&quot; binding prefix is the default in a  lot of 
cases, i.e., in any Java code (annotations).&lt;br /&gt;&lt;br /&gt;This 
binding prefix  supports several common idioms even though they are not, 
precisely, the names of properties.  In many cases, this will save developers 
the bother of using a &quot;literal:&quot; prefix.&lt;br /&gt;&lt;br /&gt;The 
goal of the &quot;prop:&quot; prefix is to be highly efficient and useful in 
90%+ of the cases. [[OGNL]], or synthetic properties in the component class, 
will pick up the remaining cases.&lt;br /&gt;&lt;br /&gt;!Numeric 
literals&lt;br /&gt;&lt;br /&gt;Simple numeric literals should be parsed into 
read-only, invariant bindings.&lt;br /&gt;{{{&lt;br /&gt;prop:5&lt;br 
/&gt;&lt;br /&gt;prop:-22.7&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;The resulting 
objects will be of type Long or type Double. TypeCoercion will ensure that 
component parameters get values (say, int or float) of the correct type.&lt;br 
/&gt;&l
 t;br /&gt;!Range literals&lt;br /&gt;&lt;br /&gt;Expresses a range of integer 
values, either ascending or descending.&lt;br /&gt;{{{&lt;br 
/&gt;prop:1..10&lt;br /&gt;&lt;br /&gt;prop:100..-100&lt;br /&gt;}}}&lt;br 
/&gt;&lt;br /&gt;The value of such a binding is Iterable; it can be used by the 
Loop component.&lt;br /&gt;&lt;br /&gt;!Boolean literals&lt;br /&gt;&lt;br 
/&gt;&quot;true&quot; and &quot;false&quot; should also be converted to 
invariant bindings.&lt;br /&gt;{{{&lt;br /&gt;prop:true&lt;br /&gt;&lt;br 
/&gt;prop:false&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;!String literals&lt;br 
/&gt;&lt;br /&gt;//Simple// string literals, enclosed in single quotes.  
Example:&lt;br /&gt;{{{&lt;br /&gt;prop:'Hello World'&lt;br /&gt;}}}&lt;br 
/&gt;&lt;br /&gt;//Remember that the binding expression will always be enclosed 
in double quotes.//&lt;br /&gt;&lt;br /&gt;!This literal&lt;br /&gt;&lt;br 
/&gt;In some cases, it is useful to be able to identify the current 
component:&lt;br /&gt;{{{&
 lt;br /&gt;prop:this&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;Even though a 
component is not immutable, the value of //this// does not ever change,&lt;br 
/&gt;and this binding is also invariant.&lt;br /&gt;&lt;br /&gt;!Null 
literal&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;prop:null&lt;br /&gt;}}}&lt;br 
/&gt;&lt;br /&gt;This value is always exactly null. This can be used to set a 
parameter who'se default value is non-null to the explicit value null.&lt;br 
/&gt;&lt;br /&gt;!Property paths&lt;br /&gt;&lt;br /&gt;Multi-step property 
paths are extremely important.&lt;br /&gt;&lt;br /&gt;{{{&lt;br 
/&gt;prop:poll.title&lt;br /&gt;&lt;br /&gt;prop:identity.user.name&lt;br 
/&gt;}}}&lt;br /&gt;&lt;br /&gt;The initial terms need to be readable, they are 
never updated. Only the final property name must be read/write, and in fact, it 
is valid to be read-only or write-only.&lt;br /&gt;&lt;br /&gt;The prop: 
binding factory builds a Java expression to read and update properties. It does 
not use r
 eflection at runtime. Therefore, the properties of the //declared// type are 
used. By contrast, [[OGNL]] uses the //actual// type, which is 
reflection-intensive. Also, unlike OGNL, errors (such as missing properties in 
the property path) are identified when the page is loaded, rather than when the 
expression is evaluated.&lt;br /&gt;</description>
+<category>bindings</category>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#PropBinding</link>
+<pubDate>Fri, 20 Oct 2006 14:50:21 GMT</pubDate>
+</item>
+<item>
 <title>ComponentEvent</title>
 <description>Component events represent the way in which incoming requests are 
routed to user-supplied Java methods.&lt;br /&gt;&lt;br /&gt;Component events 
//primarily// originate as a result of a ComponentActionRequest, though certain 
other LifecycleEvents will also originate component events.&lt;br /&gt;&lt;br 
/&gt;Each component event contains:&lt;br /&gt;* An event type; a string that 
identifies the type of event&lt;br /&gt;* An event source; a component that 
orginates the event (where applicable)&lt;br /&gt;* A context; an array of 
strings associated with the event&lt;br /&gt;&lt;br /&gt;Event processing 
starts with the component that originates the event.&lt;br /&gt;&lt;br 
/&gt;Handler methods for the event within the component are invoked.&lt;br 
/&gt;&lt;br /&gt;If no handler method aborts the event, then handlers for the 
originating component's container are invoked.&lt;br /&gt;&lt;br /&gt;This 
containues until handlers for the page (the root component) are invoked,
  or until some handler method aborts the event.&lt;br /&gt;&lt;br /&gt;The 
event is aborted when a handler method returns a non-null, non-void value.  The 
interpretation of that value varies based on the type of event.&lt;br 
/&gt;&lt;br /&gt;Events are routed to handler methods using the @~OnEvent 
annotation.&lt;br /&gt;&lt;br /&gt;This annotation is attached to a method 
within a component class.  This method becomes a handler method for an 
event.&lt;br /&gt;&lt;br /&gt;The annotation allows events to be filtered by 
event type or by originating component.&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;  
@OnEvent(value=&quot;submit&quot;, component=&quot;form&quot;)&lt;br /&gt;  
String handleSubmit()&lt;br /&gt;  {&lt;br /&gt;    // . . .&lt;br /&gt;&lt;br 
/&gt;   return &quot;PostSubmit&quot;;&lt;br /&gt;  }&lt;br /&gt;}}}&lt;br 
/&gt;&lt;br /&gt;In the above hypothetical example, a handler method is 
attached to a particular component's submit event.  After processing the data 
in the 
 form, the LogicalPageName of another page within the application is returned. 
The client browser will be redirected to that page.&lt;br /&gt;&lt;br 
/&gt;Handler methods need not be public; they are most often package private 
(which facilitated UnitTesting of the component class).&lt;br /&gt;&lt;br 
/&gt;Handler methods may take parameters.  This is most useful with handler 
methods related to links, rather than forms.&lt;br /&gt;&lt;br /&gt;Associated 
with each event is the context, a set of strings defined by the application 
programmer.&lt;br /&gt;&lt;br /&gt;Parameters are coerced (see TypeCoercion) 
from these strings.  Alternately, a parameter of type String[] receives the set 
of strings.&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;  
@OnEvent(component=&quot;delete&quot;)&lt;br /&gt;  String deleteAccount(long 
accountId)&lt;br /&gt;  {&lt;br /&gt;    // . . .&lt;br /&gt;&lt;br /&gt;   
return &quot;AccountPage&quot;;&lt;br /&gt;  }&lt;br /&gt;}}}&lt;br /&gt;&lt;br 
/&gt;Here, ther 
 first context value has been coerced to a long and passed to the 
deleteAccount() method. Presemuable, an action link on the page, named 
&quot;delete&quot;, is the source of this event.&lt;br /&gt;&lt;br 
/&gt;</description>
 <category>requests</category>
 <category>events</category>
 
<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#ComponentEvent</link>
-<pubDate>Sun, 08 Oct 2006 13:59:29 GMT</pubDate>
+<pubDate>Sun, 08 Oct 2006 13:59:00 GMT</pubDate>
 </item>
 <item>
 <title>ComponentActionRequest</title>
 <description>Component actions are actions that reflect user interaction with 
a component within a page. Again, this falls into several broad 
categories:&lt;br /&gt;&lt;br /&gt;* Links that perform a server-side action, 
and result in a page refresh, or a new page being displayed.&lt;br /&gt;* Ajax 
style links, which perform a server-side action, and refresh only part of the 
page.&lt;br /&gt;* Forms which perform a server-side action, followed by a page 
refresh (or new page being displayed).&lt;br /&gt;* Ajax style forms, which 
trigger an action, followed by a refresh of part of the page.&lt;br /&gt;* 
Other user interactions, which result in a server side action, and a partial 
page refresh.&lt;br /&gt;&lt;br /&gt;In all of these cases, one or more 
ComponentEvents is fired. The result of ComponentEvent determines whether a 
partial page render or a full page render occurs.&lt;br /&gt;&lt;br /&gt;In the 
later case, a client side redirect is sent, to force the browser to initial 
 a new PageRenderRequest.  This addresses an issue in Tapestry 4, in that 
following a link or form submission, the URL would indicate details about the 
previous page, not the newly displayed page, and clicking the browser refresh 
button could cause a server side operation to occur again (which would often be 
quite undersirable).&lt;br /&gt;&lt;br /&gt;!URI Format&lt;br /&gt;&lt;br 
/&gt;{{{&lt;br /&gt;/page-name.event-type/component-id-path/id&lt;br 
/&gt;}}}&lt;br /&gt;&lt;br /&gt;Here page-name is the LogicalPageName.  The 
event-type is a string that identifies the type of event (and will ultimately 
be used to select an event handler method).  &lt;br /&gt;&lt;br /&gt;The 
component-id-path is a dot-separated series of component ids, used to identify 
a specific component within the overall page.&lt;br /&gt;&lt;br /&gt;The id is 
optional, and may be repeated. The id value or values will be provided to the 
event handler method.&lt;br /&gt;&lt;br /&gt;Example: /Login.submit/form  
 (the URI for a form component on page Login).&lt;br /&gt;&lt;br /&gt;Example: 
/admin/UserProfile/action/menu.delete/37  (component menu.delete of the 
UserProfile page, with an id of 37).&lt;br /&gt;</description>
 
<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#ComponentActionRequest</link>
-<pubDate>Sun, 08 Oct 2006 13:35:14 GMT</pubDate>
+<pubDate>Sun, 08 Oct 2006 13:35:00 GMT</pubDate>
 </item>
 <item>
 <title>RequestTypes</title>
 <description>There are three broad categories of user requests (requests from 
the client web browser):&lt;br /&gt;&lt;br /&gt;* PageRenderRequest -- requests 
to render a specific page, possibly with some configuration&lt;br /&gt;* 
ComponentActionRequest -- requests that trigger behaivor within a specific 
component&lt;br /&gt;* ResourceRequest -- requests that access a resource file 
within the classpath&lt;br /&gt;&lt;br /&gt;Each of these requests has a 
specific URI format.</description>
 <category>request</category>
 <link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#RequestTypes</link>
-<pubDate>Sun, 08 Oct 2006 13:34:49 GMT</pubDate>
+<pubDate>Sun, 08 Oct 2006 13:34:00 GMT</pubDate>
 </item>
 <item>
 <title>PageRenderRequest</title>
 <description>Page render requests are requests used to render a specific page. 
 //render// is the term meaning to compose the HTML response to be sent to the 
client. Note: HTML is used here only as the most common case, other markups are 
entirely possible.&lt;br /&gt;&lt;br /&gt;In many cases, pages are stand-alone. 
 No extra information in the URL is necesarry to render them.  
PersistentProperties of the page will factor in to the rendering of the 
page.&lt;br /&gt;&lt;br /&gt;In specific cases, a page needs to render within a 
particular context. The most common example of this is a page that is used to 
present a specific instance of a database persistent entity. In such a case, 
the page must be combined with additional data, in the URL, to identify the 
specific entity to access and render.&lt;br /&gt;&lt;br /&gt;! URI Format&lt;br 
/&gt;&lt;br /&gt;{{{&lt;br /&gt;/page-name.html/id&lt;br /&gt;}}}&lt;br 
/&gt;&lt;br /&gt;Here &quot;page-name&quot; is the LogicalPageName for th
 e page. &lt;br /&gt;&lt;br /&gt;The &quot;.html&quot; file extension is used 
as a delimiter between the page name portion of the URI, and the context 
portion of the URI. This is necessary because it is not possible (given the 
plethora of libraries and folders) to determine how many slashes will appear in 
the URI.&lt;br /&gt;&lt;br /&gt;The context consists of one ore more ids 
(though a single id is the normal case). The id is used to identify the 
specific data to be displayed. Further, a page may require multiple ids, which 
will separated with slashes. Example: 
/admin/DisplayDetail.html/loginfailures/2006&lt;br /&gt;&lt;br /&gt;Note that 
these context values, the ids, are simply //strings//. Tapestry 4 had a 
mechanism, the DataSqueezer, that would encode the type of object with its 
value, as a single string, and convert it back. While seemingly desirable, this 
facility was easy to abuse, resulting in long and extremely ugly URIs.&lt;br 
/&gt;&lt;br /&gt;Any further informatio
 n needed by Tapestry will be added to the URI as query parameters. This may 
include things like user locale, persistent page properties, applicaition flow 
identifiers, or anything else we come up with.&lt;br /&gt;&lt;br /&gt;! Request 
Processing&lt;br /&gt;&lt;br /&gt;Once the page and id parameters are 
identified, the corresponding page will be loaded.&lt;br /&gt;&lt;br 
/&gt;Tapestry will fire two events before rendering the page.&lt;br /&gt;&lt;br 
/&gt;The first event is of type &quot;setupPageRender&quot;.  This allows the 
page to process the context (the set of ids). This typically involves reading 
objects from an external persistent store (a database)&lt;br /&gt;and storing 
those objects into transient page properties, in expectaion of the 
render.&lt;br /&gt;&lt;br /&gt;The @SetupPageRender annotation marks a method 
to be invoked when this event is triggered.  The method may take one or more 
strings, or an array of strings, as parameters; these will be&lt;br /&gt;the co
 ntext values.  The method will normally return void.  Other values are 
''TBD''. It may also take other simple types, which will be coerced from the 
string values.&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;@SetupPageRender&lt;br 
/&gt;void setup(long id)&lt;br /&gt;{&lt;br /&gt;  . . .&lt;br /&gt;}&lt;br 
/&gt;}}}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The second event is of 
type &quot;pageValidate&quot;.  It allows the page to decide whether the page 
is valid for rendering at this time. This most often involves a check to see if 
the user is logged into the application, and has the necessary privileges to 
display the contents of the page.  User identity and privileges are //not// 
concepts built into Tapestry, but are fundamental to the majority of Tapestry 
applications.</description>
 
<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#PageRenderRequest</link>
-<pubDate>Sun, 08 Oct 2006 13:33:32 GMT</pubDate>
+<pubDate>Sun, 08 Oct 2006 13:33:00 GMT</pubDate>
 </item>
 <item>
 <title>LogicalPageName</title>
 <description>A logical page name is the name of a page as it is represented in 
a URI.&lt;br /&gt;&lt;br /&gt;Internally, Tapestry operates on pages using full 
qualified class names. Technically, the FQCN is the class of the page's root 
element, but from an end developer point of view, the root element is the 
page.&lt;br /&gt;&lt;br /&gt;The logical page name must be converted to a fully 
qualified class name.&lt;br /&gt;&lt;br /&gt;A set of LibraryMappings are used. 
 Each library mapping is used to express a folder name, such as 
&quot;core&quot;, with a Java package name, such as 
org.apache.tapestry.corelib.  For pages, the page name is searched for in the 
pages sub-package (i.e., org.apache.tapestry.corelib.pages).  Component 
libraries have unique folder names mapped to root packages that contain the 
pages (and components, and mixins) of that library.&lt;br /&gt;&lt;br /&gt;When 
there is no folder name, the page is expected to be part of the application, 
under the pages sub-
 package of the application's root package.&lt;br /&gt;&lt;br /&gt;If not found 
there, as a special case, the name is treated as if it were prefixed with 
&quot;core/&quot;.  This allows access to the core pages (and more importantly, 
components -- the search algorithm is the same).&lt;br /&gt;&lt;br 
/&gt;Finally, pages may be organized into folders.  These folders become 
further sub-packages. Thus as page name of &quot;admin/EditUsers&quot; may be 
resolved to class org.example.myapp.pages.admin.EditUsers.&lt;br /&gt;&lt;br 
/&gt;</description>
 
<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#LogicalPageName</link>
-<pubDate>Sun, 08 Oct 2006 13:30:28 GMT</pubDate>
+<pubDate>Sun, 08 Oct 2006 13:30:00 GMT</pubDate>
 </item>
 <item>
 <title>OGNL</title>
@@ -50,13 +57,6 @@
 <pubDate>Sat, 07 Oct 2006 12:49:00 GMT</pubDate>
 </item>
 <item>
-<title>PropBinding</title>
-<description>The &quot;prop:&quot; binding prefix is the default in a  lot of 
cases, i.e., in any Java code (annotations).&lt;br /&gt;&lt;br /&gt;This 
binding prefix  supports several common idioms even though they are not, 
precisely, the names of properties.  In many cases, this will save developers 
the bother of using a &quot;literal:&quot; prefix.&lt;br /&gt;&lt;br /&gt;The 
goal of the &quot;prop:&quot; prefix is to be highly efficient and useful in 
90%+ of the cases. [[OGNL]], or synthetic properties in the component class, 
will pick up the remaining cases.&lt;br /&gt;&lt;br /&gt;!Numeric 
literals&lt;br /&gt;&lt;br /&gt;Simple numeric literals should be parsed into 
read-only, invariant bindings.&lt;br /&gt;{{{&lt;br /&gt;prop:5&lt;br 
/&gt;&lt;br /&gt;prop:-22.7&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;&lt;br 
/&gt;The resulting objects will be of type Long or type Double. TypeCoercion 
will ensure that component parameters get values (say, int or float) of the 
correct type.&l
 t;br /&gt;&lt;br /&gt;!Boolean literals&lt;br /&gt;&lt;br 
/&gt;&quot;true&quot; and &quot;false&quot; should also be converted to 
invariant bindings.&lt;br /&gt;{{{&lt;br /&gt;prop:true&lt;br /&gt;&lt;br 
/&gt;prop:false&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;!String literals&lt;br 
/&gt;&lt;br /&gt;//Simple// string literals, enclosed in single quotes.  
Example:&lt;br /&gt;{{{&lt;br /&gt;prop:'Hello World'&lt;br /&gt;}}}&lt;br 
/&gt;&lt;br /&gt;//Remember that the binding expression will always be enclosed 
in double quotes.//&lt;br /&gt;&lt;br /&gt;!This literal&lt;br /&gt;&lt;br 
/&gt;In some cases, it is useful to be able to identify the current 
component:&lt;br /&gt;{{{&lt;br /&gt;prop:this&lt;br /&gt;}}}&lt;br /&gt;&lt;br 
/&gt;Even though a component is not immutable, the value of //this// does not 
ever change,&lt;br /&gt;and this binding is also invariant.&lt;br /&gt;&lt;br 
/&gt;!Null literal&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;prop:null&lt;br 
/&gt;}}}&lt;br /&gt;&lt;br /
 &gt;This value is always exactly null. This can be used to set a parameter 
who'se default value is non-null to the explicit value null.&lt;br /&gt;&lt;br 
/&gt;!Property paths&lt;br /&gt;&lt;br /&gt;Multi-step property paths are 
extremely important.&lt;br /&gt;&lt;br /&gt;{{{&lt;br 
/&gt;prop:poll.title&lt;br /&gt;&lt;br /&gt;prop:identity.user.name&lt;br 
/&gt;}}}&lt;br /&gt;&lt;br /&gt;The initial terms need to be readable, they are 
never updated. Only the final property name must be read/write, and in fact, it 
is valid to be read-only or write-only.&lt;br /&gt;&lt;br /&gt;The prop: 
binding factory builds a Java expression to read and update properties. It does 
not use reflection at runtime. Therefore, the properties of the //declared// 
type are used. By contrast, [[OGNL]] uses the //actual// type, which is 
reflection-intensive. Also, unlike OGNL, errors (such as missing properties in 
the property path) are identified when the page is loaded, rather than when the 
expression i
 s evaluated.&lt;br /&gt;</description>
-<category>bindings</category>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#PropBinding</link>
-<pubDate>Sat, 07 Oct 2006 12:47:00 GMT</pubDate>
-</item>
-<item>
 <title>MasterIndex</title>
 <description>Top level concepts within Tapestry 5.&lt;br /&gt;&lt;br /&gt;* 
PropBinding -- Notes on the workhorse &quot;prop:&quot; binding prefix&lt;br 
/&gt;* TypeCoercion -- How Tapestry 5 extensibly addresses type 
conversion&lt;br /&gt;* FormProcessing&lt;br /&gt;* DynamicPageState -- 
tracking changes to page state during the render&lt;br /&gt;* 
EnvironmentalServices -- how components cooperate during page render&lt;br 
/&gt;* ComponentMixins -- A new fundamental way to build web 
functionality&lt;br /&gt;* RequestTypes -- Requests, request processing, URL 
formats</description>
 <link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#MasterIndex</link>
@@ -127,15 +127,15 @@
 <pubDate>Thu, 21 Sep 2006 06:49:00 GMT</pubDate>
 </item>
 <item>
-<title>SiteSubtitle</title>
-<description>&lt;br /&gt;The quick and dirty one-stop shopping of random ideas 
for Tapestry 5.</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#SiteSubtitle</link>
-<pubDate>Wed, 20 Sep 2006 22:49:00 GMT</pubDate>
-</item>
-<item>
 <title>SiteTitle</title>
 <description>Tapestry 5 Brain Dump</description>
 <link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#SiteTitle</link>
+<pubDate>Wed, 20 Sep 2006 22:49:00 GMT</pubDate>
+</item>
+<item>
+<title>SiteSubtitle</title>
+<description>&lt;br /&gt;The quick and dirty one-stop shopping of random ideas 
for Tapestry 5.</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#SiteSubtitle</link>
 <pubDate>Wed, 20 Sep 2006 22:49:00 GMT</pubDate>
 </item>
 </channel>

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Count.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Count.java?view=diff&rev=466136&r1=466135&r2=466136
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Count.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Count.java
 Fri Oct 20 08:00:38 2006
@@ -18,12 +18,14 @@
 import org.apache.tapestry.annotations.ComponentClass;
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.annotations.SetupRender;
+import org.apache.tapestry.util.IntegerRange;
 
 /**
  * A component that can count up or count down.
- * 
- * 
- */ 
+ * <p>
+ * This is useful as a demonstration; now that the prop binding supports
+ * [EMAIL PROTECTED] IntegerRange integer ranges}, it's much less necessary.
+ */
 @ComponentClass
 public class Count
 {

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java?view=diff&rev=466136&r1=466135&r2=466136
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
 Fri Oct 20 08:00:38 2006
@@ -26,14 +26,12 @@
 import org.apache.tapestry.ioc.services.PropertyAccess;
 import org.apache.tapestry.runtime.ComponentLifecycle;
 import org.apache.tapestry.services.BindingFactory;
+import org.apache.tapestry.util.IntegerRange;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
-/**
- * 
- */
 public class PropBindingFactoryTest extends InternalBaseTestCase
 {
     private static final String BEAN_CLASS = TargetBean.class.getName();
@@ -398,6 +396,8 @@
         { " 5.", 5d },
         { " -100.", -100d },
         { " -0.0 ", -0d },
+        { "1..10", new IntegerRange(1, 10) },
+        { " -20 .. -30 ", new IntegerRange(-20, -30) },
         { "0.", 0d },
         { " 227.75", 227.75d },
         { " -10123.67", -10123.67d },

Added: 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IntegerRangeTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IntegerRangeTest.java?view=auto&rev=466136
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IntegerRangeTest.java
 (added)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IntegerRangeTest.java
 Fri Oct 20 08:00:38 2006
@@ -0,0 +1,116 @@
+// Copyright 2006 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.tapestry.util;
+
+import java.util.Iterator;
+
+import org.apache.tapestry.test.BaseTestCase;
+import org.apache.tapestry.util.IntegerRange;
+import org.testng.annotations.Test;
+
+public class IntegerRangeTest extends BaseTestCase
+{
+    @Test
+    public void start_less_than_finish()
+    {
+        IntegerRange r = new IntegerRange(1, 3);
+
+        assertEquals(r.toString(), "1..3");
+
+        assertEquals(r.getStart(), 1);
+        assertEquals(r.getFinish(), 3);
+
+        Iterator<Integer> i = r.iterator();
+
+        assertEquals(i.next().intValue(), 1);
+        assertEquals(i.next().intValue(), 2);
+
+        assertTrue(i.hasNext());
+
+        assertEquals(i.next().intValue(), 3);
+
+        assertFalse(i.hasNext());
+
+        try
+        {
+            i.next();
+            unreachable();
+        }
+        catch (IllegalStateException ex)
+        {
+        }
+    }
+
+    @Test
+    public void start_same_as_finish()
+    {
+        IntegerRange r = new IntegerRange(3, 3);
+
+        Iterator<Integer> i = r.iterator();
+
+        assertTrue(i.hasNext());
+
+        assertEquals(i.next().intValue(), 3);
+
+        assertFalse(i.hasNext());
+    }
+
+    @Test
+    public void finish_less_than_start()
+    {
+        IntegerRange r = new IntegerRange(3, 1);
+
+        assertEquals(r.toString(), "3..1");
+
+        Iterator<Integer> i = r.iterator();
+
+        assertEquals(i.next().intValue(), 3);
+        assertEquals(i.next().intValue(), 2);
+
+        assertTrue(i.hasNext());
+
+        assertEquals(i.next().intValue(), 1);
+
+        assertFalse(i.hasNext());
+
+        try
+        {
+            i.next();
+            unreachable();
+        }
+        catch (IllegalStateException ex)
+        {
+        }
+    }
+
+    @Test
+    public void hash_code_and_equals()
+    {
+        IntegerRange r1 = new IntegerRange(1, 100);
+        IntegerRange r2 = new IntegerRange(1, 100);
+        IntegerRange r3 = new IntegerRange(1, 10);
+
+        assertEquals(r1.hashCode(), r2.hashCode());
+        assertFalse(r1.hashCode() == r3.hashCode());
+
+        assertTrue(r1.equals(r1));
+        assertEquals(r1, r2);
+
+        assertFalse(r1.equals(r3));
+        assertFalse(r1.equals(this));
+        assertFalse(r1.equals(null));
+        assertFalse(r1.equals(new IntegerRange(3, 30)));
+    }
+}

Modified: 
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html?view=diff&rev=466136&r1=466135&r2=466136
==============================================================================
--- 
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html
 (original)
+++ 
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html
 Fri Oct 20 08:00:38 2006
@@ -1,5 +1,4 @@
 <t:comp type="Border" 
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
-    <p> The Loop component demonstrates reading and writing of properties with 
the prop: binding prefix.</p>
-    <p> Merry Christmas: <t:comp type="Count" end="3"> Ho! </t:comp>
+    <p> Merry Christmas: <t:comp type="Loop" source="prop:1..3"> Ho! </t:comp>
     </p>
 </t:comp>


Reply via email to