1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
def plan_prediction_chart @charge ||= Charge.find(params[:id]) if @charge.dated? @week_endings ||= Actual.get_week_endings(2.weeks.ago.to_date) until @week_endings.last.week_ending >= @charge.end_date actual = Actual.new actual.week_ending = @week_endings.last.week_ending.next_week(:friday) @week_endings << actual end else @week_endings ||= Actual.get_week_endings(2.weeks.ago.to_date) 10.times { actual = Actual.new actual.week_ending = @week_endings.last.week_ending.next_week(:friday) @week_endings << actual } end @total_project_hours ||= Actual.project_total(@charge.project_number, @charge.primary_number) @total_budgeted_hours ||= BudgetPlan.get_total_budgeted_hours(@charge.id) @remaining_hours ||= (@total_budgeted_hours - @total_project_hours) @average_value ||= Actual.weekly_charge_average(6, @charge) @step = Array.new if @average_value < 10 @step << {:minus_three => 0.75, :minus_two => 0.50, :minus_one => 0.25, :plus_one => 0.25, :plus_two => 0.50, :plus_three => 1.0, :plus_four => 1.5} else @step << {:minus_three => 0.50, :minus_two => 0.20, :minus_one => 0.10, :plus_one => 0.10, :plus_two => 0.20, :plus_three => 0.30, :plus_four => 1.0} end @step_minus_three = @remaining_hours @step_minus_two = @remaining_hours @step_minus_one = @remaining_hours @average = @remaining_hours @step_plus_one = @remaining_hours @step_plus_two = @remaining_hours @step_plus_three = @remaining_hours @step_plus_four = @remaining_hours @chart_data = Array.new for week in @week_endings @chart_data << { :week_ending => week.week_ending, :minus_three => @step_minus_three, :minus_two => @step_minus_two, :minus_one => @step_minus_one, :average => @average, :plus_one => @step_plus_one, :plus_two => @step_plus_two, :plus_three => @step_plus_three, :plus_four => @step_plus_four } @step_minus_three -= (@average_value - (@average_value * @step[0][:minus_three])) @step_minus_two -= (@average_value - (@average_value * @step[0][:minus_two])) @step_minus_one -= (@average_value - (@average_value * @step[0][:minus_one])) @average -= @average_value.to_f @step_plus_one -= (@average_value + (@average_value * @step[0][:plus_one])) @step_plus_two -= (@average_value + (@average_value * @step[0][:plus_two])) @step_plus_three -= (@average_value + (@average_value * @step[0][:plus_three])) @step_plus_four -= (@average_value + (@average_value * @step[0][:plus_four])) end end
Refactorings
No refactoring yet !
Joe Grossberg
June 29, 2008, June 29, 2008 00:54, permalink
* Rather than specifically name all those "steps", I would just make an array of key-value pairs, with "average" (insufficiently clear variable name, BTW -- average *what*?) in the middle. Then, find that item and count backwards three and forwards four to get the values you want. You'll save a lot of duplicated code and cut way down on the number of variables you're creating. Even if it looks *similar* and not actually *duplicate*, you can almost always refactor our commonalities
* Move that "for week in @week_endings" bit to its own method.
* "if @average_value < 10" ... why the magic number? Make it a constant and call it something that explains what it represents
* Instead of doing "@step = Array.new", then appending a single item (a hash) and then accessing the first item of that array; just ditch line 23, change lines 25 and 27 to have "@step =" instead of "@step <<", change line 48 et al. to have "... @step[:minus_three]" instead of "@step[0][:minus_three]". If you have an Array that is always one element in size, you do not need an Array at all.
This could easily be the poorest code I've ever written and I am no way proud of anything you see here :).
This code builds an array of data (@chart_data) that is used to populate a chart.
For a given project, the average number of hours spent on that project are calculated. Then if the project has an end date, it gathers all the week endings between now and then, otherwise it just predicts out to the next 10 weeks.
For each week it takes the average number of hours and calculates the following the average plus and minus a variety of %'s. This way you can say "ok, if we work 50% on top of our average, we'll have this many hours left over" type of situations. This data is then plotted on a YUI! chart and provides a very useful outlook on projects.
But as you can see, my implementation is terrible! It works, but it's terrible... If anything looks confusing you need clarification on the purpose, post the line number and I'll gladly explain.