From 46a81e29e7f207322126cb311de4985d1840755f Mon Sep 17 00:00:00 2001 From: Eric Duncan Date: Thu, 2 Feb 2017 08:26:51 -0500 Subject: [PATCH] updating examples and documentation --- README.md | 29 +++++++++++++++++++++------- author.go | 2 +- doc.go | 11 ++++++++--- example_test.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++-- examples_test.go | 37 ++++++++++++++++++++++++++++++----- podcast.go | 15 +++++++++++++++ 6 files changed, 126 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 6c676e4..613b799 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,14 @@ * [Examples](#pkg-examples) ## Overview -Package `podcast` is an iTunes and RSS 2.0 podcast generator for GoLang that +Package podcast is an iTunes and RSS 2.0 podcast generator for GoLang that enforces strict compliance by using its simple interface. [![GoDoc](https://godoc.org/github.com/eduncan911/podcast?status.svg)](https://godoc.org/github.com/eduncan911/podcast) [![Build Status](https://travis-ci.org/eduncan911/podcast.svg?branch=master)](https://travis-ci.org/eduncan911/podcast) [![Go Report Card](https://goreportcard.com/badge/github.com/eduncan911/podcast)](https://goreportcard.com/report/github.com/eduncan911/podcast) -Full documentation with detailed examples located at [![GoDoc](https://godoc.org/github.com/eduncan911/podcast?status.svg)](https://godoc.org/github.com/eduncan911/podcast) +Full documentation with detailed examples located at https://godoc.org/github.com/eduncan911/podcast -Usage +### Usage $ go get -u github.com/eduncan911/podcast @@ -24,6 +24,10 @@ The API exposes a number of method receivers on structs that implements the logic required to comply with the specifications and ensure a compliant feed. A number of overrides occur to help with iTunes visibility of your episodes. +Notabily, the [Podcast.AddItem(i Item)](#Podcast.AddItem) function performs most of the +heavy lifting by taking the [Item](#Item) input and performing validation, overrides +and duplciate setters through the feed. + See the detailed Examples in the GoDocs for complete usage. ### Extensiblity @@ -60,6 +64,7 @@ Podcasts: ht * [func (p *Podcast) Bytes() []byte](#Podcast.Bytes) * [func (p *Podcast) Encode(w io.Writer) error](#Podcast.Encode) * [func (p *Podcast) String() string](#Podcast.String) + * [func (p *Podcast) Write(b []byte) (n int, err error)](#Podcast.Write) * [type TextInput](#TextInput) #### Examples @@ -70,7 +75,7 @@ Podcasts: ht * [Podcast.AddImage](#example_Podcast_AddImage) * [Podcast.AddItem](#example_Podcast_AddItem) * [Podcast.Bytes](#example_Podcast_Bytes) -* [Package (Encode)](#example__encode) +* [Package (HttpHandlers)](#example__httpHandlers) #### Package files [author.go](/src/github.com/eduncan911/podcast/author.go) [doc.go](/src/github.com/eduncan911/podcast/doc.go) [enclosure.go](/src/github.com/eduncan911/podcast/enclosure.go) [image.go](/src/github.com/eduncan911/podcast/image.go) [item.go](/src/github.com/eduncan911/podcast/item.go) [itunes.go](/src/github.com/eduncan911/podcast/itunes.go) [podcast.go](/src/github.com/eduncan911/podcast/podcast.go) [textinput.go](/src/github.com/eduncan911/podcast/textinput.go) @@ -80,7 +85,7 @@ Podcasts: ht -## type [Author](/src/target/author.go?s=149:287#L1) +## type [Author](/src/target/author.go?s=150:288#L1) ``` go type Author struct { XMLName xml.Name `xml:"itunes:owner"` @@ -90,7 +95,7 @@ type Author struct { ``` Author represents a named author and email. -For iTunes compiance, both Name and Email are required. +For iTunes compliance, both Name and Email are required. @@ -467,7 +472,7 @@ Encode writes the bytes to the io.Writer stream in RSS 2.0 specification. -### func (\*Podcast) [String](/src/target/podcast.go?s=7091:7124#L223) +### func (\*Podcast) [String](/src/target/podcast.go?s=7291:7324#L229) ``` go func (p *Podcast) String() string ``` @@ -476,6 +481,16 @@ String encodes the Podcast state to a string. +### func (\*Podcast) [Write](/src/target/podcast.go?s=7163:7215#L224) +``` go +func (p *Podcast) Write(b []byte) (n int, err error) +``` +Write implements the io.Writer inteface to write an RSS 2.0 stream +that is compliant to the RSS 2.0 specification. + + + + ## type [TextInput](/src/target/textinput.go?s=77:290#L1) ``` go type TextInput struct { diff --git a/author.go b/author.go index e51589f..bb1fc0b 100644 --- a/author.go +++ b/author.go @@ -4,7 +4,7 @@ import "encoding/xml" // Author represents a named author and email. // -// For iTunes compiance, both Name and Email are required. +// For iTunes compliance, both Name and Email are required. type Author struct { XMLName xml.Name `xml:"itunes:owner"` Name string `xml:"itunes:name"` diff --git a/doc.go b/doc.go index ef536c2..8d1bc7d 100644 --- a/doc.go +++ b/doc.go @@ -1,11 +1,11 @@ -// Package `podcast` is an iTunes and RSS 2.0 podcast generator for GoLang that +// Package podcast is an iTunes and RSS 2.0 podcast generator for GoLang that // enforces strict compliance by using its simple interface. // // [![GoDoc](https://godoc.org/github.com/eduncan911/podcast?status.svg)](https://godoc.org/github.com/eduncan911/podcast) [![Build Status](https://travis-ci.org/eduncan911/podcast.svg?branch=master)](https://travis-ci.org/eduncan911/podcast) [![Go Report Card](https://goreportcard.com/badge/github.com/eduncan911/podcast)](https://goreportcard.com/report/github.com/eduncan911/podcast) // -// Full documentation with detailed examples located at [![GoDoc](https://godoc.org/github.com/eduncan911/podcast?status.svg)](https://godoc.org/github.com/eduncan911/podcast) +// Full documentation with detailed examples located at https://godoc.org/github.com/eduncan911/podcast // -// Usage +// ### Usage // // $ go get -u github.com/eduncan911/podcast // @@ -13,6 +13,11 @@ // logic required to comply with the specifications and ensure a compliant feed. // A number of overrides occur to help with iTunes visibility of your episodes. // +// Notabily, the [Podcast.AddItem(i Item)](#Podcast.AddItem) function performs most of the +// heavy lifting by taking the [Item](#Item) input and performing validation, overrides +// and duplciate setters through the feed. +// +// // See the detailed Examples in the GoDocs for complete usage. // // Extensiblity diff --git a/example_test.go b/example_test.go index 784cc4e..36cfeb2 100644 --- a/example_test.go +++ b/example_test.go @@ -14,12 +14,15 @@ import ( func Example() { now := time.Date(2017, time.February, 1, 7, 51, 0, 0, time.Local) + // instantiate a new Podcast p := podcast.New( "Sample Podcasts", "http://example.com/", "An example Podcast", &now, &now, ) + + // add some channel properties p.ISubtitle = "A simple Podcast" p.AddImage(podcast.Image{URL: "http://example.com/podcast.jpg"}) p.AddAuthor(podcast.Author{ @@ -30,16 +33,18 @@ func Example() { for i := int64(0); i < 2; i++ { n := strconv.FormatInt(i, 10) + // create an Item item := podcast.Item{ Title: "Episode " + n, Description: "Description for Episode " + n, ISubtitle: "A simple episode " + n, PubDate: &now, } + // add a Download to the Item item.AddEnclosure( "http://example.com/"+n+".mp3", podcast.MP3, 55*(i+1)) - // check for validation errors + // add the Item and check for validation errors if _, err := p.AddItem(item); err != nil { os.Stderr.WriteString("item validation error: " + err.Error()) } @@ -98,34 +103,54 @@ func Example() { // } -func Example_encode() { +func Example_httpHandlers() { // ResponseWriter example using Podcast.Encode(w io.Writer). // httpHandler := func(w http.ResponseWriter, r *http.Request) { + // instantiate a new Podcast p := podcast.New( "eduncan911 Podcasts", "http://eduncan911.com/", "An example Podcast", &pubDate, &pubDate, ) + + // add some channel properties + p.AddAuthor(podcast.Author{Name: "Jane Doe", Email: "me@janedoe.com"}) + p.AddImage(podcast.Image{URL: "http://janedoe.com/i.jpg"}) + for i := int64(0); i < 3; i++ { n := strconv.FormatInt(i, 10) + // create an Item item := podcast.Item{ Title: "Episode " + n, Link: "http://example.com/" + n + ".mp3", Description: "Description for Episode " + n, PubDate: &pubDate, } + // add a Download to the Item + item.AddEnclosure( + "http://example.com/"+n+".mp3", podcast.MP3, 55*(i+1)) + + // add the Item and check for validation errors if _, err := p.AddItem(item); err != nil { fmt.Println(item.Title, ": error", err.Error()) return } } + // set the Content Type to that of XML w.Header().Set("Content-Type", "application/xml") + + // finally, Encode and write the Podcast to the ResponseWriter. + // + // a simple pattern is to handle any errors within this check. + // alternatively if using middleware, you can just return + // the Podcast entity as it also implements the io.Writer interface + // that complies with several middleware packages. if err := p.Encode(w); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } @@ -144,13 +169,25 @@ func Example_encode() { // go podcast v1.0.0 (github.com/eduncan911/podcast) // en-us // Wed, 01 Feb 2017 08:21:52 -0500 + // me@janedoe.com (Jane Doe) // Wed, 01 Feb 2017 08:21:52 -0500 + // + // http://janedoe.com/i.jpg + // + // + // + // me@janedoe.com (Jane Doe) + // // // http://example.com/0.mp3 // Episode 0 // http://example.com/0.mp3 // Description for Episode 0 // Wed, 01 Feb 2017 08:21:52 -0500 + // + // me@janedoe.com (Jane Doe) + // + // 55 // // // http://example.com/1.mp3 @@ -158,6 +195,10 @@ func Example_encode() { // http://example.com/1.mp3 // Description for Episode 1 // Wed, 01 Feb 2017 08:21:52 -0500 + // + // me@janedoe.com (Jane Doe) + // + // 110 // // // http://example.com/2.mp3 @@ -165,7 +206,12 @@ func Example_encode() { // http://example.com/2.mp3 // Description for Episode 2 // Wed, 01 Feb 2017 08:21:52 -0500 + // + // me@janedoe.com (Jane Doe) + // + // 165 // // // + } diff --git a/examples_test.go b/examples_test.go index 3c93863..d495fbd 100644 --- a/examples_test.go +++ b/examples_test.go @@ -16,6 +16,7 @@ var ( func ExampleNew() { ti, l, d := "title", "link", "description" + // instantiate a new Podcast p := podcast.New(ti, l, d, &pubDate, &pubDate) fmt.Println(p.Title, p.Link, p.Description, p.Language) @@ -28,6 +29,7 @@ func ExampleNew() { func ExamplePodcast_AddAuthor() { p := podcast.New("title", "link", "description", nil, nil) + // add the Author p.AddAuthor(podcast.Author{ Name: "the name", Email: "me@test.com", @@ -43,20 +45,22 @@ func ExamplePodcast_AddAuthor() { func ExamplePodcast_AddCategory() { p := podcast.New("title", "link", "description", nil, nil) - p.AddCategory("Taby", nil) - p.AddCategory("North American", []string{"Long Hair", "Short Hair"}) - p.AddCategory("Simese", nil) + // add the Category + p.AddCategory("Bombay", nil) + p.AddCategory("American", []string{"Longhair", "Shorthair"}) + p.AddCategory("Siamese", nil) fmt.Println(len(p.ICategories), len(p.ICategories[1].ICategories)) fmt.Println(p.Category) // Output: // 3 2 - // Taby,North American,Simese + // Bombay,American,Siamese } func ExamplePodcast_AddImage() { p := podcast.New("title", "link", "description", nil, nil) + // add the Image p.AddImage(podcast.Image{ URL: "http://example.com/image.jpg", }) @@ -75,6 +79,7 @@ func ExamplePodcast_AddItem() { p.AddAuthor(podcast.Author{Name: "the name", Email: "me@test.com"}) p.AddImage(podcast.Image{URL: "http://example.com/image.jpg"}) + // create an Item item := podcast.Item{ Title: "Episode 1", Description: "Description for Episode 1", @@ -86,6 +91,7 @@ func ExamplePodcast_AddItem() { podcast.MP3, 183, ) + // add the Item if _, err := p.AddItem(item); err != nil { fmt.Println("item validation error: " + err.Error()) } @@ -113,6 +119,9 @@ func ExamplePodcast_Bytes() { "An example Podcast", &pubDate, &pubDate, ) + p.AddAuthor(podcast.Author{Name: "Jane Doe", Email: "me@janedoe.com"}) + p.AddImage(podcast.Image{URL: "http://janedoe.com/i.jpg"}) + for i := int64(0); i < 4; i++ { n := strconv.FormatInt(i, 10) @@ -124,10 +133,11 @@ func ExamplePodcast_Bytes() { } if _, err := p.AddItem(item); err != nil { fmt.Println(item.Title, ": error", err.Error()) - return + break } } + // call Podcast.Bytes() to return a byte array os.Stdout.Write(p.Bytes()) // Output: @@ -140,13 +150,23 @@ func ExamplePodcast_Bytes() { // go podcast v1.0.0 (github.com/eduncan911/podcast) // en-us // Wed, 01 Feb 2017 09:11:00 -0500 + // me@janedoe.com (Jane Doe) // Wed, 01 Feb 2017 09:11:00 -0500 + // + // http://janedoe.com/i.jpg + // + // + // + // me@janedoe.com (Jane Doe) + // // // http://example.com/0.mp3 // Episode 0 // http://example.com/0.mp3 // Description for Episode 0 // Wed, 01 Feb 2017 09:11:00 -0500 + // me@janedoe.com (Jane Doe) + // // // // http://example.com/1.mp3 @@ -154,6 +174,8 @@ func ExamplePodcast_Bytes() { // http://example.com/1.mp3 // Description for Episode 1 // Wed, 01 Feb 2017 09:11:00 -0500 + // me@janedoe.com (Jane Doe) + // // // // http://example.com/2.mp3 @@ -161,6 +183,8 @@ func ExamplePodcast_Bytes() { // http://example.com/2.mp3 // Description for Episode 2 // Wed, 01 Feb 2017 09:11:00 -0500 + // me@janedoe.com (Jane Doe) + // // // // http://example.com/3.mp3 @@ -168,7 +192,10 @@ func ExamplePodcast_Bytes() { // http://example.com/3.mp3 // Description for Episode 3 // Wed, 01 Feb 2017 09:11:00 -0500 + // me@janedoe.com (Jane Doe) + // // // // + } diff --git a/podcast.go b/podcast.go index 8f287de..2a4f435 100644 --- a/podcast.go +++ b/podcast.go @@ -229,6 +229,12 @@ func (p *Podcast) Encode(w io.Writer) error { return encode(w, *p) } +// Write implements the io.Writer inteface to write an RSS 2.0 stream +// that is compliant to the RSS 2.0 specification. +func (p *Podcast) Write(b []byte) (n int, err error) { + return write(b, *p) +} + // String encodes the Podcast state to a string. func (p *Podcast) String() string { b := new(bytes.Buffer) @@ -264,6 +270,15 @@ func encode(w io.Writer, p Podcast) error { return nil } +// write writes a stream using the RSS 2.0 specification. +func write(b []byte, p Podcast) (n int, err error) { + buf := bytes.NewBuffer(b) + if err := encode(buf, p); err != nil { + return 0, errors.Wrap(err, "podcast.write: podcast.encode returned error") + } + return buf.Len(), nil +} + func parseDateRFC1123Z(t *time.Time) string { if t != nil && !t.IsZero() { return t.Format(time.RFC1123Z)