Commit e9413fd

mo khan <mo@mokhan.ca>
2016-07-04 20:05:52
remove monkey patch for `at`
1 parent 5f1f6d3
app/models/progress.rb
@@ -15,6 +15,10 @@ class Progress
   end
 
   def sets
-    workout.sets.work.where(exercise: exercise).order(:created_at)
+    workout.sets.work.for(exercise).in_order
+  end
+
+  def status
+    "#{to_sets.join("/")} @ #{max_weight} lbs"
   end
 end
app/models/workout.rb
@@ -18,22 +18,29 @@ class Workout < ApplicationRecord
   end
 
   def train(exercise, target_weight, repetitions:, set: nil)
-    set =
-      if set.present? && sets.for(exercise).at(set).present?
-        sets.for(exercise).at(set)
-      else
-        recommendation = program.recommendation_for(user, exercise)
-        sets.build(
-          type: WorkSet.name,
-          exercise: exercise,
-          target_repetitions: recommendation.repetitions
-        )
-      end
-    set.update!(actual_repetitions: repetitions, target_weight: target_weight)
-    set
+    all_sets = sets.for(exercise).to_a
+    if set.present? && (exercise_set = all_sets.to_a.at(set)).present?
+      exercise_set.update!(actual_repetitions: repetitions, target_weight: target_weight)
+      exercise_set
+    else
+      recommendation = program.recommendation_for(user, exercise)
+      exercise_set = sets.build(
+        type: WorkSet.name,
+        exercise: exercise,
+        target_repetitions: recommendation.repetitions
+      )
+      exercise_set.update!(actual_repetitions: repetitions, target_weight: target_weight)
+      exercise_set
+    end
   end
 
   def progress_for(exercise)
     Progress.new(self, exercise)
   end
+
+  def each_exercise
+    exercises.order(:created_at).distinct.each do |exercise|
+      yield exercise
+    end
+  end
 end
app/views/workouts/index.html.erb
@@ -17,11 +17,10 @@
             </p>
           </a>
           <div id="panel-<%= workout.id %>" class="content">
-            <% workout.exercises.order(:created_at).uniq.each do |exercise| %>
-              <% progress = workout.progress_for(exercise) %>
+            <% workout.each_exercise do |exercise| %>
               <p class="text-center">
               <strong><%= exercise.name %></strong>
-              <%= progress.to_sets.join("/") %> @ <%= progress.max_weight %> lbs
+              <%= workout.progress_for(exercise).status %>
               </p>
             <% end %>
           </div>
config/initializers/extensions.rb
@@ -15,9 +15,3 @@ class NilClass
     0.0.lbs.to(units)
   end
 end
-
-class ActiveRecord::AssociationRelation
-  def at(index)
-    to_a.at(index)
-  end
-end
spec/features/workouts_spec.rb
@@ -59,19 +59,19 @@ feature "Workouts", type: :feature do
     end
 
     it "saves the successful set" do
-      first_squat_set = workout.sets.for(squat).at(0)
+      first_squat_set = workout.sets.for(squat).to_a.at(0)
       subject.complete(set: first_squat_set)
       expect(first_squat_set.reload.actual_repetitions).to eql(5)
     end
 
     it "saves the failed set" do
-      second_squat_set = workout.sets.for(squat).at(1)
+      second_squat_set = workout.sets.for(squat).to_a.at(1)
       subject.complete(set: second_squat_set, repetitions: 4)
       expect(second_squat_set.reload.actual_repetitions).to eql(4)
     end
 
     it "does not change an incomplete set" do
-      third_squat_set = workout.sets.for(squat).at(2)
+      third_squat_set = workout.sets.for(squat).to_a.at(2)
       expect(third_squat_set.reload.actual_repetitions).to be_nil
     end
   end
spec/models/csv/import_spec.rb
@@ -76,18 +76,19 @@ describe Csv::Import do
       subject.import_from(directory)
 
       workout = user.workouts.order(:occurred_at).first
