Skip to content

Commit

Permalink
Add piyologutil and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
kaneshin committed Sep 22, 2024
1 parent 03e84c3 commit a5a3c71
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 100 deletions.
101 changes: 49 additions & 52 deletions log_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,23 @@ import (
"strconv"
"strings"
"time"
)

var (
reLog = regexp.MustCompile(`^([0-9:]{5}) (AM|PM)? {1,}([^ ]+)(.*)`)
reAmount = regexp.MustCompile(`^([0-9]+)(.+)$`)
reSleepLength = regexp.MustCompile(`([0-9]+)[^0-9]*([0-9]+)`)
reBodyTemperature = regexp.MustCompile(`([0-9\.]+)(.+)`)
"github.com/kaneshin/piyolog/piyologutil"
)

type (
Log interface {
Type() string
Content() string
Notes() string
CreatedAt() time.Time
}
LogItem struct {
typ string
content string
notes string
createdAt time.Time
}
SleepLog struct {
LogItem
}
WakeUpLog struct {
LogItem
SleepLength time.Duration
}
FormulaLog struct {
LogItem
Amount int
Unit string
}
SolidLog struct {
LogItem
}
BodyTemperatureLog struct {
LogItem
Temperature float64
Unit string
}
)
type Log interface {
Type() string
Content() string
Notes() string
CreatedAt() time.Time
}

type LogItem struct {
typ string
content string
notes string
createdAt time.Time
}

