diff --git a/internal/exercises/catalog.yaml b/internal/exercises/catalog.yaml index b8b9cad..5fe6fa0 100644 --- a/internal/exercises/catalog.yaml +++ b/internal/exercises/catalog.yaml @@ -251,3 +251,11 @@ projects: - "Use time.Parse() to parse time strings with known layouts" - "Use time.LoadLocation() to work with different timezones" - "Extract time components using .Date() and .Clock() methods" +- slug: 40_text_templates + title: "Text Templates" + difficulty: beginner + topics: ["text/template", "strings", "formatting"] + hints: + - "Use Go's text/template package to create and execute templates." + - "Define template actions like {{.Field}} to inject data." + - "Use template functions like printf for formatting." diff --git a/internal/exercises/solutions/40_text_templates/text_templates.go b/internal/exercises/solutions/40_text_templates/text_templates.go new file mode 100644 index 0000000..09a7784 --- /dev/null +++ b/internal/exercises/solutions/40_text_templates/text_templates.go @@ -0,0 +1,31 @@ +package exercises + +import ( + "bytes" + "text/template" +) + +// RenderTemplate takes a template string and data map, returns the rendered string or error. +func RenderTemplate(tmplStr string, data map[string]any) (string, error) { + tmpl, err := template.New("exercise").Parse(tmplStr) + if err != nil { + return "", err + } + + var buf bytes.Buffer + err = tmpl.Execute(&buf, data) + if err != nil { + return "", err + } + + return buf.String(), nil +} + +// FormatUserGreeting returns a greeting using text/template with user's name +func FormatUserGreeting(name string) (string, error) { + const greetingTmpl = "Hello, {{.Name}}!" + data := map[string]any{ + "Name": name, + } + return RenderTemplate(greetingTmpl, data) +} diff --git a/internal/exercises/templates/40_text_templates/text_templates.go b/internal/exercises/templates/40_text_templates/text_templates.go new file mode 100644 index 0000000..2857d0d --- /dev/null +++ b/internal/exercises/templates/40_text_templates/text_templates.go @@ -0,0 +1,16 @@ +package exercises + +import ( + "bytes" + "text/template" +) + +// RenderTemplate takes a template string and data map, returns the rendered string or error. +func RenderTemplate(tmplStr string, data map[string]any) (string, error) { + return "", nil +} + +// FormatUserGreeting returns a greeting using text/template with user's name +func FormatUserGreeting(name string) (string, error) { + return "", nil +} \ No newline at end of file diff --git a/internal/exercises/templates/40_text_templates/text_templates_test.go b/internal/exercises/templates/40_text_templates/text_templates_test.go new file mode 100644 index 0000000..2da533f --- /dev/null +++ b/internal/exercises/templates/40_text_templates/text_templates_test.go @@ -0,0 +1,71 @@ +package exercises + +import ( + "testing" +) + +func TestRenderTemplate(t *testing.T) { + t.Run("Success", func(t *testing.T) { + tmpl := "Name: {{.Name}}, Age: {{.Age}}" + data := map[string]any{ + "Name": "Alice", + "Age": 30, + } + + result, err := RenderTemplate(tmpl, data) + if err != nil { + t.Errorf("RenderTemplate returned error: %v", err) + } + expected := "Name: Alice, Age: 30" + if result != expected { + t.Errorf("RenderTemplate = %q, want %q", result, expected) + } + }) + + t.Run("InvalidSyntax", func(t *testing.T) { + tmpl := "Hello {{.Name" + data := map[string]any{"Name": "Bob"} + + _, err := RenderTemplate(tmpl, data) + if err == nil { + t.Error("Expected error for invalid template syntax, got nil") + } + }) + + t.Run("MissingData", func(t *testing.T) { + tmpl := "Hello, {{.MissingField}}!" + data := map[string]any{"Name": "Charlie"} + + _, err := RenderTemplate(tmpl, data) + if err != nil { + t.Errorf("RenderTemplate unexpectedly returned error: %v", err) + } + expected := "Hello, !" + if result, _ := RenderTemplate(tmpl, data); result == expected { + } + }) +} + +func TestFormatUserGreeting(t *testing.T) { + t.Run("Success", func(t *testing.T) { + result, err := FormatUserGreeting("Bob") + if err != nil { + t.Errorf("FormatUserGreeting returned error: %v", err) + } + expected := "Hello, Bob!" + if result != expected { + t.Errorf("FormatUserGreeting = %q, want %q", result, expected) + } + }) + + t.Run("EmptyName", func(t *testing.T) { + result, err := FormatUserGreeting("") + if err != nil { + t.Errorf("FormatUserGreeting returned error: %v", err) + } + expected := "Hello, !" + if result != expected { + t.Errorf("FormatUserGreeting = %q, want %q", result, expected) + } + }) +} \ No newline at end of file