From 50a8c50726c4fc042fa4df4e10b8ba69860cc1d5 Mon Sep 17 00:00:00 2001 From: Tatsushi Demachi Date: Wed, 20 Aug 2014 22:12:17 +0900 Subject: [PATCH] Add page grouping functions --- hugolib/pageGroup.go | 126 +++++++++++++++++++++++++++++++++++++++++++ hugolib/site_test.go | 67 +++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 hugolib/pageGroup.go diff --git a/hugolib/pageGroup.go b/hugolib/pageGroup.go new file mode 100644 index 000000000..2fd159ab8 --- /dev/null +++ b/hugolib/pageGroup.go @@ -0,0 +1,126 @@ +// Copyright © 2014 Steve Francia . +// +// Licensed under the Simple Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://opensource.org/licenses/Simple-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package hugolib + +import ( + "errors" + "reflect" + "sort" +) + +type PageGroup struct { + Key interface{} + Data Pages +} + +type mapKeyValues []reflect.Value + +func (v mapKeyValues) Len() int { return len(v) } +func (v mapKeyValues) Swap(i, j int) { v[i], v[j] = v[j], v[i] } + +type mapKeyByInt struct{ mapKeyValues } + +func (s mapKeyByInt) Less(i, j int) bool { return s.mapKeyValues[i].Int() < s.mapKeyValues[j].Int() } + +type mapKeyByStr struct{ mapKeyValues } + +func (s mapKeyByStr) Less(i, j int) bool { + return s.mapKeyValues[i].String() < s.mapKeyValues[j].String() +} + +func sortKeys(v []reflect.Value, order string) []reflect.Value { + if len(v) <= 1 { + return v + } + + switch v[0].Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if order == "desc" { + sort.Sort(sort.Reverse(mapKeyByInt{v})) + } else { + sort.Sort(mapKeyByInt{v}) + } + case reflect.String: + if order == "desc" { + sort.Sort(sort.Reverse(mapKeyByStr{v})) + } else { + sort.Sort(mapKeyByStr{v}) + } + } + return v +} + +func (p Pages) GroupBy(key, order string) ([]PageGroup, error) { + if len(p) < 1 { + return nil, nil + } + + if order != "asc" && order != "desc" { + return nil, errors.New("order argument must be 'asc' or 'desc'") + } + + ppt := reflect.TypeOf(&Page{}) + ft, ok := ppt.Elem().FieldByName(key) + if !ok { + return nil, errors.New("No such field in Page struct") + } + tmp := reflect.MakeMap(reflect.MapOf(ft.Type, reflect.SliceOf(ppt))) + + for _, e := range p { + ppv := reflect.ValueOf(e) + fv := ppv.Elem().FieldByName(key) + if !tmp.MapIndex(fv).IsValid() { + tmp.SetMapIndex(fv, reflect.MakeSlice(reflect.SliceOf(ppt), 0, 0)) + } + tmp.SetMapIndex(fv, reflect.Append(tmp.MapIndex(fv), ppv)) + } + + var r []PageGroup + for _, k := range sortKeys(tmp.MapKeys(), order) { + r = append(r, PageGroup{Key: k.Interface(), Data: tmp.MapIndex(k).Interface().([]*Page)}) + } + + return r, nil +} + +func (p Pages) GroupByDate(format, order string) ([]PageGroup, error) { + if len(p) < 1 { + return nil, nil + } + + if order != "asc" && order != "desc" { + return nil, errors.New("order argument must be 'asc' or 'desc'") + } + + sp := p.ByDate() + if order == "desc" { + sp = sp.Reverse() + } + + date := sp[0].Date.Format(format) + var r []PageGroup + r = append(r, PageGroup{Key: date, Data: make(Pages, 0)}) + r[0].Data = append(r[0].Data, sp[0]) + + i := 0 + for _, e := range sp[1:] { + date = e.Date.Format(format) + if r[i].Key.(string) != date { + r = append(r, PageGroup{Key: date}) + i++ + } + r[i].Data = append(r[i].Data, e) + } + return r, nil +} diff --git a/hugolib/site_test.go b/hugolib/site_test.go index ecb81ebf8..5ab09f102 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -483,6 +483,73 @@ func TestOrderedPages(t *testing.T) { } } +var GROUPED_SOURCES = []source.ByteSource{ + {"sect1/doc1.md", WEIGHTED_PAGE_1, "sect1"}, + {"sect1/doc2.md", WEIGHTED_PAGE_2, "sect1"}, + {"sect2/doc3.md", WEIGHTED_PAGE_3, "sect2"}, + {"sect3/doc4.md", WEIGHTED_PAGE_4, "sect3"}, +} + +func TestGroupedPages(t *testing.T) { + files := make(map[string][]byte) + target := &target.InMemoryTarget{Files: files} + + viper.Set("baseurl", "http://auth/bub") + s := &Site{ + Target: target, + Source: &source.InMemorySource{ByteSource: GROUPED_SOURCES}, + } + s.initializeSiteInfo() + + if err := s.CreatePages(); err != nil { + t.Fatalf("Unable to create pages: %s", err) + } + + if err := s.BuildSiteMeta(); err != nil { + t.Fatalf("Unable to build site metadata: %s", err) + } + + rbysection, err := s.Pages.GroupBy("Section", "desc") + if err != nil { + t.Fatalf("Unable to make PageGroup array: %s", err) + } + if rbysection[0].Key != "sect3" { + t.Errorf("PageGroup array in unexpected order. First group key should be '%s', got '%s'", "sect3", rbysection[0].Key) + } + if rbysection[1].Key != "sect2" { + t.Errorf("PageGroup array in unexpected order. Second group key should be '%s', got '%s'", "sect2", rbysection[1].Key) + } + if rbysection[2].Key != "sect1" { + t.Errorf("PageGroup array in unexpected order. Third group key should be '%s', got '%s'", "sect1", rbysection[2].Key) + } + if rbysection[0].Data[0].Title != "Four" { + t.Errorf("PageGroup has an unexpected page. First group's data should have '%s', got '%s'", "Four", rbysection[0].Data[0].Title) + } + if len(rbysection[2].Data) != 2 { + t.Errorf("PageGroup has unexpected number of pages. Third group should have '%d' pages, got '%d' pages", 2, len(rbysection[2].Data)) + } + + bydate, err := s.Pages.GroupByDate("2006-01", "asc") + if err != nil { + t.Fatalf("Unable to make PageGroup array: %s", err) + } + if bydate[0].Key != "2008-01" { + t.Errorf("PageGroup array in unexpected order. First group key should be '%s', got '%s'", "2008-01", bydate[0].Key) + } + if bydate[1].Key != "2012-01" { + t.Errorf("PageGroup array in unexpected order. Second group key should be '%s', got '%s'", "2012-01", bydate[1].Key) + } + if bydate[2].Key != "2012-04" { + t.Errorf("PageGroup array in unexpected order. Third group key should be '%s', got '%s'", "2012-04", bydate[2].Key) + } + if bydate[2].Data[0].Title != "Three" { + t.Errorf("PageGroup has an unexpected page. Third group's data should have '%s', got '%s'", "Three", bydate[2].Data[0].Title) + } + if len(bydate[0].Data) != 2 { + t.Errorf("PageGroup has unexpected number of pages. First group should have '%d' pages, got '%d' pages", 2, len(bydate[2].Data)) + } +} + var PAGE_WITH_WEIGHTED_TAXONOMIES_2 = []byte(`+++ tags = [ "a", "b", "c" ] tags_weight = 22