// NewLog returns a log interface.
func NewLog(date time.Time, str string) Log {
Expand All @@ -68,21 +42,18 @@ func NewLog(date time.Time, str string) Log {
return i
}

var reLog = regexp.MustCompile(`^([0-9:]{5} (AM|PM)?) +([^ ]+)(.*)`)

// NewLogItem returns a LogItem value.
func NewLogItem(date time.Time, str string) LogItem {
matches := reLog.FindStringSubmatch(str)
// set createdAt
hm := strings.Split(matches[1], ":")
h, _ := strconv.Atoi(hm[0])
m, _ := strconv.Atoi(hm[1])
if matches[2] == "PM" {
h += 12
}
h, m := piyologutil.HourAndMinuteFromTimeString(matches[1])
const notesSeparator = ` `
list := strings.Split(matches[4], notesSeparator)
return LogItem{
typ: matches[3],
content: strings.TrimSpace(list[0]),
content: strings.Trim(strings.TrimSpace(list[0]), "()"),
notes: strings.TrimSpace(strings.Join(list[1:], notesSeparator)),
createdAt: time.Date(date.Year(), date.Month(), date.Day(), h, m, 0, 0, piyoLoc),
}
Expand All @@ -108,6 +79,14 @@ func (i LogItem) String() string {
return fmt.Sprintf("%s %s %s", i.createdAt.Format("15:04"), i.typ, i.content)
}

type FormulaLog struct {
LogItem
Amount int
Unit string
}

var reAmount = regexp.MustCompile(`^([0-9]+)(.+)$`)

// NewFormulaLog returns a FormulaLog value.
func NewFormulaLog(i LogItem) FormulaLog {
sm := reAmount.FindStringSubmatch(i.content)
Expand All @@ -119,31 +98,49 @@ func NewFormulaLog(i LogItem) FormulaLog {
}
}

type SolidLog struct {
LogItem
}

// NewSolidLog returns a SolidLog value.
func NewSolidLog(i LogItem) SolidLog {
return SolidLog{
LogItem: i,
}
}

type SleepLog struct {
LogItem
}

// NewSleepLog returns a SleepLog value.
func NewSleepLog(i LogItem) SleepLog {
return SleepLog{
LogItem: i,
}
}

type WakeUpLog struct {
LogItem
Duration time.Duration
}

// NewWakeUpLog returns a WakeUpLog value.
func NewWakeUpLog(i LogItem) WakeUpLog {
sm := reSleepLength.FindStringSubmatch(i.content)
h, _ := strconv.Atoi(sm[1])
m, _ := strconv.Atoi(sm[2])
return WakeUpLog{
LogItem: i,
SleepLength: time.Duration(h)*time.Hour + time.Duration(m)*time.Minute,
LogItem: i,
Duration: piyologutil.DurationFromDurationString(i.content),
}
}

type BodyTemperatureLog struct {
LogItem
Temperature float64
Unit string
}

var reBodyTemperature = regexp.MustCompile(`([0-9\.]+)(.+)`)

// NewBodyTemperatureLog returns a BodyTemperatureLog value.
func NewBodyTemperatureLog(i LogItem) BodyTemperatureLog {
sm := reBodyTemperature.FindStringSubmatch(i.content)
Expand Down
4 changes: 2 additions & 2 deletions log_type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ func TestLogType(t *testing.T) {
out: WakeUpLog{
LogItem: LogItem{
typ: "起きる",
content: "(3時間35分)",
content: "3時間35分",
notes: "",
createdAt: time.Date(2023, time.December, 31, 2, 55, 0, 0, piyoLoc),
},
SleepLength: time.Duration(3)*time.Hour + time.Duration(35)*time.Minute,
Duration: time.Duration(3)*time.Hour + time.Duration(35)*time.Minute,
},
},
}
Expand Down
16 changes: 8 additions & 8 deletions piyolog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ func TestParse(t *testing.T) {
WakeUpLog{
LogItem: LogItem{
typ: "起きる",
content: "(0時間50分)",
content: "0時間50分",
createdAt: time.Date(2023, time.December, 31, 14, 45, 0, 0, piyoLoc),
},
SleepLength: time.Duration(50) * time.Minute,
Duration: time.Duration(50) * time.Minute,
},
BodyTemperatureLog{
LogItem: LogItem{
Expand Down Expand Up @@ -249,10 +249,10 @@ func TestParse(t *testing.T) {
WakeUpLog{
LogItem: LogItem{
typ: "起きる",
content: "(8時間40分)",
content: "8時間40分",
createdAt: time.Date(2024, time.August, 1, 4, 15, 0, 0, piyoLoc),
},
SleepLength: time.Duration(8)*time.Hour + time.Duration(40)*time.Minute,
Duration: time.Duration(8)*time.Hour + time.Duration(40)*time.Minute,
},
FormulaLog{
LogItem: LogItem{
Expand All @@ -279,10 +279,10 @@ func TestParse(t *testing.T) {
WakeUpLog{
LogItem: LogItem{
typ: "起きる",
content: "(8時間40分)",
content: "8時間40分",
createdAt: time.Date(2024, time.August, 2, 4, 15, 0, 0, piyoLoc),
},
SleepLength: time.Duration(8)*time.Hour + time.Duration(40)*time.Minute,
Duration: time.Duration(8)*time.Hour + time.Duration(40)*time.Minute,
},
FormulaLog{
LogItem: LogItem{
Expand All @@ -309,10 +309,10 @@ func TestParse(t *testing.T) {
WakeUpLog{
LogItem: LogItem{
typ: "起きる",
content: "(8時間40分)",
content: "8時間40分",
createdAt: time.Date(2024, time.August, 4, 4, 15, 0, 0, piyoLoc),
},
SleepLength: time.Duration(8)*time.Hour + time.Duration(40)*time.Minute,
Duration: time.Duration(8)*time.Hour + time.Duration(40)*time.Minute,
},
FormulaLog{
LogItem: LogItem{
Expand Down
41 changes: 33 additions & 8 deletions piyologutil/piyologutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,22 @@ import (
"time"
)

// Atoi interprets a string s and returns the corresponding integer value.
// If the given string s can't be parsed by the strconv.ParseInt, it returns 0.
func Atoi(s string) int {
v, err := strconv.ParseInt(s, 10, 0)
if err != nil {
return 0
}
return int(v)
}

var reTime = regexp.MustCompile(`^([0-9:]{5}) ?(AM|PM)?$`)

func HourAndMinuteFromTime(str string) (int, int) {
// HourAndMinuteFromTimeString returns two integer values split by a ":" character
// from the given string, such as "20:15" and "07:35 AM". First return value
// represents its hours, second return value represents its minutes.
func HourAndMinuteFromTimeString(str string) (int, int) {
matches := reTime.FindStringSubmatch(str)
hm := strings.Split(matches[1], ":")
h := Atoi(hm[0])
Expand All @@ -20,15 +33,27 @@ func HourAndMinuteFromTime(str string) (int, int) {
return h, m
}

func DurationFromTime(str string) time.Duration {
h, m := HourAndMinuteFromTime(str)
// DurationFromTimeString returns a time.Duration value interpreted by the given string.
func DurationFromTimeString(str string) time.Duration {
h, m := HourAndMinuteFromTimeString(str)
return time.Duration(h)*time.Hour + time.Duration(m)*time.Minute
}

func Atoi(s string) int {
v, err := strconv.ParseInt(s, 10, 0)
if err != nil {
return 0
var reDuration = regexp.MustCompile(`^(([0-9]+)(時間|h))?([0-9]+)(分|m)$`)

// HourAndMinuteFromTime returns two integer values split by a ":" character
// from the given string, such as "8時間15分", "7h40m" and "20m". First return value
// represents its hours, second return value represents its minutes.
func HourAndMinuteFromDurationString(str string) (int, int) {
matches := reDuration.FindStringSubmatch(str)
if len(matches) < 6 {
return 0, 0
}
return int(v)
return Atoi(matches[2]), Atoi(matches[4])
}

// DurationFromDurationString returns a time.Duration value interpreted by the given string.
func DurationFromDurationString(str string) time.Duration {
h, m := HourAndMinuteFromDurationString(str)
return time.Duration(h)*time.Hour + time.Duration(m)*time.Minute
}
74 changes: 44 additions & 30 deletions piyologutil/piyologutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,66 +7,80 @@ import (
"github.com/google/go-cmp/cmp"
)

func Test_HourAndMinuteFromTime(t *testing.T) {
func Test_Atoi(t *testing.T) {
atoitests := []struct {
in string
out1 int
out2 int
in string
out int
}{
{"00:00", 0, 0},
{"11:30", 11, 30},
{"10:25 PM", 22, 25},
{"21:45", 21, 45},
{"0", 0}, {"1", 1}, {"-1", -1},
}

for _, tt := range atoitests {
t.Run(tt.in, func(t *testing.T) {
out1, out2 := HourAndMinuteFromTime(tt.in)
if diff := cmp.Diff(tt.out1, out1); diff != "" {
t.Errorf("%s", diff)
}
if diff := cmp.Diff(tt.out2, out2); diff != "" {
out := Atoi(tt.in)
if diff := cmp.Diff(tt.out, out); diff != "" {
t.Errorf("%s", diff)
}
})
}
}

func Test_DurationFromTime(t *testing.T) {
func Test_HourAndMinute_Duration_FromTimeString(t *testing.T) {
atoitests := []struct {
in string
out time.Duration
in string
out1 int
out2 int
outdur time.Duration
}{
{"00:00", time.Duration(0)},
{"11:30", time.Duration(11)*time.Hour + time.Duration(30)*time.Minute},
{"10:25 PM", time.Duration(22)*time.Hour + time.Duration(25)*time.Minute},
{"21:45", time.Duration(21)*time.Hour + time.Duration(45)*time.Minute},
{"00:00", 0, 0, time.Duration(0)},
{"11:30", 11, 30, time.Duration(11)*time.Hour + time.Duration(30)*time.Minute},
{"10:25 PM", 22, 25, time.Duration(22)*time.Hour + time.Duration(25)*time.Minute},
{"21:45", 21, 45, time.Duration(21)*time.Hour + time.Duration(45)*time.Minute},
}

for _, tt := range atoitests {
t.Run(tt.in, func(t *testing.T) {
out := DurationFromTime(tt.in)
if diff := cmp.Diff(tt.out, out); diff != "" {
out1, out2 := HourAndMinuteFromTimeString(tt.in)
if diff := cmp.Diff(tt.out1, out1); diff != "" {
t.Errorf("%s", diff)
}
if diff := cmp.Diff(tt.out2, out2); diff != "" {
t.Errorf("%s", diff)
}
outdur := DurationFromTimeString(tt.in)
if diff := cmp.Diff(tt.outdur, outdur); diff != "" {
t.Errorf("%s", diff)
}
})
}
}

func Test_Atoi(t *testing.T) {
func Test_HourAndMinute_Duration_FromDurationString(t *testing.T) {
atoitests := []struct {
in string
out int
in string
out1 int
out2 int
outdur time.Duration
}{
{"0", 0},
{"1", 1},
{"-1", -1},
{"0h0m", 0, 0, time.Duration(0)},
{"2h0m", 2, 0, time.Duration(2) * time.Hour},
{"20m", 0, 20, time.Duration(20) * time.Minute},
{"11h30m", 11, 30, time.Duration(11)*time.Hour + time.Duration(30)*time.Minute},
{"10時間25分", 10, 25, time.Duration(10)*time.Hour + time.Duration(25)*time.Minute},
{"21時間45分", 21, 45, time.Duration(21)*time.Hour + time.Duration(45)*time.Minute},
}

for _, tt := range atoitests {
t.Run(tt.in, func(t *testing.T) {
out := Atoi(tt.in)
if diff := cmp.Diff(tt.out, out); diff != "" {
out1, out2 := HourAndMinuteFromDurationString(tt.in)
if diff := cmp.Diff(tt.out1, out1); diff != "" {
t.Errorf("%s", diff)
}
if diff := cmp.Diff(tt.out2, out2); diff != "" {
t.Errorf("%s", diff)
}
outdur := DurationFromDurationString(tt.in)
if diff := cmp.Diff(tt.outdur, outdur); diff != "" {
t.Errorf("%s", diff)
}
})
Expand Down

0 comments on commit a5a3c71

Please sign in to comment.