-      row_session = workout.progress_for(barbell_row)
-      expect(row_session.to_sets).to eql([5, 5, 5, 5, 5])
-      expect(row_session.sets.at(0).target_weight).to eql(65.0)
-      expect(row_session.sets.at(0).actual_repetitions).to eql(5)
-      expect(row_session.sets.at(1).target_weight).to eql(65.0)
-      expect(row_session.sets.at(1).actual_repetitions).to eql(5)
-      expect(row_session.sets.at(2).target_weight).to eql(65.0)
-      expect(row_session.sets.at(2).actual_repetitions).to eql(5)
-      expect(row_session.sets.at(3).target_weight).to eql(65.0)
-      expect(row_session.sets.at(3).actual_repetitions).to eql(5)
-      expect(row_session.sets.at(4).target_weight).to eql(65.0)
-      expect(row_session.sets.at(4).actual_repetitions).to eql(5)
+      progress = workout.progress_for(barbell_row)
+      expect(progress.to_sets).to eql([5, 5, 5, 5, 5])
+      sets = progress.sets.to_a
+      expect(sets.at(0).target_weight).to eql(65.0)
+      expect(sets.at(0).actual_repetitions).to eql(5)
+      expect(sets.at(1).target_weight).to eql(65.0)
+      expect(sets.at(1).actual_repetitions).to eql(5)
+      expect(sets.at(2).target_weight).to eql(65.0)
+      expect(sets.at(2).actual_repetitions).to eql(5)
+      expect(sets.at(3).target_weight).to eql(65.0)
+      expect(sets.at(3).actual_repetitions).to eql(5)
+      expect(sets.at(4).target_weight).to eql(65.0)
+      expect(sets.at(4).actual_repetitions).to eql(5)
     end
 
     it "excludes items that have already been imported" do
@@ -116,15 +117,16 @@ describe Csv::Import do
       progress = workout.progress_for(chinups)
       expect(progress).to_not be_nil
       expect(progress.to_sets).to eql([5, 3, 2])
-      expect(progress.sets.at(0).target_weight).to eql(0.0)
-      expect(progress.sets.at(0).target_repetitions).to eql(5)
-      expect(progress.sets.at(0).actual_repetitions).to eql(5)
-      expect(progress.sets.at(1).target_weight).to eql(0.0)
-      expect(progress.sets.at(1).target_repetitions).to eql(5)
-      expect(progress.sets.at(1).actual_repetitions).to eql(3)
-      expect(progress.sets.at(2).target_weight).to eql(0.0)
-      expect(progress.sets.at(2).target_repetitions).to eql(5)
-      expect(progress.sets.at(2).actual_repetitions).to eql(2)
+      sets = progress.sets.to_a
+      expect(sets.at(0).target_weight).to eql(0.0)
+      expect(sets.at(0).target_repetitions).to eql(5)
+      expect(sets.at(0).actual_repetitions).to eql(5)
+      expect(sets.at(1).target_weight).to eql(0.0)
+      expect(sets.at(1).target_repetitions).to eql(5)
+      expect(sets.at(1).actual_repetitions).to eql(3)
+      expect(sets.at(2).target_weight).to eql(0.0)
+      expect(sets.at(2).target_repetitions).to eql(5)
+      expect(sets.at(2).actual_repetitions).to eql(2)
     end
 
     it "imports the correct number of sets" do
@@ -132,11 +134,13 @@ describe Csv::Import do
 
       subject.import(row)
       workout = user.workouts.first
-      expect(workout.progress_for(squat).sets.count).to eql(3)
-      expect(workout.progress_for(squat).to_sets).to eql([5, 5, 5])
+      progress = workout.progress_for(squat)
+      expect(progress.sets.count).to eql(3)
+      expect(progress.to_sets).to eql([5, 5, 5])
 
-      expect(workout.progress_for(deadlift).sets.count).to eql(1)
-      expect(workout.progress_for(deadlift).to_sets).to eql([5])
+      progress = workout.progress_for(deadlift)
+      expect(progress.sets.count).to eql(1)
+      expect(progress.to_sets).to eql([5])
     end
   end
 end
