diff --git a/activity.go b/activity.go index 9e6c26d..d3aaf48 100644 --- a/activity.go +++ b/activity.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "strings" "time" @@ -732,6 +733,24 @@ func (a *Activity) UnmarshalJSON(data []byte) error { return loadActivity(val, a) } +func fmtActivityProps(w io.Writer) func(*Activity) error { + return func(a *Activity) error { + if !IsNil(a.Object) { + io.WriteString(w, fmt.Sprintf(" object: %s", a.Object)) + } + return OnIntransitiveActivity(a, fmtIntransitiveActivityProps(w)) + } +} + +func (a Activity) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] {", a, a.Type)) + fmtActivityProps(s)(&a) + io.WriteString(s, " }") + } +} + // ToActivity func ToActivity(it Item) (*Activity, error) { switch i := it.(type) { diff --git a/actor.go b/actor.go index 615ddf8..9b8bf09 100644 --- a/actor.go +++ b/actor.go @@ -5,6 +5,7 @@ import ( "encoding/gob" "encoding/json" "fmt" + "io" "reflect" "time" @@ -413,6 +414,13 @@ func (a Actor) MarshalJSON() ([]byte, error) { return nil, nil } +func (a Actor) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { }", a, a.Type)) + } +} + // Endpoints a json object which maps additional (typically server/domain-wide) // endpoints which may be useful either for this actor or someone referencing this actor. // This mapping may be nested inside the actor document as the value or may be a link to diff --git a/collection.go b/collection.go index bb3df25..c17517a 100644 --- a/collection.go +++ b/collection.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" "unsafe" @@ -314,6 +315,13 @@ func (c *Collection) GobDecode(data []byte) error { return unmapCollectionProperties(mm, c) } +func (c Collection) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { totalItems: %d }", c, c.Type, c.TotalItems)) + } +} + // ToCollection func ToCollection(it Item) (*Collection, error) { switch i := it.(type) { diff --git a/collection_page.go b/collection_page.go index 011310c..556bf3e 100644 --- a/collection_page.go +++ b/collection_page.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" @@ -410,3 +411,10 @@ func (c CollectionPage) Equals(with Item) bool { }) return result } + +func (c CollectionPage) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { totalItems: %d }", c, c.Type, c.TotalItems)) + } +} diff --git a/intransitive_activity.go b/intransitive_activity.go index 32d0e76..574c0c8 100644 --- a/intransitive_activity.go +++ b/intransitive_activity.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" "unsafe" @@ -341,3 +342,31 @@ func (i IntransitiveActivity) Equals(with Item) bool { } return result } + +func fmtIntransitiveActivityProps(w io.Writer) func(*IntransitiveActivity) error { + return func(ia *IntransitiveActivity) error { + if !IsNil(ia.Actor) { + io.WriteString(w, fmt.Sprintf(" actor: %s", ia.Actor)) + } + if !IsNil(ia.Target) { + io.WriteString(w, fmt.Sprintf(" target: %s", ia.Target)) + } + if !IsNil(ia.Result) { + io.WriteString(w, fmt.Sprintf(" result: %s", ia.Result)) + } + if !IsNil(ia.Origin) { + io.WriteString(w, fmt.Sprintf(" origin: %s", ia.Origin)) + } + if !IsNil(ia.Instrument) { + io.WriteString(w, fmt.Sprintf(" instrument: %s", ia.Instrument)) + } + return OnObject(ia, fmtObjectProps(w)) + } +} + +func (i IntransitiveActivity) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { }", i, i.Type)) + } +} diff --git a/link.go b/link.go index 1887427..73e9fd2 100644 --- a/link.go +++ b/link.go @@ -3,6 +3,9 @@ package activitypub import ( "bytes" "encoding/gob" + "fmt" + "io" + "github.com/valyala/fastjson" ) @@ -155,3 +158,10 @@ func (l *Link) GobDecode(data []byte) error { } return unmapLinkProperties(mm, l) } + +func (l Link) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { }", l, l.Type)) + } +} diff --git a/natural_language_values.go b/natural_language_values.go index 21a75e4..defe0e0 100644 --- a/natural_language_values.go +++ b/natural_language_values.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "strconv" "strings" @@ -134,6 +135,23 @@ func (n NaturalLanguageValues) MarshalText() ([]byte, error) { return nil, nil } +func (n NaturalLanguageValues) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'q': + io.WriteString(s, "[") + for _, nn := range n { + nn.Format(s, verb) + } + io.WriteString(s, "]") + case 'v': + io.WriteString(s, "[") + for _, nn := range n { + nn.Format(s, verb) + } + io.WriteString(s, "]") + } +} + // Append is syntactic sugar for resizing the NaturalLanguageValues map // and appending an element func (n *NaturalLanguageValues) Append(lang LangRef, value Content) error { @@ -165,6 +183,23 @@ func (l LangRefValue) String() string { return fmt.Sprintf("%s[%s]", l.Value, l.Ref) } +func (l LangRefValue) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'q': + if l.Ref == NilLangRef { + io.WriteString(s, string(l.Value)) + } else { + io.WriteString(s, fmt.Sprintf("%q[%s]", l.Value, l.Ref)) + } + case 'v': + if l.Ref == NilLangRef { + io.WriteString(s, fmt.Sprintf("%q", string(l.Value))) + } else { + io.WriteString(s, fmt.Sprintf("%q[%s]", string(l.Value), l.Ref)) + } + } +} + // UnmarshalJSON decodes an incoming JSON document into the receiver object. func (l *LangRefValue) UnmarshalJSON(data []byte) error { p := fastjson.Parser{} @@ -368,6 +403,15 @@ func (c Content) Equals(other Content) bool { return bytes.Equal(c, other) } +func (c Content) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'q': + io.WriteString(s, string(c)) + case 'v': + io.WriteString(s, fmt.Sprintf("%q", string(c))) + } +} + func unescape(b []byte) []byte { // FIXME(marius): I feel like I'm missing something really obvious about encoding/decoding from Json regarding // escape characters, and that this function is just a hack. Be better future Marius, find the real problem! diff --git a/natural_language_values_test.go b/natural_language_values_test.go index 39f1e99..5f4ec8f 100644 --- a/natural_language_values_test.go +++ b/natural_language_values_test.go @@ -263,7 +263,7 @@ func TestNaturalLanguageValue_MarshalText(t *testing.T) { if j == nil { t.Errorf("Error marshaling: nil value returned") } - expected := fmt.Sprintf("\"%s[%s]\"", nlv.Value, nlv.Ref) + expected := fmt.Sprintf("%s[%s]", nlv.Value, nlv.Ref) if string(j) != expected { t.Errorf("Wrong value: %s, expected %s", j, expected) } diff --git a/object.go b/object.go index 3b9dde9..1140318 100644 --- a/object.go +++ b/object.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "strings" "time" @@ -342,6 +343,183 @@ func (o *Object) GobDecode(data []byte) error { return unmapObjectProperties(mm, o) } +func fmtObjectProps(w io.Writer) func(*Object) error { + return func(o *Object) error { + if len(o.Name) > 0 { + n, _ := io.WriteString(w, fmt.Sprintf("%s: [%s]", "name", o.Name)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if len(o.Summary) > 0 { + n, _ := io.WriteString(w, fmt.Sprintf("%s: [%s]", "summary", o.Summary)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if len(o.Content) > 0 { + n, _ := io.WriteString(w, fmt.Sprintf("%s: [%s]", "content", o.Content)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Attachment) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "attachment", o.Attachment)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.AttributedTo) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "attributedTo", o.AttributedTo)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Audience) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "audience", o.Audience)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Context) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "context", o.Context)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Generator) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "generator", o.Generator)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Icon) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "icon", o.Icon)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Image) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "image", o.Image)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.InReplyTo) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "inReplyTo", o.InReplyTo)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Location) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "location", o.Location)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Preview) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "preview", o.Preview)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Replies) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "replies", o.Replies)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Tag) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "tag", o.Tag)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.URL) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "url", o.URL)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.To) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "to", o.To)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Bto) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "bto", o.Bto)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.CC) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "cc", o.CC)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.BCC) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "bcc", o.BCC)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !o.Published.IsZero() { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "published", o.Published)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !o.Updated.IsZero() { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "updated", o.Updated)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !o.StartTime.IsZero() { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "startTime", o.StartTime)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !o.EndTime.IsZero() { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "endTime", o.EndTime)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if o.Duration != 0 { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "duration", o.Duration)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Likes) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "likes", o.Likes)) + if n > 0 { + io.WriteString(w, ", ") + } + } + if !IsNil(o.Shares) { + n, _ := io.WriteString(w, fmt.Sprintf("%s: %s", "shares", o.Shares)) + if n > 0 { + io.WriteString(w, ", ") + } + } + return nil + } +} + +func (o Object) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { ", o, o.Type)) + fmtObjectProps(s)(&o) + io.WriteString(s, " }") + } +} + // Recipients performs recipient de-duplication on the Object's To, Bto, CC and BCC properties func (o *Object) Recipients() ItemCollection { var aud ItemCollection diff --git a/ordered_collection.go b/ordered_collection.go index 3cb29ca..5fa6a2b 100644 --- a/ordered_collection.go +++ b/ordered_collection.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" "unsafe" @@ -483,3 +484,10 @@ func (o OrderedCollection) Equals(with Item) bool { }) return result } + +func (o OrderedCollection) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { totalItems: %d }", o, o.Type, o.TotalItems)) + } +} diff --git a/ordered_collection_page.go b/ordered_collection_page.go index e56f7d3..73487c2 100644 --- a/ordered_collection_page.go +++ b/ordered_collection_page.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" @@ -368,3 +369,10 @@ func (o OrderedCollectionPage) Equals(with Item) bool { }) return result } + +func (o OrderedCollectionPage) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { totalItems: %d }", o, o.Type, o.TotalItems)) + } +} diff --git a/place.go b/place.go index 694961e..9387888 100644 --- a/place.go +++ b/place.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" "unsafe" @@ -251,6 +252,13 @@ func (p *Place) Clean() { p.Bto = nil } +func (p Place) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { }", p, p.Type)) + } +} + // ToPlace func ToPlace(it Item) (*Place, error) { switch i := it.(type) { diff --git a/profile.go b/profile.go index aecae1e..739cc51 100644 --- a/profile.go +++ b/profile.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" "unsafe" @@ -223,6 +224,13 @@ func (p *Profile) Clean() { p.Bto = nil } +func (p Profile) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { }", p, p.Type)) + } +} + // ToProfile tries to convert the it Item to a Profile object func ToProfile(it Item) (*Profile, error) { switch i := it.(type) { diff --git a/question.go b/question.go index 05a53b4..08fddda 100644 --- a/question.go +++ b/question.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" @@ -228,6 +229,13 @@ func (q *Question) GobDecode(data []byte) error { return unmapQuestionProperties(mm, q) } +func (q Question) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { }", q, q.Type)) + } +} + // QuestionNew initializes a Question activity func QuestionNew(id ID) *Question { q := Question{ID: id, Type: QuestionType} diff --git a/relationship.go b/relationship.go index 9fa3dd4..cd724dd 100644 --- a/relationship.go +++ b/relationship.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" "unsafe" @@ -240,6 +241,13 @@ func (r *Relationship) Clean() { r.Bto = nil } +func (r Relationship) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { }", r, r.Type)) + } +} + // ToRelationship tries to convert the it Item to a Relationship object. func ToRelationship(it Item) (*Relationship, error) { switch i := it.(type) { diff --git a/tombstone.go b/tombstone.go index 7046d85..58ab3ac 100644 --- a/tombstone.go +++ b/tombstone.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "fmt" + "io" "reflect" "time" "unsafe" @@ -229,6 +230,13 @@ func (t *Tombstone) Clean() { t.Bto = nil } +func (t Tombstone) Format(s fmt.State, verb rune) { + switch verb { + case 's', 'v': + io.WriteString(s, fmt.Sprintf("%T[%s] { formerType: %q }", t, t.Type, t.FormerType)) + } +} + // ToTombstone func ToTombstone(it Item) (*Tombstone, error) { switch i := it.(type) {