Skip to content

Commit

Permalink
docs: Enhance code documentation and clarity
Browse files Browse the repository at this point in the history
Improve documentation across multiple packages to enhance code
readability and maintainability. Add package-level comments,
function descriptions, and inline explanations for key
components. Clarify variable names and refine error handling
to provide more context. These changes aim to make the codebase
more self-explanatory and easier for developers to understand
and maintain.
  • Loading branch information
pblittle committed Sep 10, 2024
1 parent b6af05a commit 1156a39
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 11 deletions.
6 changes: 5 additions & 1 deletion internal/calculators/target_calculator.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package calculators provides functions for performing calculations on shot data.
package calculators

import (
Expand All @@ -7,7 +8,8 @@ import (
)

// CalculateTargets computes the median target distance for each club type
// and updates the Target field in each ShotData struct.
// and updates the Target field in each ProcessedShotData struct.
// This function modifies the input slice in-place.
func CalculateTargets(shotData *[]models.ProcessedShotData) {
// Group shots by club type
clubShots := make(map[string][]float64)
Expand All @@ -30,6 +32,8 @@ func CalculateTargets(shotData *[]models.ProcessedShotData) {

// calculateMedian computes the median value from a slice of float64 numbers.
// It handles both odd and even-length slices.
// The function sorts the input slice and returns the middle value (or average of two middle values).
// If the input slice is empty, it returns 0.
func calculateMedian(numbers []float64) float64 {
sort.Float64s(numbers)
length := len(numbers)
Expand Down
18 changes: 14 additions & 4 deletions internal/parsers/shot_data_parser.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package parsers provides functionality for parsing shot data from various launch monitor types.
package parsers

import (
Expand All @@ -13,21 +14,26 @@ import (
"albatross/internal/reader"
)

// headerPattern is a regular expression used to identify header rows in the CSV file.
var headerPattern = regexp.MustCompile(`(?i)(club type|total distance|side carry)`)

// ProcessShotData reads and processes shot data from a CSV file
// ProcessShotData reads and processes shot data from a CSV file.
// It supports different launch monitor types and returns a slice of ProcessedShotData.
func ProcessShotData(inputFile string, launchMonitorType string) ([]models.ProcessedShotData, error) {
// Open the input file
file, err := os.Open(inputFile)
if err != nil {
return nil, fmt.Errorf("opening file: %w", err)
}
defer file.Close()

// Set up CSV reader
csvReader := csv.NewReader(file)
csvReader.Comma = ',' // Using comma as separator
csvReader.LazyQuotes = true
csvReader.FieldsPerRecord = -1 // Allow variable number of fields

// Create appropriate launch monitor based on the type
var launchMonitor models.LaunchMonitor
switch launchMonitorType {
case "mlm2pro":
Expand All @@ -40,6 +46,7 @@ func ProcessShotData(inputFile string, launchMonitorType string) ([]models.Proce
var headers []string
inDataBlock := false

// Read and process each row of the CSV file
for {
row, err := csvReader.Read()
if err != nil {
Expand All @@ -53,6 +60,7 @@ func ProcessShotData(inputFile string, launchMonitorType string) ([]models.Proce
continue
}

// Check if the current row is a header row
if isHeader(row) {
headers = normalizeHeaders(row)
inDataBlock = true
Expand All @@ -64,11 +72,13 @@ func ProcessShotData(inputFile string, launchMonitorType string) ([]models.Proce
continue
}

// Check if we've reached the end of the data block
if isEmptyRow(row) || strings.HasPrefix(strings.ToLower(row[0]), "average") {
inDataBlock = false
continue
}

// Parse and process the row data
rawData, err := launchMonitor.ParseRow(row, headers)
if err != nil {
log.Printf("Skipping row due to error: %v", err)
Expand All @@ -86,7 +96,7 @@ func ProcessShotData(inputFile string, launchMonitorType string) ([]models.Proce
return shotData, nil
}

// isHeader checks if a row is a header row
// isHeader checks if a row is a header row by matching against the headerPattern.
func isHeader(row []string) bool {
if len(row) == 0 {
return false
Expand All @@ -99,7 +109,7 @@ func isHeader(row []string) bool {
return false
}

// normalizeHeaders standardizes header names
// normalizeHeaders standardizes header names by converting them to lowercase and trimming whitespace.
func normalizeHeaders(row []string) []string {
normalized := make([]string, len(row))
for i, header := range row {
Expand All @@ -108,7 +118,7 @@ func normalizeHeaders(row []string) []string {
return normalized
}

// isEmptyRow checks if a row is empty
// isEmptyRow checks if a row is empty by verifying that all cells are empty strings when trimmed.
func isEmptyRow(row []string) bool {
for _, cell := range row {
if strings.TrimSpace(cell) != "" {
Expand Down
8 changes: 7 additions & 1 deletion internal/writer/writer.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
// Package writer provides interfaces and implementations for writing processed shot data to various output formats.
package writer

import "albatross/internal/models"

// Writer interface defines the method that any writer should implement
// Writer interface defines the method that any writer should implement.
// This interface allows for different output formats to be used interchangeably,
// following the Strategy pattern.
type Writer interface {
// Write takes a filename and a slice of ProcessedShotData, and writes the data to the specified file.
// The exact format of the output is determined by the specific implementation of the Writer interface.
// It returns an error if the writing process encounters any issues.
Write(filename string, data []models.ProcessedShotData) error
}
16 changes: 11 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Package main is the entry point for the Albatross application.
// It processes shot data from various launch monitors and calculates targets.
package main

import (
Expand All @@ -11,6 +13,8 @@ import (
"albatross/utils"
)

// main is the entry point of the application. It handles command-line arguments,
// processes shot data, calculates targets, and writes the results to a file.
func main() {
// Parse command-line arguments
if len(os.Args) != 3 {
Expand All @@ -25,20 +29,20 @@ func main() {
log.Fatalf("Error: Invalid launch monitor type '%s'. Supported type is mlm2pro.", os.Args[1])
}

// Process shot data
// Process shot data from the input file
shotData, err := parsers.ProcessShotData(inputFile, launchMonitorType)
if err != nil {
log.Fatalf("Error processing shot data: %v", err)
}

log.Printf("Processed shot data: %+v", shotData)

// Calculate targets
// Calculate targets based on the processed shot data
calculators.CalculateTargets(&shotData)

log.Printf("Calculated targets: %+v", shotData)

// Write processed data to output file
// Write processed data to an output file
outputFile := utils.ReplaceFileExtension(inputFile, "_processed.csv")
writer := writer.ShotPatternWriter{}
if err := writer.Write(outputFile, shotData); err != nil {
Expand All @@ -48,12 +52,14 @@ func main() {
log.Printf("Successfully processed %d shots and saved results to %s", len(shotData), outputFile)
}

// normalizeLaunchMonitorType converts the launch monitor type to lowercase for consistency
// normalizeLaunchMonitorType converts the launch monitor type to lowercase for consistency.
// This ensures that the type check is case-insensitive.
func normalizeLaunchMonitorType(launchMonitorType string) string {
return strings.ToLower(launchMonitorType)
}

// isValidLaunchMonitorType checks if the provided launch monitor type is supported
// isValidLaunchMonitorType checks if the provided launch monitor type is supported.
// Currently, only "mlm2pro" is supported.
func isValidLaunchMonitorType(launchMonitorType string) bool {
return launchMonitorType == "mlm2pro"
}

0 comments on commit 1156a39

Please sign in to comment.