move: advanced funcs to functional programming
This commit is contained in:
73
27-functional-programming/_legacy/01-variadic-funcs/main.go
Normal file
73
27-functional-programming/_legacy/01-variadic-funcs/main.go
Normal file
@@ -0,0 +1,73 @@
|
||||
// For more tutorials: https://blog.learngoprogramming.com
|
||||
//
|
||||
// Copyright © 2018 Inanc Gumus
|
||||
// Learn Go Programming Course
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
nums := []int{2, 3, 7}
|
||||
fmt.Printf("nums : %d\n", nums)
|
||||
|
||||
n := avgNoVariadic(nums)
|
||||
fmt.Printf("avgNoVariadic : %d\n", n)
|
||||
|
||||
n = avg(2, 3, 7)
|
||||
fmt.Printf("avg(2, 3, 7) : %d\n", n)
|
||||
|
||||
n = avg(2, 3, 7, 8)
|
||||
fmt.Printf("avg(2, 3, 7, 8) : %d\n", n)
|
||||
|
||||
// use ... to pass a slice
|
||||
n = avg(nums...)
|
||||
fmt.Printf("avg(nums...) : %d\n", n)
|
||||
|
||||
// uses the existing slice
|
||||
double(nums...)
|
||||
fmt.Printf("double(nums...) : %d\n", nums)
|
||||
|
||||
// creates a new slice
|
||||
double(4, 6, 14)
|
||||
fmt.Printf("double(4, 6, 14): %d\n", nums)
|
||||
|
||||
// creates a nil slice
|
||||
fmt.Printf("\nmain.nums : %p\n", nums)
|
||||
investigate("passes main.nums", nums...)
|
||||
investigate("passes main.nums", nums...)
|
||||
investigate("passes args", 4, 6, 14)
|
||||
investigate("passes args", 4, 6, 14)
|
||||
investigate("no args")
|
||||
}
|
||||
|
||||
func investigate(msg string, nums ...int) {
|
||||
fmt.Printf("investigate.nums: %12p -> %s\n", nums, msg)
|
||||
|
||||
if len(nums) > 0 {
|
||||
fmt.Printf("\tfirst element: %d\n", nums[0])
|
||||
}
|
||||
}
|
||||
|
||||
func double(nums ...int) {
|
||||
for i := range nums {
|
||||
nums[i] *= 2
|
||||
}
|
||||
}
|
||||
|
||||
func avg(nums ...int) int {
|
||||
return sum(nums) / len(nums)
|
||||
}
|
||||
|
||||
func avgNoVariadic(nums []int) int {
|
||||
return sum(nums) / len(nums)
|
||||
}
|
||||
|
||||
func sum(nums []int) (total int) {
|
||||
for _, n := range nums {
|
||||
total += n
|
||||
}
|
||||
return
|
||||
}
|
||||
52
27-functional-programming/_legacy/02-func-values/main.go
Normal file
52
27-functional-programming/_legacy/02-func-values/main.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// For more tutorials: https://blog.learngoprogramming.com
|
||||
//
|
||||
// Copyright © 2018 Inanc Gumus
|
||||
// Learn Go Programming Course
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type filterFunc func(int) bool
|
||||
|
||||
func main() {
|
||||
signatures()
|
||||
funcValues()
|
||||
}
|
||||
|
||||
func isEven(n int) bool {
|
||||
return n%2 == 0
|
||||
}
|
||||
|
||||
func isOdd(m int) bool {
|
||||
return m%2 == 1
|
||||
}
|
||||
|
||||
func signatures() {
|
||||
fmt.Println("••• FUNC SIGNATURES (TYPES) •••")
|
||||
fmt.Printf("isEven : %T\n", isEven)
|
||||
fmt.Printf("isOdd : %T\n", isOdd)
|
||||
}
|
||||
|
||||
func funcValues() {
|
||||
fmt.Println("\n••• FUNC VALUES (VARS) •••")
|
||||
|
||||
// var value func(int) bool
|
||||
var value filterFunc
|
||||
fmt.Printf("value nil? : %t\n", value == nil)
|
||||
|
||||
value = isEven
|
||||
fmt.Printf("value(2) : %t\n", value(2))
|
||||
fmt.Printf("isEven(2) : %t\n", isEven(2))
|
||||
|
||||
value = isOdd
|
||||
fmt.Printf("value(1) : %t\n", value(1))
|
||||
fmt.Printf("isOdd(1) : %t\n", isOdd(1))
|
||||
|
||||
fmt.Printf("value nil? : %t\n", value == nil)
|
||||
fmt.Printf("value : %p\n", value)
|
||||
fmt.Printf("isEven : %p\n", isEven)
|
||||
fmt.Printf("isOdd : %p\n", isOdd)
|
||||
}
|
||||
82
27-functional-programming/_legacy/03-func-to-func/main.go
Normal file
82
27-functional-programming/_legacy/03-func-to-func/main.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// For more tutorials: https://blog.learngoprogramming.com
|
||||
//
|
||||
// Copyright © 2018 Inanc Gumus
|
||||
// Learn Go Programming Course
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type filterFunc func(int) bool
|
||||
|
||||
func main() {
|
||||
signatures()
|
||||
|
||||
fmt.Println("\n••• WITHOUT FUNC VALUES •••")
|
||||
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
fmt.Printf("evens : %d\n", filterEvens(nums...))
|
||||
fmt.Printf("odds : %d\n", filterOdds(nums...))
|
||||
|
||||
fmt.Println("\n••• FUNC VALUES •••")
|
||||
fmt.Printf("evens : %d\n", filter(isEven, nums...))
|
||||
fmt.Printf("odds : %d\n", filter(isOdd, nums...))
|
||||
|
||||
fmt.Println("\n••• MAPPING •••")
|
||||
fmt.Println(strings.Map(unpunct, "hello!!! HOW ARE YOU???? :))"))
|
||||
fmt.Println(strings.Map(unpunct, "TIME IS UP!"))
|
||||
}
|
||||
|
||||
func unpunct(r rune) rune {
|
||||
if unicode.IsPunct(r) {
|
||||
return -1
|
||||
}
|
||||
return unicode.ToLower(r)
|
||||
}
|
||||
|
||||
func filter(f filterFunc, nums ...int) (filtered []int) {
|
||||
for _, n := range nums {
|
||||
if f(n) {
|
||||
filtered = append(filtered, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func filterOdds(nums ...int) (filtered []int) {
|
||||
for _, n := range nums {
|
||||
if isOdd(n) {
|
||||
filtered = append(filtered, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func filterEvens(nums ...int) (filtered []int) {
|
||||
for _, n := range nums {
|
||||
if isEven(n) {
|
||||
filtered = append(filtered, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func isEven(n int) bool {
|
||||
return n%2 == 0
|
||||
}
|
||||
|
||||
func isOdd(m int) bool {
|
||||
return m%2 == 1
|
||||
}
|
||||
|
||||
func signatures() {
|
||||
fmt.Println("••• FUNC SIGNATURES (TYPES) •••")
|
||||
fmt.Printf("isEven : %T\n", isEven)
|
||||
fmt.Printf("isOdd : %T\n", isOdd)
|
||||
}
|
||||
76
27-functional-programming/_legacy/04-closures/main.go
Normal file
76
27-functional-programming/_legacy/04-closures/main.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// For more tutorials: https://blog.learngoprogramming.com
|
||||
//
|
||||
// Copyright © 2018 Inanc Gumus
|
||||
// Learn Go Programming Course
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type filterFunc func(int) bool
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
fmt.Println("••• FUNC VALUES •••")
|
||||
fmt.Printf("evens : %d\n", filter(isEven, nums...))
|
||||
fmt.Printf("odds : %d\n", filter(isOdd, nums...))
|
||||
fmt.Printf("> 3 : %d\n", filter(greaterThan3, nums...))
|
||||
fmt.Printf("> 6 : %d\n", filter(greaterThan6, nums...))
|
||||
|
||||
// ========================================================================
|
||||
|
||||
fmt.Println("\n••• CLOSURES •••")
|
||||
|
||||
var min int
|
||||
greaterThan := func(n int) bool {
|
||||
return n > min
|
||||
}
|
||||
|
||||
min = 3
|
||||
fmt.Printf("> 3 : %d\n", filter(greaterThan, nums...))
|
||||
|
||||
min = 6
|
||||
fmt.Printf("> 6 : %d\n", filter(greaterThan, nums...))
|
||||
|
||||
// min = 1
|
||||
// fmt.Printf("> 1 : %d\n", filter(greaterThan, nums...))
|
||||
// min = 2
|
||||
// fmt.Printf("> 2 : %d\n", filter(greaterThan, nums...))
|
||||
// min = 3
|
||||
// fmt.Printf("> 3 : %d\n", filter(greaterThan, nums...))
|
||||
|
||||
var filterers []filterFunc
|
||||
for i := 1; i <= 3; i++ {
|
||||
current := i
|
||||
|
||||
filterers = append(filterers, func(n int) bool {
|
||||
min = current
|
||||
return greaterThan(n)
|
||||
})
|
||||
}
|
||||
|
||||
printer(filterers, nums...)
|
||||
}
|
||||
|
||||
func printer(filterers []filterFunc, nums ...int) {
|
||||
for i, filterer := range filterers {
|
||||
fmt.Printf("> %d : %d\n", i+1, filter(filterer, nums...))
|
||||
}
|
||||
}
|
||||
|
||||
func greaterThan6(n int) bool { return n > 6 }
|
||||
func greaterThan3(n int) bool { return n > 3 }
|
||||
func isEven(n int) bool { return n%2 == 0 }
|
||||
func isOdd(m int) bool { return m%2 == 1 }
|
||||
|
||||
func filter(f filterFunc, nums ...int) (filtered []int) {
|
||||
for _, n := range nums {
|
||||
if f(n) {
|
||||
filtered = append(filtered, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// For more tutorials: https://blog.learngoprogramming.com
|
||||
//
|
||||
// Copyright © 2018 Inanc Gumus
|
||||
// Learn Go Programming Course
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type filterFunc func(int) bool
|
||||
|
||||
func main() {
|
||||
fmt.Println("••• HIGHER-ORDER FUNCS •••")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
odd := reverse(reverse(isEven))
|
||||
fmt.Printf("reversed : %t\n", odd(8))
|
||||
|
||||
fmt.Printf("> 3 : %d\n", filter(greater(3), nums...))
|
||||
fmt.Printf("> 6 : %d\n", filter(greater(6), nums...))
|
||||
fmt.Printf("<= 6 : %d\n", filter(lesseq(6), nums...))
|
||||
fmt.Printf("<= 6 : %d\n", filter(reverse(greater(6)), nums...))
|
||||
}
|
||||
|
||||
func reverse(f filterFunc) filterFunc {
|
||||
return func(n int) bool {
|
||||
return !f(n)
|
||||
}
|
||||
}
|
||||
|
||||
func greater(min int) filterFunc {
|
||||
return func(n int) bool {
|
||||
return n > min
|
||||
}
|
||||
}
|
||||
|
||||
func lesseq(max int) filterFunc {
|
||||
return func(n int) bool {
|
||||
return n <= max
|
||||
}
|
||||
}
|
||||
|
||||
func filter(f filterFunc, nums ...int) (filtered []int) {
|
||||
for _, n := range nums {
|
||||
if f(n) {
|
||||
filtered = append(filtered, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func isEven(n int) bool { return n%2 == 0 }
|
||||
func isOdd(m int) bool { return m%2 == 1 }
|
||||
@@ -0,0 +1,97 @@
|
||||
// For more tutorials: https://blog.learngoprogramming.com
|
||||
//
|
||||
// Copyright © 2018 Inanc Gumus
|
||||
// Learn Go Programming Course
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type filterFunc func(int) bool
|
||||
|
||||
func main() {
|
||||
fmt.Println("••• HIGHER-ORDER FUNCS •••")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
odd := reverse(reverse(isEven))
|
||||
fmt.Printf("reversed : %t\n", odd(8))
|
||||
|
||||
fmt.Printf("> 3 : %d\n", filter(greater(3), nums...))
|
||||
fmt.Printf("> 6 : %d\n", filter(greater(6), nums...))
|
||||
fmt.Printf("<= 6 : %d\n", filter(lesseq(6), nums...))
|
||||
fmt.Printf("<= 6 : %d\n", filter(reverse(greater(6)), nums...))
|
||||
|
||||
fmt.Println("\n••• CLOSURES •••")
|
||||
fmt.Printf("uniques : %d\n", filter(uniques(), 1, 1, 2, 3, 3))
|
||||
|
||||
dups := reverse(uniques())
|
||||
fmt.Printf("dups : %v\n", filter(dups, 1, 1, 2, 3, 3))
|
||||
|
||||
dups = reverse(uniques())
|
||||
fmt.Printf("dups dups : %v\n", filter(dups, 1, 1, 2, 3, 3, 3, 3))
|
||||
|
||||
dups = reverse(uniques())
|
||||
out := filter(dups, 1, 1, 2, 3, 3, 3, 3)
|
||||
fmt.Printf("dups uniqs : %v\n", filter(uniques(), out...))
|
||||
|
||||
dups = reverse(uniques())
|
||||
chained := chain(reverse(greater(1)), dups, uniques())
|
||||
fmt.Printf("dups chain : %v\n", filter(chained, 1, 1, 2, 3, 3, 3, 3, 0, 0))
|
||||
}
|
||||
|
||||
func chain(filters ...filterFunc) filterFunc {
|
||||
return func(n int) bool {
|
||||
for _, next := range filters {
|
||||
if !next(n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func uniques() filterFunc {
|
||||
seen := make(map[int]bool)
|
||||
|
||||
return func(n int) (ok bool) {
|
||||
if !seen[n] {
|
||||
seen[n], ok = true, true
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func reverse(f filterFunc) filterFunc {
|
||||
return func(n int) bool {
|
||||
return !f(n)
|
||||
}
|
||||
}
|
||||
|
||||
func greater(min int) filterFunc {
|
||||
return func(n int) bool {
|
||||
return n > min
|
||||
}
|
||||
}
|
||||
|
||||
func lesseq(max int) filterFunc {
|
||||
return func(n int) bool {
|
||||
return n <= max
|
||||
}
|
||||
}
|
||||
|
||||
func filter(f filterFunc, nums ...int) (filtered []int) {
|
||||
for _, n := range nums {
|
||||
if f(n) {
|
||||
filtered = append(filtered, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func isEven(n int) bool { return n%2 == 0 }
|
||||
func isOdd(m int) bool { return m%2 == 1 }
|
||||
20
27-functional-programming/log-parser-exp/field.go
Normal file
20
27-functional-programming/log-parser-exp/field.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// field helps for field parsing
|
||||
type field struct{ err error }
|
||||
|
||||
// uatoi parses an unsigned integer string and saves the error.
|
||||
// it assumes that the val is unsigned.
|
||||
// for ease of usability: it returns an int instead of uint.
|
||||
func (f *field) uatoi(name, val string) int {
|
||||
n, err := strconv.Atoi(val)
|
||||
if n < 0 || err != nil {
|
||||
f.err = fmt.Errorf("incorrect field -> %q = %q", name, val)
|
||||
}
|
||||
return n
|
||||
}
|
||||
15
27-functional-programming/log-parser-exp/filterby.go
Normal file
15
27-functional-programming/log-parser-exp/filterby.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
func filterBy(results []result, filterer filterFunc) []result {
|
||||
out := results[:0]
|
||||
|
||||
for _, r := range results {
|
||||
if !filterer(r) {
|
||||
continue
|
||||
}
|
||||
|
||||
out = append(out, r)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
34
27-functional-programming/log-parser-exp/filters.go
Normal file
34
27-functional-programming/log-parser-exp/filters.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import "strings"
|
||||
|
||||
func noopFilter(r result) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func not(filter filterFunc) filterFunc {
|
||||
return func(r result) bool {
|
||||
return !filter(r)
|
||||
}
|
||||
}
|
||||
|
||||
func domainExtFilter(domains ...string) filterFunc {
|
||||
return func(r result) bool {
|
||||
for _, domain := range domains {
|
||||
if strings.HasSuffix(r.domain, "."+domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func domainFilter(domain string) filterFunc {
|
||||
return func(r result) bool {
|
||||
return strings.Contains(r.domain, domain)
|
||||
}
|
||||
}
|
||||
|
||||
func orgDomainsFilter(r result) bool {
|
||||
return strings.HasSuffix(r.domain, ".org")
|
||||
}
|
||||
17
27-functional-programming/log-parser-exp/groupby.go
Normal file
17
27-functional-programming/log-parser-exp/groupby.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
func groupBy(results []result, keyer groupFunc) []result {
|
||||
grouped := make(map[string]result, len(results))
|
||||
|
||||
for _, cur := range results {
|
||||
key := keyer(cur)
|
||||
grouped[key] = cur.add(grouped[key])
|
||||
}
|
||||
|
||||
out := results[:0]
|
||||
for _, r := range grouped {
|
||||
out = append(out, r)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
21
27-functional-programming/log-parser-exp/groupers.go
Normal file
21
27-functional-programming/log-parser-exp/groupers.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
// domainGrouper groups by domain.
|
||||
// but it keeps the other fields.
|
||||
// for example: it returns pages as well, but you shouldn't use them.
|
||||
// exercise: write a function that erases superfluous data.
|
||||
func domainGrouper(r result) string {
|
||||
return r.domain
|
||||
}
|
||||
|
||||
func pageGrouper(r result) string {
|
||||
return r.domain + r.page
|
||||
}
|
||||
|
||||
// you could have created a noopGrouper as well
|
||||
// but it's not necessary i think (map allocation)
|
||||
func noopGrouper(r result) string {
|
||||
// with something like:
|
||||
// return randomStrings()
|
||||
return ""
|
||||
}
|
||||
16
27-functional-programming/log-parser-exp/log.txt
Normal file
16
27-functional-programming/log-parser-exp/log.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
learngoprogramming.com.tr / 10 5
|
||||
learngoprogramming.com /courses 15 10
|
||||
learngoprogramming.com /courses 10 5
|
||||
learngoprogramming.com /articles 20 15
|
||||
learngoprogramming.com /articles 5 2
|
||||
golang.org / 40 20
|
||||
golang.org / 20 10
|
||||
golang.org /blog 45 25
|
||||
golang.org /blog 15 5
|
||||
blog.golang.org /courses 60 30
|
||||
blog.golang.org /courses 30 20
|
||||
blog.golang.org /updates 20 10
|
||||
blog.golang.org /reference 65 35
|
||||
blog.golang.org /reference 15 5
|
||||
inanc.io /about 30 15
|
||||
inanc.io /about 70 35
|
||||
16
27-functional-programming/log-parser-exp/log_err_missing.txt
Normal file
16
27-functional-programming/log-parser-exp/log_err_missing.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
learngoprogramming.com / 10 5
|
||||
learngoprogramming.com /courses 15 10
|
||||
learngoprogramming.com /courses 10 5
|
||||
learngoprogramming.com /articles 20 15
|
||||
learngoprogramming.com /articles 5 2
|
||||
golang.org / 40 20
|
||||
golang.org / 20 10
|
||||
golang.org /blog 45 25
|
||||
golang.org /blog 15 5
|
||||
blog.golang.org /updates
|
||||
blog.golang.org /updates 30 20
|
||||
blog.golang.org /updates 20 10
|
||||
blog.golang.org /reference 65 35
|
||||
blog.golang.org /reference 15 5
|
||||
inanc.io /about 30 15
|
||||
inanc.io /about 70 35
|
||||
@@ -0,0 +1,16 @@
|
||||
learngoprogramming.com / 10 5
|
||||
learngoprogramming.com /courses 15 10
|
||||
learngoprogramming.com /courses 10 5
|
||||
learngoprogramming.com /articles 20 15
|
||||
learngoprogramming.com /articles 5 2
|
||||
golang.org / 40 20
|
||||
golang.org / 20 10
|
||||
golang.org /blog 45 -250
|
||||
golang.org /blog 15 5
|
||||
blog.golang.org /updates 60 30
|
||||
blog.golang.org /updates 30 20
|
||||
blog.golang.org /updates 20 10
|
||||
blog.golang.org /reference 65 35
|
||||
blog.golang.org /reference 15 5
|
||||
inanc.io /about 30 15
|
||||
inanc.io /about 70 35
|
||||
16
27-functional-programming/log-parser-exp/log_err_str.txt
Normal file
16
27-functional-programming/log-parser-exp/log_err_str.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
learngoprogramming.com / 10 5
|
||||
learngoprogramming.com /courses 15 10
|
||||
learngoprogramming.com /courses 10 5
|
||||
learngoprogramming.com /articles 20 15
|
||||
learngoprogramming.com /articles 5 2
|
||||
golang.org / 40 TWENTY
|
||||
golang.org / 20 10
|
||||
golang.org /blog 45 25
|
||||
golang.org /blog 15 5
|
||||
blog.golang.org /updates 60 30
|
||||
blog.golang.org /updates 30 20
|
||||
blog.golang.org /updates 20 10
|
||||
blog.golang.org /reference 65 35
|
||||
blog.golang.org /reference 15 5
|
||||
inanc.io /about 30 15
|
||||
inanc.io /about 70 35
|
||||
49
27-functional-programming/log-parser-exp/main.go
Normal file
49
27-functional-programming/log-parser-exp/main.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// For more tutorials: https://blog.learngoprogramming.com
|
||||
//
|
||||
// Copyright © 2018 Inanc Gumus
|
||||
// Learn Go Programming Course
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer recoverErr()
|
||||
|
||||
_, err := newReport().
|
||||
from(os.Stdin).
|
||||
to(os.Stdout).
|
||||
retrieveFrom(textReader).
|
||||
filterBy(orgDomainsFilter).
|
||||
// filterBy(not(domainExtFilter("org", "io"))).
|
||||
// groupBy(pageGrouper).
|
||||
groupBy(domainGrouper).
|
||||
writeTo(textWriter).
|
||||
run()
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("> Err:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func recoverErr() {
|
||||
val := recover()
|
||||
|
||||
if val == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err, ok := val.(string); ok {
|
||||
fmt.Println("> Error occurred:", err)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
newReport -> stats.NewReport().
|
||||
Result -> stats.Record
|
||||
*/
|
||||
85
27-functional-programming/log-parser-exp/report.go
Normal file
85
27-functional-programming/log-parser-exp/report.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package main
|
||||
|
||||
import "io"
|
||||
|
||||
type (
|
||||
parserFunc func(io.Reader) ([]result, error)
|
||||
filterFunc func(result) bool
|
||||
groupFunc func(result) string
|
||||
outputFunc func(io.Writer, []result) error
|
||||
)
|
||||
|
||||
type report struct {
|
||||
input io.Reader
|
||||
output io.Writer
|
||||
parser parserFunc
|
||||
filterer filterFunc
|
||||
grouper groupFunc
|
||||
outputter outputFunc
|
||||
}
|
||||
|
||||
func newReport() *report {
|
||||
return &report{
|
||||
// parser: textParser,
|
||||
filterer: noopFilter,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *report) from(reader io.Reader) *report {
|
||||
r.input = reader
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *report) to(writer io.Writer) *report {
|
||||
r.output = writer
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *report) retrieveFrom(fn parserFunc) *report {
|
||||
r.parser = fn
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *report) filterBy(fn filterFunc) *report {
|
||||
r.filterer = fn
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *report) groupBy(fn groupFunc) *report {
|
||||
r.grouper = fn
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *report) writeTo(fn outputFunc) *report {
|
||||
r.outputter = fn
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *report) run() ([]result, error) {
|
||||
if r.parser == nil {
|
||||
panic("report retriever cannot be nil")
|
||||
}
|
||||
|
||||
results, err := r.parser(r.input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// noop if filterer is nil
|
||||
results = filterBy(results, r.filterer)
|
||||
|
||||
// grouper is more tricky
|
||||
// you don't want to create an unnecessary map
|
||||
if r.grouper != nil {
|
||||
results = groupBy(results, r.grouper)
|
||||
}
|
||||
|
||||
// prefer: noop output
|
||||
if r.output != nil {
|
||||
if err := r.outputter(r.output, results); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
38
27-functional-programming/log-parser-exp/result.go
Normal file
38
27-functional-programming/log-parser-exp/result.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// result stores the parsed result for a domain
|
||||
type result struct {
|
||||
domain string
|
||||
page string
|
||||
visits int
|
||||
uniques int
|
||||
}
|
||||
|
||||
// parseLine parses a log line and returns the parsed result with an error
|
||||
func parseLine(line string) (r result, err error) {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) != 4 {
|
||||
return r, fmt.Errorf("wrong number of fields -> %v", fields)
|
||||
}
|
||||
|
||||
r.domain = fields[0]
|
||||
r.page = fields[1]
|
||||
|
||||
f := new(field)
|
||||
r.visits = f.uatoi("visits", fields[2])
|
||||
r.uniques = f.uatoi("uniques", fields[3])
|
||||
|
||||
return r, f.err
|
||||
}
|
||||
|
||||
// add adds the metrics of another result to the result
|
||||
func (r result) add(other result) result {
|
||||
r.visits += other.visits
|
||||
r.uniques += other.uniques
|
||||
return r
|
||||
}
|
||||
44
27-functional-programming/log-parser-exp/textreader.go
Normal file
44
27-functional-programming/log-parser-exp/textreader.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// For more tutorials: https://blog.learngoprogramming.com
|
||||
//
|
||||
// Copyright © 2018 Inanc Gumus
|
||||
// Learn Go Programming Course
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func textReader(r io.Reader) ([]result, error) {
|
||||
in := bufio.NewScanner(r)
|
||||
return parseText(in)
|
||||
}
|
||||
|
||||
func parseText(in *bufio.Scanner) ([]result, error) {
|
||||
var (
|
||||
results []result
|
||||
lines int
|
||||
)
|
||||
|
||||
for in.Scan() {
|
||||
lines++
|
||||
|
||||
result, err := parseLine(in.Text())
|
||||
if err != nil {
|
||||
// TODO: custom error type for line information
|
||||
return nil, fmt.Errorf("line %d: %v", lines, err)
|
||||
}
|
||||
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
if err := in.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
30
27-functional-programming/log-parser-exp/textwriter.go
Normal file
30
27-functional-programming/log-parser-exp/textwriter.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TODO: sort by result key interfaces section
|
||||
|
||||
func textWriter(w io.Writer, results []result) error {
|
||||
fmt.Fprintf(w, "%-25s %-10s %10s %10s\n",
|
||||
"DOMAINS", "PAGES", "VISITS", "UNIQUES")
|
||||
|
||||
fmt.Fprintln(w, strings.Repeat("-", 58))
|
||||
|
||||
var total result
|
||||
|
||||
for _, r := range results {
|
||||
total = total.add(r)
|
||||
|
||||
fmt.Fprintf(w, "%-25s %-10s %10d %10d\n",
|
||||
r.domain, r.page, r.visits, r.uniques)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "\n%-36s %10d %10d\n",
|
||||
"", total.visits, total.uniques)
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user