Skip to content

Commit 1ea89e3

Browse files
author
Aadit Kamat
authored
Add weather forecast solution in go
1 parent 0a682dd commit 1ea89e3

File tree

8 files changed

+314
-0
lines changed

8 files changed

+314
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"blurb": "Learn about comments by helping a weather station manage their weather forecasting program.",
3+
"authors": [
4+
"nikimanoledaki",
5+
"micuffaro"
6+
],
7+
"files": {
8+
"solution": [
9+
"weather_forecast.go"
10+
],
11+
"test": [
12+
"weather_forecast_test.go"
13+
],
14+
"exemplar": [
15+
".meta/exemplar.go"
16+
]
17+
}
18+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"track":"go","exercise":"weather-forecast","id":"649999bf6ef646439f57ceb10b962ec5","url":"https://exercism.org/tracks/go/exercises/weather-forecast","handle":"aaditkamat","is_requester":true,"auto_approve":false}

Exercism/go/weather-forecast/HELP.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Help
2+
3+
## Running the tests
4+
5+
To run the tests run the command `go test` from within the exercise directory.
6+
7+
If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem`
8+
flags:
9+
10+
go test -v --bench . --benchmem
11+
12+
Keep in mind that each reviewer will run benchmarks on a different machine, with
13+
different specs, so the results from these benchmark tests may vary.
14+
15+
## Submitting your solution
16+
17+
You can submit your solution using the `exercism submit weather_forecast.go` command.
18+
This command will upload your solution to the Exercism website and print the solution page's URL.
19+
20+
It's possible to submit an incomplete solution which allows you to:
21+
22+
- See how others have completed the exercise
23+
- Request help from a mentor
24+
25+
## Need to get help?
26+
27+
If you'd like help solving the exercise, check the following pages:
28+
29+
- The [Go track's documentation](https://exercism.org/docs/tracks/go)
30+
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
31+
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
32+
33+
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
34+
35+
To get help if you're having trouble, you can use one of the following resources:
36+
37+
- [How to Write Go Code](https://golang.org/doc/code.html)
38+
- [Effective Go](https://golang.org/doc/effective_go.html)
39+
- [Go Resources](http://golang.org/help)
40+
- [StackOverflow](http://stackoverflow.com/questions/tagged/go)

Exercism/go/weather-forecast/HINTS.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Hints
2+
3+
## General
4+
5+
- A [documentation comment][comment] should be written directly before the entity that it is describing, start with the name of what it is describing, take the form of a sentence, and end with a period.
6+
7+
## 1. Document package weather
8+
9+
- The [package comment][comment] should be written directly before the package, start with `Package x`, and end with a period.
10+
11+
## 2. Document the CurrentCondition variable
12+
13+
- The [variable comment][variable comment] should be written right before the variable that it is describing, start with its name, and end with a period.
14+
15+
## 3. Document the CurrentLocation variable
16+
17+
- The [variable comment][variable comment] should be written right before the variable that it is describing, start with its name, and end with a period.
18+
19+
## 4. Document the Forecast() function
20+
21+
- The [function comment][comment] should come directly before the function, start with the name of the function and end with a period.
22+
23+
[comment]: https://golang.org/doc/effective_go.html#commentary
24+
[variable comment]: https://dave.cheney.net/practical-go/presentations/qcon-china.html#_comments
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Weather Forecast
2+
3+
Welcome to Weather Forecast on Exercism's Go Track.
4+
If you need help running the tests or submitting your code, check out `HELP.md`.
5+
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
6+
7+
## Introduction
8+
9+
In the previous exercise, we saw that there are two ways to write comments in Go: single-line comments that are preceded by `//`, and multiline comment blocks that are wrapped with `/*` and `*/`.
10+
11+
## Documentation comments
12+
13+
In Go, comments play an important role in documenting code. They are used by the `godoc` command, which extracts these comments to create documentation about Go packages. A documentation comment should be a complete sentence that starts with the name of the thing being described and ends with a period.
14+
15+
Comments should precede packages as well as exported identifiers, for example exported functions, methods, package variables, constants, and structs, which you will learn more about in the next exercises.
16+
17+
A package-level variable can look like this:
18+
19+
```go
20+
// TemperatureCelsius represents a certain temperature in degrees Celsius.
21+
var TemperatureCelsius float64
22+
```
23+
24+
## Package comments
25+
26+
Package comments should be written directly before a package clause (`package x`) and begin with `Package x ...` like this:
27+
28+
```go
29+
// Package kelvin provides tools to convert
30+
// temperatures to and from Kelvin.
31+
package kelvin
32+
```
33+
34+
## Function comments
35+
36+
A function comment should be written directly before the function declaration. It should be a full sentence that starts with the function name. For example, an exported comment for the function `Calculate` should take the form `Calculate ...`. It should also explain what arguments the function takes, what it does with them, and what its return values mean, ending in a period):
37+
38+
```go
39+
// CelsiusFreezingTemp returns an integer value equal to the temperature at which water freezes in degrees Celsius.
40+
func CelsiusFreezingTemp() int {
41+
return 0
42+
}
43+
```
44+
45+
## Instructions
46+
47+
Being hired by a big weather forecast company, your job is to maintain their code base. Scrolling through the code, you find it hard to follow what the code is actually doing. Good thing you know just the right thing to do!
48+
49+
## 1. Document package weather
50+
51+
Write a package comment for `package weather` that describes its contents. The package comment should introduce the package and provide information relevant to the package as a whole.
52+
53+
## 2. Document the CurrentCondition variable
54+
55+
Write a comment for the package variable `CurrentCondition`.
56+
57+
This should tell any user of the package what information the variable stores, and what they can do with it.
58+
59+
## 3. Document the CurrentLocation variable
60+
61+
Just like the previous step, write a comment for `CurrentLocation`.
62+
63+
## 4. Document the Forecast() function
64+
65+
Write a function comment for `Forecast()`. Your comments must describe what the function does, but not how it does it.
66+
67+
## Source
68+
69+
### Created by
70+
71+
- @nikimanoledaki
72+
- @micuffaro

