Commit 6b9ddff
Changed files (5)
app
models
spec
models
csv
app/models/csv/exercise.rb
@@ -0,0 +1,5 @@
+class Csv::Exercise
+ attr_accessor :name, :weight_kg, :weight_lb
+ attr_accessor :sets
+end
+
app/models/csv/import.rb
@@ -1,11 +1,49 @@
+require "csv"
+
class Csv::Import
+ attr_reader :user, :program
+
def initialize(user, program)
+ @user = user
+ @program = program
end
def can_parse?(directory)
- puts `ls -al #{directory}`
+ File.exist?(database_file(directory))
end
def import_from(directory)
+ ActiveRecord::Base.transaction do
+ ::CSV.foreach(database_file(directory)).drop(1).each do |row|
+ import(row)
+ end
+ end
+ end
+
+ private
+
+ def database_file(dir)
+ "#{dir}/spreadsheet-stronglifts.csv"
+ end
+
+ def import(row)
+ workout_row = Csv::Workout.map_from(row, user)
+
+ workout = program.workouts.find_by(name: workout_row.workout)
+ training_session = user.begin_workout(
+ workout,
+ workout_row.date,
+ workout_row.body_weight_lb.to_f)
+ training_session.exercise_sessions.destroy_all
+ workout.exercise_workouts.each do |exercise_workout|
+ row = workout_row.exercises.find do |x|
+ x.name.downcase == exercise_workout.exercise.name.downcase
+ end
+ training_session.train(
+ exercise_workout.exercise,
+ row.weight_lb,
+ row.sets
+ )
+ end
end
end
app/models/csv/workout.rb
@@ -0,0 +1,28 @@
+class Csv::Workout
+ attr_accessor :date, :note, :workout
+ attr_accessor :body_weight_kg, :body_weight_lb
+ attr_accessor :exercises
+
+ def self.map_from(row, user)
+ workout = new
+ day, month, year = row[0].split('/')
+ year = "20#{year}"
+ workout.date = user.timezone.local_to_utc(Time.utc(year, month, day))
+ workout.note = row[1]
+ workout.workout = row[2]
+ workout.body_weight_kg = row[3]
+ workout.body_weight_lb = row[4]
+ workout.exercises = []
+ all_exercises = row[5..(row.size)]
+ # skip additional exercises for now
+ all_exercises.take(3 * 8).each_slice(8) do |slice|
+ exercise = Csv::Exercise.new
+ exercise.name = slice[0]
+ exercise.weight_kg = slice[1]
+ exercise.weight_lb = slice[2]
+ exercise.sets = slice[3..(slice.size)]
+ workout.exercises << exercise
+ end
+ workout
+ end
+end
app/models/user.rb
@@ -9,7 +9,7 @@ class User < ActiveRecord::Base
validates :username, presence: true, format: { with: USERNAME_REGEX }, uniqueness: true
validates :email, presence: true, email: true, uniqueness: true
validates_acceptance_of :terms_and_conditions
-
+
after_create :create_profile
def timezone
@@ -58,11 +58,10 @@ class User < ActiveRecord::Base
user.authenticate(password)
end
end
-
+
private
-
+
def create_profile
self.profile = Profile.create!(user: self, gender: nil, social_tolerance: nil)
end
-
end
spec/models/csv/import_spec.rb
@@ -0,0 +1,102 @@
+require 'rails_helper'
+
+describe Csv::Import do
+ include_context "stronglifts_program"
+ subject { Csv::Import.new(user, program) }
+ let(:user) { create(:user) }
+
+ describe "#can_parse?" do
+ let(:directory) { Dir.mktmpdir }
+
+ context "when the directory contains a csv export" do
+ before :each do
+ FileUtils.touch("#{directory}/spreadsheet-stronglifts.csv")
+ end
+
+ it "returns true" do
+ expect(subject.can_parse?(directory)).to be_truthy
+ end
+ end
+
+ context "when the directory does not have csv export" do
+ it "returns false" do
+ expect(subject.can_parse?(directory)).to be_falsey
+ end
+ end
+ end
+
+ describe "#import_from" do
+ let(:directory) { Dir.mktmpdir }
+ let(:backup_file) do
+ Rails.root.join("spec", "fixtures", "spreadsheet-stronglifts.csv")
+ end
+
+ before :each do
+ `cp #{backup_file} #{directory}`
+ end
+
+ after :each do
+ FileUtils.remove_entry(directory)
+ end
+
+ it "imports each training session" do
+ subject.import_from(directory)
+ training_session = user.training_sessions.order(:occurred_at).first
+
+ expected_date = user.timezone.local_to_utc(Time.utc(2015, 03, 02))
+ expect(training_session.occurred_at).to eql(expected_date)
+ expect(training_session.workout).to eql(workout_a)
+ expect(training_session.body_weight).to eql(205.0)
+ expect(training_session.exercise_sessions.count).to eql(3)
+ expect(
+ training_session.exercise_sessions.map { |x| x.exercise.name }
+ ).to match_array(["Squat", "Bench Press", "Barbell Row"])
+ end
+
+ it "imports the completed squat exercise" do
+ subject.import_from(directory)
+
+ training_session = user.training_sessions.order(:occurred_at).first
+ squat_session = training_session.progress_for(squat)
+
+ expect(squat_session.target_weight).to eql(45.0)
+ expect(squat_session.sets[0]).to eql("5")
+ expect(squat_session.sets[1]).to eql("5")
+ expect(squat_session.sets[2]).to eql("5")
+ expect(squat_session.sets[3]).to eql("5")
+ expect(squat_session.sets[4]).to eql("5")
+ end
+
+ it "imports the completed bench exercise" do
+ subject.import_from(directory)
+
+ training_session = user.training_sessions.order(:occurred_at).first
+ bench_session = training_session.progress_for(bench_press)
+ expect(bench_session.target_weight).to eql(65.0)
+ expect(bench_session.sets[0]).to eql("5")
+ expect(bench_session.sets[1]).to eql("5")
+ expect(bench_session.sets[2]).to eql("5")
+ expect(bench_session.sets[3]).to eql("5")
+ expect(bench_session.sets[4]).to eql("5")
+ end
+
+ it "imports the completed barbell row exercise" do
+ subject.import_from(directory)
+
+ training_session = user.training_sessions.order(:occurred_at).first
+ row_session = training_session.progress_for(barbell_row)
+ expect(row_session.target_weight).to eql(65.0)
+ expect(row_session.sets[0]).to eql("5")
+ expect(row_session.sets[1]).to eql("5")
+ expect(row_session.sets[2]).to eql("5")
+ expect(row_session.sets[3]).to eql("5")
+ expect(row_session.sets[4]).to eql("5")
+ end
+
+ it "excludes items that have already been imported" do
+ subject.import_from(directory)
+ subject.import_from(directory)
+ expect(user.training_sessions.count).to eql(100)
+ end
+ end
+end