<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -11,6 +11,18 @@ module Suprdate
       if array.size == 1 then array[0] else array end
     end
     
+    def self.english_list(items)
+      items = items.map { |x| x.to_s }
+      case items.length
+      when 1
+        items[0]
+      when 2
+        items.join(' and ')
+      else
+        items[0..-2].join(', ') + ', and ' + items.last
+      end
+    end
+    
     # Some inflection on the #name of constants.
     module CleanConstantName
     </diff>
      <filename>lib/suprdate.rb</filename>
    </modified>
    <modified>
      <diff>@@ -29,19 +29,26 @@ module Suprdate
 
       # Perform the conversion, returns a string.
       def convert(serialization)
-        words = [serialization[:title]]
+        @words = [serialization[:title]]
         serialization[:sentences].each do |sentence|
-          next words &lt;&lt; 'never happens' if sentence[:including].empty?
+          next @words &lt;&lt; 'never happens' if sentence[:including].empty?
           sentence[:including].each do |clause|
             clause.extend(SerializationClauseHelper)
-            if clause[:type] == :range
-              words &lt;&lt; 'happens every'
-              words &lt;&lt; clause[:interval] if clause.has_interval
-            end
-            words &lt;&lt; clause.unit_name
+            each_clause(clause)
           end
         end
-        words.map { |x| x.to_s }.join(' ')
+        @words.map { |x| x.to_s }.join(' ')
+      end
+      
+      def each_clause(clause)
+        if clause[:type] == :range
+          @words &lt;&lt; 'happens every'
+          @words &lt;&lt; clause[:interval] if clause.has_interval
+          @words &lt;&lt; clause.unit_name
+        else
+          @words &lt;&lt; 'in'
+          @words &lt;&lt; clause.english_list
+        end
       end
       
     end
@@ -51,6 +58,22 @@ module Suprdate
       def unit_name() self[:unit].send(has_interval ? :name_plural : :name_singular) end
       def has_interval() self[:interval] != CONTINUOUS end
         
