<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>Rakish.Core/Locations.cs</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -4,4 +4,5 @@
 */obj/*
 *resharper.user*
 *.suo
-*.resharper
\ No newline at end of file
+*.resharper
+*.csproj.user
\ No newline at end of file</diff>
      <filename>.gitignore</filename>
    </modified>
    <modified>
      <diff>@@ -45,6 +45,7 @@
     &lt;Reference Include=&quot;System.Xml&quot; /&gt;
   &lt;/ItemGroup&gt;
   &lt;ItemGroup&gt;
+    &lt;Compile Include=&quot;Locations.cs&quot; /&gt;
     &lt;Compile Include=&quot;Recipe.cs&quot; /&gt;
     &lt;Compile Include=&quot;Task.cs&quot; /&gt;
     &lt;Compile Include=&quot;TaskAttribute.cs&quot; /&gt;</diff>
      <filename>Rakish.Core/Rakish.Core.csproj</filename>
    </modified>
    <modified>
      <diff>@@ -2,108 +2,216 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Reflection;
+using System.Linq;
 
 namespace Rakish.Core
 {
+
+ 
+
+    /// &lt;summary&gt;
+    /// 
+    /// &lt;/summary&gt;
     public class RecipeFinder
     {
-        public IList&lt;Recipe&gt; FindRecipesInAssemblies()
+        
+        //scanning directories 
+        //loading assemblies
+        //building tree of recipes
+        //reflecting on types
+
+        private string[] startDirs;
+
+        public RecipeFinder()
         {
-            var startDir = Environment.CurrentDirectory;
-            return FindRecipesInAssemblies(startDir);
+            
         }
+        public RecipeFinder(params string[] startDirs) : this()
+        {
+            this.startDirs = startDirs;
 
-        public IList&lt;Recipe&gt; FindRecipesInAssemblies(params string[] startDirs)
+            if(startDirs == null)
+            {
+                Locations.StartDirs = new string[] { Environment.CurrentDirectory };
+                this.startDirs = Locations.StartDirs;
+            }
+
+            
+        }
+        //TODO: Too many variables
+        public IList&lt;Recipe&gt; FindRecipesInFiles()
         {
             var recipeClasses = new List&lt;Recipe&gt;();
+            
+            //TODO: Fix this
+            Locations.StartDirs = startDirs;
 
-            foreach(var startDir in startDirs)
+            foreach (var startDir in startDirs)
             {
-                FileInfo[] possibleContainers = GetPossibleContainers(startDir);
+                FileInfo[] dlls = FindAllDlls(startDir);
+                var loadedAssemblies = PreLoadAssembliesToPreventAssemblyNotFoundError(dlls);
 
-                foreach(var assemblyFile in possibleContainers)
-                {
-                    FindRecipesInAssembly(assemblyFile, recipeClasses);
-                }
+                foreach(var assembly in loadedAssemblies)
+                    FindRecipesInAssembly(assembly, recipeClasses);
+                
             }
 
             return recipeClasses.AsReadOnly();
         }
 
-        private static void FindRecipesInAssembly(FileInfo file, List&lt;Recipe&gt; recipeClasses)
+        private List&lt;Assembly&gt; PreLoadAssembliesToPreventAssemblyNotFoundError(FileInfo[] dllFile)
         {
-            var loaded = Assembly.LoadFrom(file.FullName);
+            var loaded = new List&lt;Assembly&gt;();
+            
+            foreach (var dll in dllFile)
+                //loading the core twice is BAD because &quot;if(blah is RecipeAttribute)&quot; etc will always fail
+                if(! dll.Name.StartsWith(&quot;Rakish.Core&quot;)) 
+                    loaded.Add(Assembly.LoadFrom(dll.FullName));
+
+            return loaded;
+        }
+
+        private static void FindRecipesInAssembly(Assembly loaded, List&lt;Recipe&gt; recipeClasses)
+        {   
             var types = loaded.GetTypes();
+            
             foreach(var type in types)
-            {
                 FindRecipeInType(type, recipeClasses);
-            }
+            
         }
 
-        private static void FindRecipeInType(Type type, List&lt;Recipe&gt; recipeClasses)
+
+        public static RecipeAttribute GetRecipeAttributeOrNull(Type type)
         {
-            var atts = type.GetCustomAttributes(true);
+            //get recipe attributes for type 
+            var atts = type.GetCustomAttributes(typeof(RecipeAttribute), true);
+
+            //should only be one per type
+            if (atts.Length &gt; 1)
+                throw new Exception(&quot;Expected only 1 recipe attribute, but got more&quot;);
+
+            //return if none, we'll skip this class
+            if (atts.Length == 0)
+                return null;
 
-            foreach(var att in atts)
+            var recipeAtt = atts[0] as RecipeAttribute;
+
+            //throw if bad case. Should cast fine (if not, then might indicate 2 of the same assembly is loaded)
+            if (recipeAtt == null)
+                throw new Exception(&quot;Casting error for RecipeAttribute. Same assembly loaded more than once?&quot;);
+
+            return recipeAtt;
+        }
+
+        //TODO: FindRecipeInType is Too long and 
+        //TODO: too many IL Instructions
+        //TODO: Nesting is too deep
+        //TODO: Not enough comments
+        //TODO: Too many variables
+        //
+        private static void FindRecipeInType(Type type, List&lt;Recipe&gt; manifest)
+        {
+            //find the attribute on the assembly if there is one
+            var recipeAtt = GetRecipeAttributeOrNull(type);
+            
+            //if not found, return
+            if (recipeAtt == null) return;
+            
+            //create recipe details from attribute
+            Recipe recipe = CreateRecipeFromAttribute(type, recipeAtt);
+
+            //add to manifest
+            manifest.Add(recipe);
+
+            //trawl through and add the tasks
+            AddTasksToRecipe(type, recipe);
+            
+        }
+
+        private static Recipe CreateRecipeFromAttribute(Type type, RecipeAttribute recipeAtt)
+        {
+            return new Recipe
+                       {
+                           Class = type, 
+                           Name = String.IsNullOrEmpty(recipeAtt.Name) ? type.Name.Replace(&quot;Recipe&quot;,&quot;&quot;).ToLower() : recipeAtt.Name
+                       };
+        }
+
+        private static void AddTasksToRecipe(Type type, Recipe recipe)
+        {
+            //loop through methods in class
+            foreach(var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly ))
             {
-                var recipeAtt = att as RecipeAttribute;
+                //get the custom attributes on the method
+                var foundAttributes = method.GetCustomAttributes(typeof(TaskAttribute), false);
+                
+                if(foundAttributes.Length &gt; 1)
+                    throw new Exception(&quot;Should only be one task attribute on a method&quot;);
 
-                if (recipeAtt == null)
+                //if none, skp to the next method
+                if (foundAttributes.Length == 0)
                     continue;
+                
+                var taskAttribute = foundAttributes[0] as TaskAttribute;
+                
+                if (taskAttribute == null)
+                    throw new Exception(&quot;couldn't cast TaskAttribute correctly, more that one assembly loaded?&quot;);
+
+                //get the task based on attribute contents
+                Task t = CreateTaskFromAttribute(method, taskAttribute);
 
-                var recipe = new Recipe { Class = type, Name = String.IsNullOrEmpty(recipeAtt.Name) ? type.Name.Replace(&quot;Recipe&quot;,&quot;&quot;).ToLower() : recipeAtt.Name };
-                recipeClasses.Add(recipe);
-
-                foreach(var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
-                {
-                    var taskAttributes = method.GetCustomAttributes(true);
-                    foreach(var taskAttribute in taskAttributes)
-                    {
-                        var ta = taskAttribute as TaskAttribute;
-                        
-                        if (ta == null)
-                            continue;
-
-                        Task t = new Task();
-                        
-                        if(! String.IsNullOrEmpty(ta.Name))
-                        {
-                            t.Name = ta.Name;
-                        }
-                        else
-                        {
-                            t.Name = method.Name.Replace(&quot;Task&quot;, &quot;&quot;).ToLower();
-                        }
-                        
-                        t.Method = method;
-                        
-                        if(! String.IsNullOrEmpty(ta.Help))
-                        {
-                            t.Description = ta.Help;
-                        }
-                        else
-                        {
-                            t.Description = &quot;No description&quot;;
-                        }
-
-                        foreach(string methodName in ta.After)
-                        {
-                            var dependee = type.GetMethod(methodName);
-                            if(dependee == null) throw new Exception(String.Format(&quot;No dependee method {0}&quot;,methodName));
-                            t.DependsOnMethods.Add(dependee);
-                        }
-
-                        recipe.Tasks.Add(t);
-                        
-                    }
-                }
+                //build list of dependent tasks
+                CreateDependentTasks(type, taskAttribute, t);
+
+                //add the task to the recipe
+                recipe.Tasks.Add(t);
             }
         }
 
-        private FileInfo[] GetPossibleContainers(string startDir)
+        private static void CreateDependentTasks(Type type, TaskAttribute taskAttribute, Task t)
         {
-            return new DirectoryInfo(startDir)
+            foreach(string methodName in taskAttribute.After)
+            {
+                var dependee = type.GetMethod(methodName);
+                if(dependee == null) throw new Exception(String.Format(&quot;No dependee method {0}&quot;,methodName));
+                t.DependsOnMethods.Add(dependee);
+            }
+        }
+
+        private static Task CreateTaskFromAttribute(MethodInfo method, TaskAttribute ta)
+        {
+            Task t = new Task();
+                    
+            if(! String.IsNullOrEmpty(ta.Name))
+                t.Name = ta.Name;
+            else
+                t.Name = method.Name.Replace(&quot;Task&quot;, &quot;&quot;).ToLower();
+                    
+                    
+            t.Method = method;
+                    
+            if(! String.IsNullOrEmpty(ta.Help))
+                t.Description = ta.Help;
+            else
+                t.Description = &quot;No description&quot;;
+            return t;
+        }
+
+        private FileInfo[] FindAllDlls(string startDir)
+        {
+            
+            var found = new DirectoryInfo(startDir)
                 .GetFiles(&quot;*.dll&quot;, SearchOption.AllDirectories);
+
+            var deduped = new List&lt;FileInfo&gt;();
+            
+            foreach(var fileInfo in found)
+                if(! fileInfo.Directory.FullName.Contains(&quot;\\obj\\&quot;))
+                    deduped.Add(fileInfo);
+            
+            return deduped.ToArray();
+
+
         }
     }
 }
\ No newline at end of file</diff>
      <filename>Rakish.Core/RecipeFinder.cs</filename>
    </modified>
    <modified>
      <diff>@@ -6,6 +6,13 @@ namespace Rakish.Core
 {
     public class TaskRunner
     {
+        private RecipeFinder finder;
+        
+        public TaskRunner(RecipeFinder aFinder)
+        {
+            finder = aFinder;
+        }
+
         public void Run(Recipe recipe, Task task)
         {
             var recipeInstance = Activator.CreateInstance(recipe.Class);
@@ -13,10 +20,11 @@ namespace Rakish.Core
             task.Method.Invoke(recipeInstance, null);
         }
 
+        //TODO: Run is Too long
+        //TODO: Nesting depth is too deep
         public void Run(string recipeName, string taskName)
         {
-            var finder = new RecipeFinder();
-            var found = finder.FindRecipesInAssemblies();
+            var found = finder.FindRecipesInFiles();
             
             foreach(var r in found)
             {
@@ -42,7 +50,7 @@ namespace Rakish.Core
 //        {
 //            var manifest = new RunManifest();
 //            var finder = new RecipeFinder();
-//            var found = finder.FindRecipesInAssemblies();
+//            var found = finder.FindRecipesInFiles();
 //
 //            foreach (var r in found)
 //            {</diff>
      <filename>Rakish.Core/TaskRunner.cs</filename>
    </modified>
    <modified>
      <diff>@@ -10,8 +10,8 @@ namespace Rakish.Runner
     {
         public static void Main(string[] args)
         {
-            var finder = new RecipeFinder();
-            var found = finder.FindRecipesInAssemblies();
+            var finder = new RecipeFinder(Environment.CurrentDirectory);
+            var found = finder.FindRecipesInFiles();
 
             if(args.Length &gt; 0)
             {
@@ -22,7 +22,7 @@ namespace Rakish.Runner
                 }
 
                 var parts = args[0].Split(':');
-                var runner = new TaskRunner();
+                var runner = new TaskRunner(finder);
                 
                 if(parts.Length == 2)
                     runner.Run(parts[0],parts[1]);</diff>
      <filename>Rakish.Runner/Program.cs</filename>
    </modified>
    <modified>
      <diff>@@ -64,7 +64,7 @@
   &lt;/Target&gt;
   --&gt;
   &lt;PropertyGroup&gt;
-    &lt;PostBuildEvent&gt;copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)rakish.exe&quot;
-copy &quot;$(TargetDir)&quot;*.dll &quot;$(SolutionDir)&quot;&lt;/PostBuildEvent&gt;
+    &lt;PostBuildEvent&gt;copy &quot;$(TargetPath)&quot; &quot;C:\Program Files\Rakish\rakish.exe&quot;
+copy &quot;$(TargetDir)&quot;*.dll &quot;C:\Program Files\Rakish&quot;&lt;/PostBuildEvent&gt;
   &lt;/PropertyGroup&gt;
 &lt;/Project&gt;
\ No newline at end of file</diff>
      <filename>Rakish.Runner/Rakish.Runner.csproj</filename>
    </modified>
    <modified>
      <diff>@@ -46,15 +46,17 @@ namespace Rakish.Test
         [Task(Name=&quot;stats&quot;, Help=&quot;Lists line counts for all types of files&quot;)]
         public void Stats()
         {
-            string rootDir = Environment.CurrentDirectory;// +&quot;..\\..\\..\\..\\&quot;;
+            string rootDir = Locations.StartDirs[0];
+            Console.WriteLine(rootDir);
             var count = new Dictionary&lt;string, long&gt;() { { &quot;lines&quot;, 0 }, { &quot;classes&quot;, 0 }, { &quot;files&quot;, 0 }, { &quot;enums&quot;, 0 }, { &quot;methods&quot;, 0 } };
             GetLineCount(rootDir, &quot;*.cs&quot;, count);
 
             
             Console.WriteLine(&quot;c# Files:\t\t{0}&quot;, count[&quot;files&quot;]);
             Console.WriteLine(&quot;c# Classes:  \t{0}&quot;, count[&quot;classes&quot;]);
-            Console.WriteLine(&quot;c# Methods:\t\t{0}&quot;, count[&quot;methods&quot;]);
+            Console.WriteLine(&quot;c# Methods:  \t{0}&quot;, count[&quot;methods&quot;]);
             Console.WriteLine(&quot;c# Lines:\t\t{0}&quot;, count[&quot;lines&quot;]);
+            Console.WriteLine(&quot;Avg Methods Per Class:\t\t{0}&quot;, count[&quot;methods&quot;]/count[&quot;classes&quot;]);
             
         }
         
@@ -72,13 +74,13 @@ namespace Rakish.Test
                     var line = r.ReadLine();
                     while(line != null)
                     {
-                        if (fileFilter == &quot;*.cs&quot; &amp;&amp; Regex.Match(line, &quot;.+public|private|internal|protected.+class.+&quot;).Length &gt; 0)
+                        if (fileFilter == &quot;*.cs&quot; &amp;&amp; Regex.Match(line, &quot;.+[public|private|internal|protected].+class.+&quot;).Length &gt; 0)
                             counts[&quot;classes&quot;] += 1;
 
-                        if (fileFilter == &quot;*.cs&quot; &amp;&amp; Regex.Match(line, &quot;.+public|private|internal|protected.+enum.+&quot;).Length &gt; 0)
+                        if (fileFilter == &quot;*.cs&quot; &amp;&amp; Regex.Match(line, &quot;.+[public|private|internal|protected].+enum.+&quot;).Length &gt; 0)
                             counts[&quot;enums&quot;] += 1;
 
-                        if (fileFilter == &quot;*.cs&quot; &amp;&amp; Regex.Match(line, &quot;.+public|private|internal|protected.+\\(.*\\).+&quot;).Length &gt; 0)
+                        if (fileFilter == &quot;*.cs&quot; &amp;&amp; Regex.Match(line, &quot;.+[public|private|internal|protected].+\\(.*\\).+&quot;).Length &gt; 0)
                             counts[&quot;methods&quot;] += 1;
 
                         counts[&quot;lines&quot;] += 1;</diff>
      <filename>Rakish.Test/DemoRecipe.cs</filename>
    </modified>
    <modified>
      <diff>@@ -10,18 +10,23 @@ namespace Rakish.Test
     [TestFixture]
     public class RecipeDiscoveryFixture
     {
-        readonly RecipeFinder finder = new RecipeFinder();
+        private RecipeFinder finder;
         IList&lt;Recipe&gt; found;
 
         [SetUp]
         public void Before_Each_Test_Is_Run()
         {
-            found = finder.FindRecipesInAssemblies();   
+            finder = new RecipeFinder(Environment.CurrentDirectory + &quot;..\\..\\..\\..\\&quot;);
+            found = finder.FindRecipesInFiles();   
         }
 
         [Test]
         public void Can_Discover_Recipes()
         {
+            foreach(var r in found)
+            {
+                Console.WriteLine(r.Name);
+            }
             Assert.AreEqual(3, found.Count);
         }
 
@@ -46,7 +51,7 @@ namespace Rakish.Test
         public void Can_Run_Task()
         {
             var recipeInfo = found[1];
-            var runner = new TaskRunner();
+            var runner = new TaskRunner(finder);
             runner.Run(recipeInfo, recipeInfo.Tasks[0]);
             Assert.AreEqual(&quot;TEST&quot;, AppDomain.CurrentDomain.GetData(&quot;TEST&quot;));
         }
@@ -54,7 +59,7 @@ namespace Rakish.Test
         [Test]
         public void Can_Run_Task_By_Name()
         {
-            var runner = new TaskRunner();
+            var runner = new TaskRunner(finder);
             runner.Run(&quot;demo&quot;,&quot;list&quot;);
             Assert.AreEqual(&quot;LIST&quot;, AppDomain.CurrentDomain.GetData(&quot;TEST&quot;));
             runner.Run(&quot;demo&quot;, &quot;stats&quot;);
@@ -79,7 +84,7 @@ namespace Rakish.Test
         [Test]
         public void Functions_Are_Called_In_Correct_Order_With_Dependencies()
         {
-            var runner = new TaskRunner();
+            var runner = new TaskRunner(finder);
             runner.Run(&quot;demo2&quot;, &quot;one&quot;);          
 
         }
@@ -87,7 +92,7 @@ namespace Rakish.Test
         [Test]
         public void Can_Infer_Recipe_Category_And_Task_Name()
         {
-            var runner = new TaskRunner();
+            var runner = new TaskRunner(finder);
             runner.Run(&quot;demo3&quot;, &quot;hello&quot;);          
         }
 </diff>
      <filename>Rakish.Test/RecipeDiscoveryFixture.cs</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>13bb6224c2022d508e890404cb6d25f414603971</id>
    </parent>
  </parents>
  <author>
    <name>Tobin</name>
    <email>tobin@tobinharris.com</email>
  </author>
  <url>http://github.com/tobinharris/golem/commit/e68f88f96b7d7c8e8239a6b2ed720b3bd8cbc1f3</url>
  <id>e68f88f96b7d7c8e8239a6b2ed720b3bd8cbc1f3</id>
  <committed-date>2008-09-20T01:41:28-07:00</committed-date>
  <authored-date>2008-09-20T01:41:28-07:00</authored-date>
  <message>refactoring</message>
  <tree>16e3b04e26a37c3de89e4e6809d6cf330e79426f</tree>
  <committer>
    <name>Tobin</name>
    <email>tobin@tobinharris.com</email>
  </committer>
</commit>
