Jelajahi Sumber

Improve the godoc

Rob Figueiredo 13 tahun lalu
induk
melakukan
9f40a4b026
4 mengubah file dengan 56 tambahan dan 28 penghapusan
  1. 24 7
      cron.go
  2. 16 7
      parser.go
  3. 5 5
      parser_test.go
  4. 11 9
      schedule.go

+ 24 - 7
cron.go

@@ -8,8 +8,8 @@ import (
 )
 
 // Cron keeps track of any number of entries, invoking the associated func as
-// specified by the spec.  See http://en.wikipedia.org/wiki/Cron
-// It may be started and stopped.
+// specified by the schedule. It may be started, stopped, and the entries may
+// be inspected while running.
 type Cron struct {
 	entries  []*Entry
 	stop     chan struct{}
@@ -18,19 +18,30 @@ type Cron struct {
 	running  bool
 }
 
-// Simple interface for submitted cron jobs.
+// Job is an interface for submitted cron jobs.
 type Job interface {
 	Run()
 }
 
-// A cron entry consists of a schedule and the func to execute on that schedule.
+// Entry consists of a schedule and the func to execute on that schedule.
 type Entry struct {
+	// The schedule on which this job should be run.
 	*Schedule
+
+	// The next time the job will run. This is the zero time if Cron has not been
+	// started or this entry's schedule is unsatisfiable
 	Next time.Time
+
+	// The last time this job was run. This is the zero time if the job has never
+	// been run.
 	Prev time.Time
-	Job  Job
+
+	// The Job to run.
+	Job Job
 }
 
+// byTime is a wrapper for sorting the entry array by time
+// (with zero time at the end).
 type byTime []*Entry
 
 func (s byTime) Len() int      { return len(s) }
@@ -48,6 +59,7 @@ func (s byTime) Less(i, j int) bool {
 	return s[i].Next.Before(s[j].Next)
 }
 
+// New returns a new Cron job runner.
 func New() *Cron {
 	return &Cron{
 		entries:  nil,
@@ -58,15 +70,17 @@ func New() *Cron {
 	}
 }
 
-// Provide a default implementation for those that want to run a simple func.
+// jobAdapter provides a default implementation for wrapping a simple func.
 type jobAdapter func()
 
 func (r jobAdapter) Run() { r() }
 
+// AddFunc adds a func to the Cron to be run on the given schedule.
 func (c *Cron) AddFunc(spec string, cmd func()) {
 	c.AddJob(spec, jobAdapter(cmd))
 }
 
+// AddFunc adds a Job to the Cron to be run on the given schedule.
 func (c *Cron) AddJob(spec string, cmd Job) {
 	entry := &Entry{
 		Schedule: Parse(spec),
@@ -80,7 +94,7 @@ func (c *Cron) AddJob(spec string, cmd Job) {
 	c.add <- entry
 }
 
-// Return a snapshot of the cron entries.
+// Entries returns a snapshot of the cron entries.
 func (c *Cron) Entries() []*Entry {
 	if c.running {
 		c.snapshot <- nil
@@ -90,6 +104,7 @@ func (c *Cron) Entries() []*Entry {
 	return c.entrySnapshot()
 }
 
+// Start the cron scheduler in its own go-routine.
 func (c *Cron) Start() {
 	c.running = true
 	go c.run()
@@ -142,11 +157,13 @@ func (c *Cron) run() {
 	}
 }
 
+// Stop the cron scheduler.
 func (c *Cron) Stop() {
 	c.stop <- struct{}{}
 	c.running = false
 }
 
+// entrySnapshot returns a copy of the current cron entry list.
 func (c *Cron) entrySnapshot() []*Entry {
 	entries := []*Entry{}
 	for _, e := range c.entries {

+ 16 - 7
parser.go

@@ -7,8 +7,8 @@ import (
 	"strings"
 )
 
-// Returns a new crontab schedule representing the given spec.
-// Panics with a descriptive error if the spec is not valid.
+// Parse returns a new crontab schedule representing the given spec.
+// It panics with a descriptive error if the spec is not valid.
 func Parse(spec string) *Schedule {
 	if spec[0] == '@' {
 		return parseDescriptor(spec)
@@ -38,8 +38,8 @@ func Parse(spec string) *Schedule {
 	return schedule
 }
 
-// Return an Int with the bits set representing all of the times that the field represents.
-// A "field" is a comma-separated list of "ranges".
+// getField returns an Int with the bits set representing all of the times that
+// the field represents.  A "field" is a comma-separated list of "ranges".
 func getField(field string, r bounds) uint64 {
 	// list = range {"," range}
 	var bits uint64
@@ -50,8 +50,10 @@ func getField(field string, r bounds) uint64 {
 	return bits
 }
 
+// getRange returns the bits indicated by the given expression:
+//   number | number "-" number [ "/" number ]
 func getRange(expr string, r bounds) uint64 {
-	// number | number "-" number [ "/" number ]
+
 	var (
 		start, end, step uint
 		rangeAndStep     = strings.Split(expr, "/")
@@ -63,7 +65,7 @@ func getRange(expr string, r bounds) uint64 {
 	if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" {
 		start = r.min
 		end = r.max
-		extra_star = STAR_BIT
+		extra_star = starBit
 	} else {
 		start = parseIntOrName(lowAndHigh[0], r.names)
 		switch len(lowAndHigh) {
@@ -103,6 +105,7 @@ func getRange(expr string, r bounds) uint64 {
 	return getBits(start, end, step) | extra_star
 }
 
+// parseIntOrName returns the (possibly-named) integer contained in expr.
 func parseIntOrName(expr string, names map[string]uint) uint {
 	if names != nil {
 		if namedInt, ok := names[strings.ToLower(expr)]; ok {
@@ -112,6 +115,7 @@ func parseIntOrName(expr string, names map[string]uint) uint {
 	return mustParseInt(expr)
 }
 
+// mustParseInt parses the given expression as an int or panics.
 func mustParseInt(expr string) uint {
 	num, err := strconv.Atoi(expr)
 	if err != nil {
@@ -124,6 +128,7 @@ func mustParseInt(expr string) uint {
 	return uint(num)
 }
 
+// getBits sets all bits in the range [min, max], modulo the given step size.
 func getBits(min, max, step uint) uint64 {
 	var bits uint64
 
@@ -139,14 +144,18 @@ func getBits(min, max, step uint) uint64 {
 	return bits
 }
 
+// all returns all bits within the given bounds.  (plus the star bit)
 func all(r bounds) uint64 {
-	return getBits(r.min, r.max, 1) | STAR_BIT
+	return getBits(r.min, r.max, 1) | starBit
 }
 
+// first returns bits with only the first (minimum) value set.
 func first(r bounds) uint64 {
 	return getBits(r.min, r.min, 1)
 }
 
+// parseDescriptor returns a pre-defined schedule for the expression, or panics
+// if none matches.
 func parseDescriptor(spec string) *Schedule {
 	switch spec {
 	case "@yearly", "@annually":

+ 5 - 5
parser_test.go

@@ -23,8 +23,8 @@ func TestRange(t *testing.T) {
 		{"5-7/2", 0, 7, 1<<5 | 1<<7},
 		{"5-7/1", 0, 7, 1<<5 | 1<<6 | 1<<7},
 
-		{"*", 1, 3, 1<<1 | 1<<2 | 1<<3 | STAR_BIT},
-		{"*/2", 1, 3, 1<<1 | 1<<3 | STAR_BIT},
+		{"*", 1, 3, 1<<1 | 1<<2 | 1<<3 | starBit},
+		{"*/2", 1, 3, 1<<1 | 1<<3 | starBit},
 	}
 
 	for _, c := range ranges {
@@ -68,10 +68,10 @@ func TestBits(t *testing.T) {
 	}
 
 	for _, c := range allBits {
-		actual := all(c.r) // all() adds the STAR_BIT, so compensate for that..
-		if c.expected|STAR_BIT != actual {
+		actual := all(c.r) // all() adds the starBit, so compensate for that..
+		if c.expected|starBit != actual {
 			t.Errorf("%d-%d/%d => (expected) %b != %b (actual)",
-				c.r.min, c.r.max, 1, c.expected|STAR_BIT, actual)
+				c.r.min, c.r.max, 1, c.expected|starBit, actual)
 		}
 	}
 

+ 11 - 9
schedule.go

@@ -4,13 +4,13 @@ import (
 	"time"
 )
 
-// A cron schedule that specifies a duty cycle (to the second granularity).
+// Schedule specifies a duty cycle (to the second granularity).
 // Schedules are computed initially and stored as bit sets.
 type Schedule struct {
 	Second, Minute, Hour, Dom, Month, Dow uint64
 }
 
-// A range of acceptable values.
+// bounds provides a range of acceptable values (plus a map of name to value).
 type bounds struct {
 	min, max uint
 	names    map[string]uint
@@ -49,21 +49,21 @@ var (
 
 const (
 	// Set the top bit if a star was included in the expression.
-	STAR_BIT = 1 << 63
+	starBit = 1 << 63
 )
 
-// Return the next time this schedule is activated, greater than the
-// given time.  If no time can be found to satisfy the schedule, return the
-// zero time.
+// Next returns the next time this schedule is activated, greater than the given
+// time.  If no time can be found to satisfy the schedule, return the zero time.
 func (s *Schedule) Next(t time.Time) time.Time {
+	// General approach:
 	// For Month, Day, Hour, Minute, Second:
-	// Check if the current value matches.  If yes, do nothing for that field.
+	// Check if the time value matches.  If yes, continue to the next field.
 	// If the field doesn't match the schedule, then increment the field until it matches.
 	// While incrementing the field, a wrap-around brings it back to the beginning
 	// of the field list (since it is necessary to re-verify previous field
 	// values)
 
-	// Start at the earliest possible time.
+	// Start at the earliest possible time (the upcoming second).
 	t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond)
 
 	// This flag indicates whether a field has been incremented.
@@ -146,13 +146,15 @@ WRAP:
 	return t
 }
 
+// dayMatches returns true if the schedule's day-of-week and day-of-month
+// restrictions are satisfied by the given time.
 func dayMatches(s *Schedule, t time.Time) bool {
 	var (
 		domMatch bool = 1<<uint(t.Day())&s.Dom > 0
 		dowMatch bool = 1<<uint(t.Weekday())&s.Dow > 0
 	)
 
-	if s.Dom&STAR_BIT > 0 || s.Dow&STAR_BIT > 0 {
+	if s.Dom&starBit > 0 || s.Dow&starBit > 0 {
 		return domMatch && dowMatch
 	}
 	return domMatch || dowMatch