Revision
3455
Author
ernest.prabhakar@gmail.com
Date
2010-02-08 15:05:40 -0800 (Mon, 08 Feb 2010)

Log Message

Create and pass spec for Enumerable#p_find

Modified Paths

Diff

Modified: MacRuby/trunk/lib/dispatch/enumerable.rb (3454 => 3455)


--- MacRuby/trunk/lib/dispatch/enumerable.rb	2010-02-08 23:05:29 UTC (rev 3454)
+++ MacRuby/trunk/lib/dispatch/enumerable.rb	2010-02-08 23:05:40 UTC (rev 3455)
@@ -31,41 +31,50 @@
 
   # Parallel +collect+ plus +inject+
   # Accumulates from +initial+ via +op+ (default = '+')
+  # Note: each object can only run one mapreduce at a time
   def p_mapreduce(initial, op=:+, &block)
+    raise ArgumentError if not initial.respond_to? op
+    # Since exceptions from a Dispatch block can act funky 
     @mapreduce_q ||= Dispatch::Queue.new("enumerable.p_mapreduce.#{object_id}")
-    # Ideally should set from within a Dispatch.once to avoid race
-    raise ArgumentError if not initial.respond_to? op
-    # Since exceptions from a Dispatch block act funky 
+    # Ideally should run from within a Dispatch.once to avoid race
     @mapreduce_q.sync do 
-      @result = initial
-      q = Dispatch.queue_for(@result)
-      p_each do |obj|
+      @mapreduce_result = initial
+      q = Dispatch.queue_for(@mapreduce_result)
+      self.p_each do |obj|
         val = block.call(obj)
-        q.async { @result = @result.send(op, val) }
+        q.async { @mapreduce_result = @mapreduce_result.send(op, val) }
       end
       q.sync {}
-      return @result # can return from inside the block
+      return @mapreduce_result
     end
   end
 
-
   # Parallel +select+; will return array of objects for which
   # +&block+ returns true.
   def p_find_all(&block)
     found_all = Dispatch.wrap(Array)
     self.p_each { |obj| found_all << obj if block.call(obj) }
-    found_all._done # will this leak?
+    found_all._done_
   end
 
   # Parallel +detect+; will return -one- match for +&block+
   # but it may not be the 'first'
   # Only useful if the test block is very expensive to run
+  # Note: each object can only run one find at a time
+
   def p_find(&block)
-    found = Dispatch.wrap(nil)
-    self.p_each do |obj|
-      found = found.nil? ? block.call(obj) : nil
-      found = obj if found and found.nil? 
+    @find_q ||= Dispatch::Queue.new("enumerable.p_find.#{object_id}")
+    @find_q.sync do 
+      @find_result = nil
+      q = Dispatch.queue_for(@find_result)
+      self.p_each do |obj|
+        if @find_result.nil?
+          found = block.call(obj)
+          q.async { @find_result = obj if found }
+        end
+      end
+      q.sync {} #if @find_result.nil?
+      return @find_result
     end
-    found._done # will this leak?
   end
 end

Modified: MacRuby/trunk/spec/macruby/library/dispatch/enumerable_spec.rb (3454 => 3455)


--- MacRuby/trunk/spec/macruby/library/dispatch/enumerable_spec.rb	2010-02-08 23:05:29 UTC (rev 3454)
+++ MacRuby/trunk/spec/macruby/library/dispatch/enumerable_spec.rb	2010-02-08 23:05:40 UTC (rev 3455)
@@ -39,25 +39,18 @@
         @ary.p_each_with_index {|v, i| temp = v**i; @q.sync {@sum2 += temp} }
         @sum2.should == @sum1
       end
-      
-      it "should execute concurrently" do
-        true.should == true
-      end
     end
     
     describe :p_map do
       it "exists on objects that support Enumerable" do
         @ary.respond_to?(:p_map).should == true
       end
+      
       it "should behave like map" do
         map1 = @ary.map {|v| v*v}
         map2 = @ary.p_map {|v| v*v}
         map2.should == map1
       end
-      
-      it "should execute concurrently" do
-        true.should == true
-      end
     end
 
     describe :p_mapreduce do
@@ -85,11 +78,37 @@
         sum2 = @ary.p_mapreduce(0, :|) {|v| v**2}   
         sum2.should == sum1
       end
-      
-      it "should execute concurrently" do
-        true.should == true
+    end
+
+    describe :p_find_all do
+      it "exists on objects that support Enumerable" do
+        @ary.respond_to?(:p_find_all).should == true
+      end  
+
+      it "should behave like find_all" do
+        found1 = @ary.find_all {|v| v.odd?}
+        found2 = @ary.p_find_all {|v| v.odd?}
+        found2.sort.should == found1
       end
     end
 
+    describe :p_find do
+      it "exists on objects that support Enumerable" do
+        @ary.respond_to?(:p_find).should == true
+      end  
+
+      it "returns nil if nothing found" do
+        found2 = @ary.p_find {|v| false}
+        found2.should.nil?
+      end
+
+      it "returns one element that matches the condition" do
+        found1 = @ary.find_all {|v| v.odd?}
+        found2 = @ary.p_find {|v| v.odd?}
+        found2.should_not.nil?
+        found1.include? found2
+      end
+    end
+    
   end
 end
\ No newline at end of file