<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>docs/draft-gregorio-uritemplate-03.txt</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,7 @@
+=== 0.3.0 / 2008-12-08
+
+* Implemented version 0.3 (http://bitworking.org/projects/URI-Templates/spec/draft-gregorio-uritemplate-03.txt)
+
 === 0.2.0 / 2008-3-18
 * Changed lib directory structure to reflect the name of the gem.
   use &quot;require 'uri/templates'&quot; instead of &quot;require 'uri_template'&quot;</diff>
      <filename>History.txt</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,10 @@
 = URI-Templates
 http://rubyforge.org/projects/uri-templates/
 
+This release implements version 0.3 of the URI Template specification.
+
+See: http://bitworking.org/projects/URI-Templates/spec/draft-gregorio-uritemplate-03.txt
+
 == DESCRIPTION:
 
 URI Templates are strings that contain embedded variables that are transformed into URIs after embedded variables are substituted. </diff>
      <filename>README.txt</filename>
    </modified>
    <modified>
      <diff>@@ -93,8 +93,8 @@ grammar UriTemplate
       end
     } 
     / 
-    'append' {
-     # The append operator MUST only have one variable in its expansion.  If
+    'suffix' {
+     # The suffix operator MUST only have one variable in its expansion.  If
      # the variable is defined and non-empty then substitute the value of
      # the variable followed by the value of arg, otherwise substitute the
      # empty string.
@@ -136,15 +136,12 @@ grammar UriTemplate
      end
    }
     / 
-    'listjoin' {
-     # The listjoin operator MUST have only one variable in its expansion
-     # and that variable must be a list.  If the list is non-empty then
-     # substitute the concatenation of all the list members with intevening
-     # values of arg.
-      #
-     # The result of substitution MUST match the URI-reference rule and
-     # SHOULD also match any known rules for the scheme of the resulting
-     # URI.
+    'list' {
+    # 	The listjoin operator MUST have only one variable in its expansion
+    # and that variable must be a list.  More than one variable is an
+    # error.  If the list is non-empty then substitute the concatenation of
+    # all the list members with intervening values of arg.  If the list is
+    # empty or the variable is undefined them substitute the empty string.
      def exec
        lambda do |env, joinop, vars|
          return &quot;&quot; unless env[vars].respond_to? :each</diff>
      <filename>grammar/uri_template.treetop</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,10 @@
 module UriTemplate
   include Treetop::Runtime
 
+  def initialize
+    @root = nil
+  end
+
   def root
     @root || :uri_template
   end
@@ -291,7 +295,7 @@ module UriTemplate
   end
 
   module Op3
-    # The append operator MUST only have one variable in its expansion.  If
+    # The suffix operator MUST only have one variable in its expansion.  If
     # the variable is defined and non-empty then substitute the value of
     # the variable followed by the value of arg, otherwise substitute the
     # empty string.
@@ -334,22 +338,19 @@ module UriTemplate
   end
 
   module Op5
-    # The listjoin operator MUST have only one variable in its expansion
-    # and that variable must be a list.  If the list is non-empty then
-    # substitute the concatenation of all the list members with intevening
-    # values of arg.
-     #
-    # The result of substitution MUST match the URI-reference rule and
-    # SHOULD also match any known rules for the scheme of the resulting
-    # URI.
-    def exec
-      lambda do |env, joinop, vars|
-        return &quot;&quot; unless env[vars].respond_to? :each
-        env[vars].map do |v|
-          &quot;#{UriTemplate::Encoder.encode(v)}&quot; if v
-        end.compact.join(joinop)
-      end
-    end
+    # 	The listjoin operator MUST have only one variable in its expansion
+    # and that variable must be a list.  More than one variable is an
+    # error.  If the list is non-empty then substitute the concatenation of
+    # all the list members with intervening values of arg.  If the list is
+    # empty or the variable is undefined them substitute the empty string.
+     def exec
+       lambda do |env, joinop, vars|
+         return &quot;&quot; unless env[vars].respond_to? :each
+         env[vars].map do |v|
+           &quot;#{UriTemplate::Encoder.encode(v)}&quot; if v
+         end.compact.join(joinop)
+       end
+     end
   end
 
   def _nt_op
@@ -394,12 +395,12 @@ module UriTemplate
         if r3
           r0 = r3
         else
-          if input.index('append', index) == index
+          if input.index('suffix', index) == index
             r4 = (SyntaxNode).new(input, index...(index + 6))
             r4.extend(Op3)
             @index += 6
           else
-            terminal_parse_failure('append')
+            terminal_parse_failure('suffix')
             r4 = nil
           end
           if r4
@@ -416,12 +417,12 @@ module UriTemplate
             if r5
               r0 = r5
             else
-              if input.index('listjoin', index) == index
-                r6 = (SyntaxNode).new(input, index...(index + 8))
+              if input.index('list', index) == index
+                r6 = (SyntaxNode).new(input, index...(index + 4))
                 r6.extend(Op5)
-                @index += 8
+                @index += 4
               else
-                terminal_parse_failure('listjoin')
+                terminal_parse_failure('list')
                 r6 = nil
               end
               if r6</diff>
      <filename>lib/uri/grammar.rb</filename>
    </modified>
    <modified>
      <diff>@@ -20,7 +20,10 @@
 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #++
+
+#$KCODE='u'
 require 'rubygems'
+#require 'unicode'
 require 'treetop'
 require 'cgi'
 </diff>
      <filename>lib/uri/templates.rb</filename>
    </modified>
    <modified>
      <diff>@@ -7,3 +7,17 @@ FIXTURES = File.dirname(__FILE__) + &quot;/fixtures&quot;
 #def read_fixture(f)
 #  File.read(File.join(FIXTURES, f))
 #end
+
+module Unicode
+  def self.const_missing(name)  
+    # Check that the constant name is of the right form: U0000 to U10FFFF
+    if name.to_s =~ /^U([0-9a-fA-F]{4,5}|10[0-9a-fA-F]{4})$/
+      # Convert the codepoint to an immutable UTF-8 string,
+      # define a real constant for that value and return the value
+      #p name, name.class
+      const_set(name, [$1.dup.to_i(16)].pack(&quot;U&quot;).freeze)
+    else  # Raise an error for constants that are not Unicode.
+      raise NameError, &quot;Uninitialized constant: Unicode::#{name}&quot;
+    end
+  end
+end
\ No newline at end of file</diff>
      <filename>test/test_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,6 +6,8 @@ class TestUriTemplate &lt; Test::Unit::TestCase
   def test_encode
     assert_equal &quot;stefan&quot;, UriTemplate::Encoder.encode(&quot;stefan&quot;)
     assert_equal '%26', UriTemplate::Encoder.encode(&quot;&amp;&quot;)
+    assert_equal '%20', UriTemplate::Encoder.encode(&quot; &quot;)
+    #assert_equal '%CE%8E', UriTemplate::Encoder.encode(Unicode::U03d3)
   end
   
   def test_op
@@ -21,7 +23,7 @@ class TestUriTemplate &lt; Test::Unit::TestCase
       'a_b' =&gt; 'baz'
     }
     assert_equal '/&amp;wilma/#bar', UriTemplate::URI.new('/{-prefix|&amp;|foo=wilma}/{-prefix|#|b}').replace(defaults)
-    assert_equal '/foo/data#bar', UriTemplate::URI.new('/{-append|/|a}{-opt|data|points}{-neg|@|a}{-prefix|#|b}').replace(defaults)
+    assert_equal '/foo/data#bar', UriTemplate::URI.new('/{-suffix|/|a}{-opt|data|points}{-neg|@|a}{-prefix|#|b}').replace(defaults)
   end
   
   def test_replace</diff>
      <filename>test/test_uri_template.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 #  Created by Stefan Saasen.
 #  Copyright (c) 2008. All rights reserved.
 require File.dirname(__FILE__) + '/test_helper.rb'
- 
+
 class TestUriTemplateGrammar &lt; Test::Unit::TestCase
   
   def check(expected, template, values = {})
@@ -21,7 +21,7 @@ class TestUriTemplateGrammar &lt; Test::Unit::TestCase
     assert_not_nil @parser.parse('http://www.google.com/notebook/feeds/{userID}')
     assert_not_nil @parser.parse('http://www.google.com/notebook/feeds/{-prefix|/notebooks/|notebookID}')
     assert_not_nil @parser.parse('http://www.google.com/notebook/feeds/{userID}{-prefix|/notebooks/|notebookID}')
-    assert_not_nil @parser.parse('http://www.google.com/notebook/feeds/{userID}{-prefix|/notebooks/|notebookID}{-opt|/-/|categories}{-listjoin|/|categories}?{-join|&amp;|updated-min,updated-max,alt,start-index,max-results,entryID,orderby}')
+    assert_not_nil @parser.parse('http://www.google.com/notebook/feeds/{userID}{-prefix|/notebooks/|notebookID}{-opt|/-/|categories}{-list|/|categories}?{-join|&amp;|updated-min,updated-max,alt,start-index,max-results,entryID,orderby}')
   end
   
   def test_replace
@@ -36,19 +36,19 @@ class TestUriTemplateGrammar &lt; Test::Unit::TestCase
     check &quot;barney&quot;, &quot;foo=wilma&quot;, &quot;foo&quot; =&gt; &quot;barney&quot;
   end
   
-  def test_append
-    check &quot;&quot;, &quot;-append|/|foo&quot;
-    check &quot;wilma#&quot;, &quot;-append|#|foo=wilma&quot;
-    check &quot;barney&amp;?&quot;, &quot;-append|&amp;?|foo=wilma&quot;, &quot;foo&quot; =&gt;  &quot;barney&quot;
+  def test_suffix
+    check &quot;&quot;, &quot;-suffix|/|foo&quot;
+    check &quot;wilma#&quot;, &quot;-suffix|#|foo=wilma&quot;
+    check &quot;barney&amp;?&quot;, &quot;-suffix|&amp;?|foo=wilma&quot;, &quot;foo&quot; =&gt;  &quot;barney&quot;
   end
   
-  def test_listjoin
-    check &quot;a&amp;b&amp;c&quot;, &quot;-listjoin|&amp;|bar&quot;, 'bar' =&gt; ['a', 'b', 'c']
-    check &quot;&quot;, &quot;-listjoin|/|foo&quot;
-    check &quot;a/b&quot;, &quot;-listjoin|/|foo&quot;, &quot;foo&quot; =&gt; ['a', 'b']
-    check &quot;ab&quot;, &quot;-listjoin||foo&quot;, &quot;foo&quot; =&gt; ['a', 'b']
-    check &quot;a&quot;, &quot;-listjoin|/|foo&quot;, &quot;foo&quot; =&gt; ['a']
-    check &quot;&quot;, &quot;-listjoin|/|foo&quot;, &quot;foo&quot; =&gt; []
+  def test_list
+    check &quot;a&amp;b&amp;c&quot;, &quot;-list|&amp;|bar&quot;, 'bar' =&gt; ['a', 'b', 'c']
+    check &quot;&quot;, &quot;-list|/|foo&quot;
+    check &quot;a/b&quot;, &quot;-list|/|foo&quot;, &quot;foo&quot; =&gt; ['a', 'b']
+    check &quot;ab&quot;, &quot;-list||foo&quot;, &quot;foo&quot; =&gt; ['a', 'b']
+    check &quot;a&quot;, &quot;-list|/|foo&quot;, &quot;foo&quot; =&gt; ['a']
+    check &quot;&quot;, &quot;-list|/|foo&quot;, &quot;foo&quot; =&gt; []
   end
   
   def test_join
@@ -91,11 +91,11 @@ class TestUriTemplateGrammar &lt; Test::Unit::TestCase
   
   def test_special
     check &quot;%20&quot;, &quot;foo&quot;, &quot;foo&quot; =&gt; ' '
-    check '%26&amp;%26&amp;%7C&amp;_', &quot;-listjoin|&amp;|foo&quot;, 'foo' =&gt; [&quot;&amp;&quot;, &quot;&amp;&quot;, &quot;|&quot;, &quot;_&quot;]
+    check '%26&amp;%26&amp;%7C&amp;_', &quot;-list|&amp;|foo&quot;, 'foo' =&gt; [&quot;&amp;&quot;, &quot;&amp;&quot;, &quot;|&quot;, &quot;_&quot;]
   end
   
   def test_misc
-    assert_equal &quot;http://www.google.com/notebook/feeds/joe?&quot;,  @parser.parse(&quot;http://www.google.com/notebook/feeds/{userID}{-prefix|/notebooks/|notebookID}{-opt|/-/|categories}{-listjoin|/|categories}?{-join|&amp;|updated-min,updated-max,alt,start-index,max-results,entryID,orderby}&quot;).value(&quot;userID&quot; =&gt; &quot;joe&quot;)
+    assert_equal &quot;http://www.google.com/notebook/feeds/joe?&quot;,  @parser.parse(&quot;http://www.google.com/notebook/feeds/{userID}{-prefix|/notebooks/|notebookID}{-opt|/-/|categories}{-list|/|categories}?{-join|&amp;|updated-min,updated-max,alt,start-index,max-results,entryID,orderby}&quot;).value(&quot;userID&quot; =&gt; &quot;joe&quot;)
     assert_equal &quot;http://example.org/news/joe/&quot;, @parser.parse(&quot;http://example.org/news/{id}/&quot;).value(&quot;id&quot; =&gt; &quot;joe&quot;)
   end
   
@@ -117,7 +117,7 @@ class TestUriTemplateGrammar &lt; Test::Unit::TestCase
   # string, and both list0 and points are lists.  The variable 'u' is a
   # string of two unicode characters, the WHITE CHESS KING (0x2654) and
   # the WHITE CHESS QUEEN (0x2655).
-  def test_draft
+  def test_draft_0_2
     defaults = {
       'a' =&gt; 'foo',
       'b' =&gt; 'bar',
@@ -126,7 +126,8 @@ class TestUriTemplateGrammar &lt; Test::Unit::TestCase
       'list0' =&gt; [],
       'str0' =&gt; '',
       'reserved' =&gt; ':/?#[]@!$&amp;\'()*+,;=',
-      'u' =&gt; '&#9812;&#9813;',
+      #'u' =&gt; '&#9812;&#9813;',
+      'u' =&gt; &quot;#{Unicode::U2654}#{Unicode::U2655}&quot;,
       'a_b' =&gt; 'baz'
     }
     assert_equal 'http://example.org/?q=foo', @parser.parse('http://example.org/?q={a}').value(defaults)
@@ -144,13 +145,13 @@ class TestUriTemplateGrammar &lt; Test::Unit::TestCase
     assert_equal './', @parser.parse('./{-prefix|#|str0}').value(defaults)
     
     # append, prefix
-    assert_equal '/foo/#bar', @parser.parse('/{-append|/|a}{-prefix|#|b}').value(defaults)
+    assert_equal '/foo/#bar', @parser.parse('/{-suffix|/|a}{-prefix|#|b}').value(defaults)
     
     # neg
     assert_equal '/', @parser.parse('/{-neg|@|a}').value(defaults)
     
     # append, opt, neg, prefix
-    assert_equal '/foo/data#bar', @parser.parse('/{-append|/|a}{-opt|data|points}{-neg|@|a}{-prefix|#|b}').value(defaults)
+    assert_equal '/foo/data#bar', @parser.parse('/{-suffix|/|a}{-opt|data|points}{-neg|@|a}{-prefix|#|b}').value(defaults)
     
     # UTF-8
     assert_equal 'http://example.org/q=%E2%99%94%E2%99%95/', @parser.parse('http://example.org/q={u}/').value(defaults)
@@ -158,12 +159,59 @@ class TestUriTemplateGrammar &lt; Test::Unit::TestCase
     # join
     assert_equal 'http://example.org/?a=foo&amp;data=10%2C20%2C30', @parser.parse('http://example.org/?{-join|&amp;|a,data}').value(defaults)
     
-    # listjoin
-    assert_equal 'http://example.org/?d=10,20,30&amp;a=foo&amp;b=bar', @parser.parse('http://example.org/?d={-listjoin|,|points}&amp;{-join|&amp;|a,b}').value(defaults)    
-    assert_equal 'http://example.org/?d=&amp;', @parser.parse('http://example.org/?d={-listjoin|,|list0}&amp;{-join|&amp;|foo}').value(defaults)
+    # list
+    assert_equal 'http://example.org/?d=10,20,30&amp;a=foo&amp;b=bar', @parser.parse('http://example.org/?d={-list|,|points}&amp;{-join|&amp;|a,b}').value(defaults)    
+    assert_equal 'http://example.org/?d=&amp;', @parser.parse('http://example.org/?d={-list|,|list0}&amp;{-join|&amp;|foo}').value(defaults)
     
     # misc
     assert_equal 'http://example.org/foobar/baz', @parser.parse('http://example.org/{a}{b}/{a_b}').value(defaults)
     assert_equal 'http://example.org/foo/-/foo/', @parser.parse('http://example.org/{a}{-prefix|/-/|a}/').value(defaults)
   end
+  
+  # +---------+----------------------------------+
+  # | Name    | Value                            |
+  # +---------+----------------------------------+
+  # | foo     | \u03d3                           |
+  # | bar     | fred                             |
+  # | baz     | 10,20,30                         |
+  # | qux     | [&quot;10&quot;,&quot;20&quot;,&quot;30&quot;]                 |
+  # | corge   | []                               |
+  # | grault  |                                  |
+  # | garply  | a/b/c                            |
+  # | waldo   | ben &amp; jerrys                     |
+  # | fred    | [&quot;fred&quot;, &quot;&quot;, &quot;wilma&quot;]            |
+  # | plugh   | [&quot;\u017F\u0307&quot;, &quot;\u0073\u0307&quot;] |
+  # | 1-a_b.c | 200                              |
+  # +---------+----------------------------------+  
+  def test_draft_0_3
+    defaults = {
+      'foo' =&gt; Unicode::U03d3,
+      'bar' =&gt; 'fred',
+      'baz' =&gt; '10,20,30',
+      'qux' =&gt; %w(10 20 30),
+      'corge' =&gt; [],
+      'grault' =&gt; nil,
+      'garply' =&gt; 'a/b/c',
+      'waldo' =&gt; 'ben &amp; jerrys',
+      'fred' =&gt; [&quot;fred&quot;, &quot;&quot;, &quot;wilma&quot;],
+      'plugh' =&gt; [&quot;#{Unicode::U017F}#{Unicode::U0307}&quot;, &quot;#{Unicode::U0073}#{Unicode::U0307}&quot;],
+      '1-a_b.c' =&gt; 200
+    }
+
+    [
+      ['http://example.org/?q=fred', 'http://example.org/?q={bar}'],
+      #['http://example.org/?foo=%CE%8E&amp;bar=fred&amp;baz=10%2C20%2C30', 'http://example.org/?{-join|&amp;|foo,bar,xyzzy,baz}'],
+      ['/', '/{xyzzy}'],
+      ['http://example.org/?d=10,20,30', 'http://example.org/?d={-list|,|qux}'],
+      ['http://example.org/?d=10&amp;d=20&amp;d=30', 'http://example.org/?d={-list|&amp;d=|qux}'],
+      ['http://example.org/fredfred/a%2Fb%2Fc', 'http://example.org/{bar}{bar}/{garply}'],
+#      ['http://example.org/fred/fred//wilma', 'http://example.org/{bar}{-prefix|/|fred}'],
+#      [':%E1%B9%A1:%E1%B9%A1:', '{-neg|:|corge}{-suffix|:|plugh}'],
+      ['../ben%20%26%20jerrys/', '../{waldo}/'],
+#      ['telnet:192.0.2.16:80', 'telnet:192.0.2.16{-opt|:80|grault}'],
+      [':200:', ':{1-a_b.c}:']
+    ].each do |test|
+      assert_equal test.first, @parser.parse(test.last).value(defaults)
+    end
+  end
 end</diff>
      <filename>test/test_uri_template_grammar.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>9a0ddf30919ee8250ea10c346e3c412a0d7946a4</id>
    </parent>
  </parents>
  <author>
    <name>Stefan Saasen</name>
    <email>stefan@coravy.com</email>
  </author>
  <url>http://github.com/juretta/uri-templates/commit/2e7b62d150169051d2ce7d5b828289259161fb77</url>
  <id>2e7b62d150169051d2ce7d5b828289259161fb77</id>
  <committed-date>2009-05-21T02:10:12-07:00</committed-date>
  <authored-date>2008-12-06T14:16:56-08:00</authored-date>
  <message>WIP: Added Draft Version 0.3. Implemented first changes.</message>
  <tree>79e9360f259db7c33ea036499fa29daaf8c97138</tree>
  <committer>
    <name>Stefan Saasen</name>
    <email>stefan@coravy.com</email>
  </committer>
</commit>