Exercism/go/weather-forecast/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module weather
2+
3+
go 1.16
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Package weather allows users to generate the weather forecast.
2+
package weather
3+
4+
// CurrentCondition is used to store the condition at the current time.
5+
var CurrentCondition string
6+
// CurrentLocation is used to store the location provided at the current time.
7+
var CurrentLocation string
8+
9+
/*
10+
Forecast returns a string that represent the weather forecast based on the supplied
11+
parameters for city and condition.
12+
*/
13+
func Forecast(city, condition string) string {
14+
CurrentLocation, CurrentCondition = city, condition
15+
return CurrentLocation + " - current weather condition: " + CurrentCondition
16+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package weather
2+
3+
import (
4+
"fmt"
5+
"go/ast"
6+
"go/parser"
7+
"go/token"
8+
"strings"
9+
"testing"
10+
)
11+
12+
func TestComments(t *testing.T) {
13+
filename := "weather_forecast.go"
14+
15+
fs := token.NewFileSet()
16+
f, err := parser.ParseFile(fs, filename, nil, parser.ParseComments)
17+
if err != nil {
18+
t.Fatal(err)
19+
}
20+
21+
wantedComments := 4
22+
got := len(f.Comments)
23+
if got != wantedComments {
24+
t.Errorf("Incorrect number of comments: got %d, want %d", got, wantedComments)
25+
}
26+
27+
testPackageComment(t, f)
28+
29+
ast.Inspect(f, func(node ast.Node) bool {
30+
switch n := node.(type) {
31+
case *ast.GenDecl:
32+
if n.Lparen.IsValid() {
33+
for _, v := range n.Specs {
34+
testBlockIdentifierComment(t, v.(*ast.ValueSpec))
35+
}
36+
} else {
37+
testIdentifierComment(t, n)
38+
}
39+
case *ast.FuncDecl:
40+
testFunctionComment(t, n)
41+
}
42+
return true
43+
})
44+
}
45+
46+
func testPackageComment(t *testing.T, node *ast.File) {
47+
t.Helper()
48+
if node.Doc == nil {
49+
t.Errorf("Package weather should have a comment")
50+
}
51+
52+
packageName := node.Name.Name
53+
want := "Package " + packageName
54+
packageComment := node.Doc.Text()
55+
56+
if ok, errStr := testComment("Package", packageName, packageComment, want); !ok {
57+
t.Error(errStr)
58+
}
59+
60+
}
61+
func testIdentifierComment(t *testing.T, node *ast.GenDecl) {
62+
t.Helper()
63+
64+
identifierName := node.Specs[0].(*ast.ValueSpec).Names[0].Name
65+
if node.Doc == nil {
66+
t.Errorf("Exported identifier %s should have a comment", identifierName)
67+
}
68+
69+
identifierComment := node.Doc.Text()
70+
want := identifierName
71+
72+
if ok, errStr := testComment("Variable", identifierName, identifierComment, want); !ok {
73+
t.Error(errStr)
74+
}
75+
}
76+
77+
func testBlockIdentifierComment(t *testing.T, node *ast.ValueSpec) {
78+
t.Helper()
79+
80+
identifierName := node.Names[0].Name
81+
if node.Doc == nil {
82+
t.Errorf("Exported identifier %s should have a comment", identifierName)
83+
}
84+
85+
identifierComment := node.Doc.Text()
86+
want := identifierName
87+
88+
if ok, errStr := testComment("Variable", identifierName, identifierComment, want); !ok {
89+
t.Error(errStr)
90+
}
91+
92+
}
93+
94+
func testFunctionComment(t *testing.T, node *ast.FuncDecl) {
95+
t.Helper()
96+
funcName := node.Name.Name
97+
if node.Doc == nil {
98+
t.Errorf("Exported function %s() should have a comment", funcName)
99+
}
100+
101+
funcComment := node.Doc.Text()
102+
want := funcName
103+
104+
if ok, errStr := testComment("Function", funcName, funcComment, want); !ok {
105+
t.Error(errStr)
106+
}
107+
}
108+
109+
func testComment(entityKind, entityName, comment, wantedPrefix string) (ok bool, errString string) {
110+
111+
trimmedComment := strings.TrimSpace(comment)
112+
lowerEntity := strings.ToLower(entityKind)
113+
114+
// Check if comment has wanted prefix
115+
if !strings.HasPrefix(comment, wantedPrefix) {
116+
errorString := fmt.Sprintf("%s comment for %s '%s' should start with '// %s ...': got '// %s'",
117+
entityKind, lowerEntity, entityName, wantedPrefix, trimmedComment)
118+
return false, errorString
119+
}
120+
121+
// Check if comment content is empty
122+
commentContent := strings.TrimPrefix(trimmedComment, wantedPrefix)
123+
commentContent = strings.TrimSpace(commentContent)
124+
commentContent = strings.TrimSuffix(commentContent, ".")
125+
126+
if commentContent == "" {
127+
lowerEntity := strings.ToLower(entityKind)
128+
errorString := fmt.Sprintf("%s comment of '%s' should provide a description of the %s, e.g '// %s <%s_description>'",
129+
entityKind, entityName, lowerEntity, wantedPrefix, lowerEntity)
130+
return false, errorString
131+
}
132+
133+
// Check if comment ends in a period
134+
if !strings.HasSuffix(trimmedComment, ".") {
135+
return false, fmt.Sprintf("%s comment for %s '%s' should end with a period (.)",
136+
entityKind, lowerEntity, entityName)
137+
}
138+
139+
return true, ""
140+
}

0 commit comments

Comments
 (0)