Add page grouping functions
authorTatsushi Demachi <tdemachi@gmail.com>
Wed, 20 Aug 2014 13:12:17 +0000 (22:12 +0900)
committerspf13 <steve.francia@gmail.com>
Mon, 25 Aug 2014 13:18:52 +0000 (09:18 -0400)
hugolib/pageGroup.go [new file with mode: 0644]
hugolib/site_test.go

diff --git a/hugolib/pageGroup.go b/hugolib/pageGroup.go
new file mode 100644 (file)
index 0000000..2fd159a
--- /dev/null
@@ -0,0 +1,126 @@
+// Copyright © 2014 Steve Francia <spf@spf13.com>.
+//
+// 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
+}
index ecb81ebf8f04b1f18dde1f1528df7ddfeff2f273..5ab09f102ad3c129c26aa1449289a0862039dec3 100644 (file)
@@ -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