+      def english_list()
+        raise RuntimeError.new('No list to speak of') if self[:type] != :list 
+        if self[:unit] == Month
+          months_as_strings(self[:list])
+        else
+          self[:list]
+        end
+      end
+      
+      def months_as_strings(months)
+        months.map do |sym_or_i|
+          MONTHS_AS_STR[MONTHS_SYM_TO_I[sym_or_i] || sym_or_i] or 
+            raise ExpressionError.new(&quot;Unknown month specifier: #{sym_or_i}&quot;)
+        end
+      end
+      
     end
 
     # Raised when you're trying to do weird things that aren't possible with the DSL
@@ -70,8 +93,8 @@ module Suprdate
     
     class ExpressionFragment &lt; ExpressionError
       
-      def self.between(sub_unit, super_unit)
-        new(&quot;#{sub_unit.name_plural} in which #{super_unit.name_singular.downcase}?&quot;)
+      def self.between(lesser_unit, greater_unit)
+        new(&quot;#{lesser_unit.name_plural} in which #{greater_unit.name_singular.downcase}?&quot;)
       end
       
     end
@@ -171,6 +194,8 @@ module Suprdate
       # Serialized representation of the data collected. 
       # Call #serialize to get the whole thing.
       def to_hash
+        assert_non_fragment(@including)
+        assert_non_fragment(@excluding)
         {:including =&gt; @including.map { |clause| clause.to_hash },
          :excluding =&gt; @excluding.map { |clause| clause.to_hash }}
       end
@@ -196,6 +221,15 @@ module Suprdate
         end
       end
       
+      def assert_non_fragment(clauses)
+        if clauses.length &gt; 1
+          last = clauses.last
+          if last.respond_to?(:from) &amp;&amp; last.from.nil?
+            raise ExpressionFragment.between(clauses[-2].unit, last.unit)
+          end
+        end
+      end
+      
     end
     
     module ChainAttrAccessor</diff>
      <filename>lib/suprdate/dsl.rb</filename>
    </modified>
    <modified>
      <diff>@@ -180,10 +180,15 @@ describe DSL, 'elements integrated' do
   end
   
   it &quot;should not permit incomplete things&quot; do
-    lambda { Event().every.day.in.month }.should raise_error(DSL::ExpressionFragment)
-    lambda { Event().every.month.in.year }.should raise_error(DSL::ExpressionFragment)
-    lambda { Event().every.day.in.year }.should raise_error(DSL::ExpressionFragment)
-    lambda { Event().every.day.in.month(:jan).in.year }.should raise_error(DSL::ExpressionFragment)
+    lambda { Event().every.day.in.month.serialize }.should raise_error(DSL::ExpressionFragment)
+    lambda { Event().every.month.in.year.serialize }.should raise_error(DSL::ExpressionFragment)
+    lambda { Event().every.day.in.year.serialize }.should raise_error(DSL::ExpressionFragment)
+    lambda { Event().every.day.in.month(:jan).in.year.serialize }.should raise_error(DSL::ExpressionFragment)
+    # and again with except
+    lambda { Event().every.except.day.in.month.serialize }.should raise_error(DSL::ExpressionFragment)
+    lambda { Event().every.except.month.in.year.serialize }.should raise_error(DSL::ExpressionFragment)
+    lambda { Event().every.except.day.in.year.serialize }.should raise_error(DSL::ExpressionFragment)
+    lambda { Event().every.except.day.in.month(:jan).in.year.serialize }.should raise_error(DSL::ExpressionFragment)
   end
   
 end
@@ -254,10 +259,9 @@ describe DSL::SerializationToEnglish, 'integrated with the DSL serialization' do
   end
   
   it &quot;should serialize multiple clauses&quot; do
-    pending 'Once invalid serializations cannot occur'
-    Event('foo').every.day.in.month(:jan).to_english.should == 'Foo happens every day in January'
-    Event('foo').every(9).days.in.month(:jan).to_english.should == 'Foo happens every 9 days in January, starting from the 1st'
-    Event('foo').every(2).days.in.year(2000).to_english.should == 'Foo happens every 2 days in 2000, starting from January 1st'
+    Event('Foo').every.day.in.month(:jan).to_english.should == 'Foo happens every day in January'
+    Event('Foo').every(9).days.in.month(:jan).to_english.should == 'Foo happens every 9 days in January, starting from the 1st'
+    Event('Foo').every(2).days.in.year(2000).to_english.should == 'Foo happens every 2 days in 2000, starting from January 1st'
   end
 
 end
@@ -281,5 +285,12 @@ describe DSL::SerializationClauseHelper do
     (mock = mock('unit')).should_receive(:name_plural).once.and_return(expected = rand_int)
     subject(:interval =&gt; 2, :unit =&gt; mock).unit_name == expected
   end
-
+  
+  it &quot;should convert months to strings and everything else leave alone&quot; do
+    lambda { subject(:type =&gt; :range).english_list }.should raise_error(RuntimeError)
+    subject(:type =&gt; :list, :list =&gt; [2000], :unit =&gt; Year).english_list.should == [2000]
+    subject(:type =&gt; :list, :list =&gt; [:jan, 1, 3, :oct], :unit =&gt; Month).english_list.
+      should == [&quot;January&quot;, &quot;January&quot;, &quot;March&quot;, &quot;October&quot;]
+  end
+  
 end
\ No newline at end of file</diff>
      <filename>spec/dsl.spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -53,7 +53,7 @@ describe Suprdate::UNITS do
 
 end
 
-describe Suprdate, :disarray do
+describe Utility, :disarray do
 
   it &quot;should return unaltered array if 2 or more elements&quot; do
     Utility::disarray(array = Array.new(2)).should == array
@@ -68,6 +68,26 @@ describe Suprdate, :disarray do
 
 end
 
+describe Utility, :english_list do
+
+  it &quot;should return string forms of single items&quot; do
+    Utility::english_list([1]).should == '1'
+    (mock_item = mock('item')).should_receive(:to_s).and_return(expected = rand_int.to_s)
+    Utility::english_list([mock_item]).should == expected
+  end
+  
+  it &quot;should return two-item lists with and in the middle&quot; do
+    Utility::english_list([1, 2]).should == '1 and 2'
+    Utility::english_list([:Fox, :Hounds]).should == 'Fox and Hounds'
+  end
+  
+  it &quot;should use commas in lists of any length greater than do&quot; do
+    Utility::english_list([1, 2, 3]).should == '1, 2, and 3'
+    Utility::english_list(['Loud', 'scary', 'extremely flatulent']).should == 'Loud, scary, and extremely flatulent'
+  end
+
+end
+
 describe Utility::CleanConstantName do
 
   module FooNamespace</diff>
      <filename>spec/suprdate.spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>2a370eae68834c0b55771389cbd6739b330c3cd7</id>
    </parent>
  </parents>
  <author>
    <name>ole</name>
    <email>oliver.saunders@gmail.com</email>
  </author>
  <url>http://github.com/olliesaunders/suprdate/commit/a17b1ff62bf9ef49cbe1607b29e1f4c57b7f22db</url>
  <id>a17b1ff62bf9ef49cbe1607b29e1f4c57b7f22db</id>
  <committed-date>2009-01-24T20:11:19-08:00</committed-date>
  <authored-date>2009-01-24T20:11:19-08:00</authored-date>
  <message>Done bit more work done on the English serialization of the DSL and added incomplete (fragment) constraint</message>
  <tree>bdafac214422c89c18deded7b5f0dbb1cece5a32</tree>
  <committer>
    <name>ole</name>
    <email>oliver.saunders@gmail.com</email>
  </committer>
</commit>