spec/models/exercise_set_spec.rb
@@ -14,4 +14,20 @@ describe ExerciseSet do
       expect(subject.weight_per_side).to eql("25.0 lb/side")
     end
   end
+
+  describe ".for" do
+    let(:squat) { create(:exercise) }
+    let(:dip) { create(:exercise) }
+
+    it "returns all sets for the exercise only" do
+      squat_set = create(:work_set, exercise: squat)
+      dip_set = create(:work_set, exercise: dip)
+
+      expect(ExerciseSet.for(squat)).to match_array([squat_set])
+    end
+
+    it "returns nil" do
+      expect(ExerciseSet.for(squat)).to be_empty
+    end
+  end
 end
spec/models/workout_spec.rb
@@ -32,12 +32,13 @@ describe Workout, type: :model do
       expect(result).to be_persisted
       expect(result.exercise).to eql(squat)
       expect(subject.progress_for(squat).to_sets).to eql([5, 3])
-      set = subject.sets.in_order.at(0)
+      sets = subject.sets.in_order.to_a
+      set = sets.at(0)
       expect(set.exercise).to eql(squat)
       expect(set.target_weight).to eql(target_weight.to_f)
       expect(set.target_repetitions).to eql(5)
       expect(set.actual_repetitions).to eql(5)
-      set = subject.sets.in_order.at(1)
+      set = sets.at(1)
       expect(set.exercise).to eql(squat)
       expect(set.target_weight).to eql(target_weight.to_f)
       expect(set.target_repetitions).to eql(5)
@@ -56,18 +57,19 @@ describe Workout, type: :model do
       expect(result.exercise).to eql(squat)
       progress = subject.progress_for(squat)
       expect(progress.to_sets).to eql([5, 3, 5])
-      expect(progress.sets.at(0).exercise).to eql(squat)
-      expect(progress.sets.at(0).target_weight).to eql(target_weight.to_f)
-      expect(progress.sets.at(0).target_repetitions).to eql(5)
-      expect(progress.sets.at(0).actual_repetitions).to eql(5)
-      expect(progress.sets.at(1).exercise).to eql(squat)
-      expect(progress.sets.at(1).target_weight).to eql(new_weight.to_f)
-      expect(progress.sets.at(1).target_repetitions).to eql(5)
-      expect(progress.sets.at(1).actual_repetitions).to eql(3)
-      expect(progress.sets.at(2).exercise).to eql(squat)
-      expect(progress.sets.at(2).target_weight).to eql(target_weight.to_f)
-      expect(progress.sets.at(2).target_repetitions).to eql(5)
-      expect(progress.sets.at(2).actual_repetitions).to eql(5)
+      sets = progress.sets.to_a
+      expect(sets.at(0).exercise).to eql(squat)
+      expect(sets.at(0).target_weight).to eql(target_weight.to_f)
+      expect(sets.at(0).target_repetitions).to eql(5)
+      expect(sets.at(0).actual_repetitions).to eql(5)
+      expect(sets.at(1).exercise).to eql(squat)
+      expect(sets.at(1).target_weight).to eql(new_weight.to_f)
+      expect(sets.at(1).target_repetitions).to eql(5)
+      expect(sets.at(1).actual_repetitions).to eql(3)
+      expect(sets.at(2).exercise).to eql(squat)
+      expect(sets.at(2).target_weight).to eql(target_weight.to_f)
+      expect(sets.at(2).target_repetitions).to eql(5)
+      expect(sets.at(2).actual_repetitions).to eql(5)
     end
 
     it "cannot save a duplicate exercise" do
spec/factories.rb
@@ -7,6 +7,7 @@ FactoryGirl.define do
     association :workout
     target_repetitions { rand(12) }
     target_weight { rand(400) }
+    factory :work_set, class: 'WorkSet'
   end
   factory :program do
     name { FFaker::Internet.user_name }