summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile9
-rw-r--r--activity.html14
-rw-r--r--activity.lua64
-rw-r--r--generate.lua8
-rw-r--r--spec/activity_spec.lua43
6 files changed, 125 insertions, 14 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2d19fc7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.html
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..35267f8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,9 @@
+all: activity.html
+
+%.html: generate.lua activity.lua
+ lua generate.lua >$@
+
+clean:
+ rm -f *.html
+
+.PHONY: all clean
diff --git a/activity.html b/activity.html
deleted file mode 100644
index 618a3bb..0000000
--- a/activity.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!doctype html>
-<html lang="en">
-<meta charset="utf-8">
-<link rel="stylesheet" type="text/css" href="style.css">
-<title>Activity</title>
-<table class="activity-chart">
-<tr><td class="activity-chart-label"><td><td data-activity-level="1"><td data-activity-level="1"><td data-activity-level="2"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0">
-<tr><td class="activity-chart-label"><span>Mon</span><td><td data-activity-level="0"><td data-activity-level="3"><td data-activity-level="1"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="1"><td data-activity-level="4"><td data-activity-level="4"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0">
-<tr><td class="activity-chart-label"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="3"><td data-activity-level="0"><td data-activity-level="1"><td data-activity-level="0"><td data-activity-level="2"><td data-activity-level="1"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0">
-<tr><td class="activity-chart-label"><span>Wed</span><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="4"><td data-activity-level="1"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td>
-<tr><td class="activity-chart-label"><td data-activity-level="1"><td data-activity-level="2"><td data-activity-level="2"><td data-activity-level="2"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="3"><td data-activity-level="0"><td data-activity-level="2"><td data-activity-level="1"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td>
-<tr><td class="activity-chart-label"><span>Fri</span><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="1"><td data-activity-level="2"><td data-activity-level="1"><td data-activity-level="3"><td data-activity-level="0"><td data-activity-level="4"><td data-activity-level="2"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td>
-<tr><td class="activity-chart-label"><td data-activity-level="2"><td data-activity-level="1"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td data-activity-level="0"><td>
-</table>
diff --git a/activity.lua b/activity.lua
new file mode 100644
index 0000000..1be6e93
--- /dev/null
+++ b/activity.lua
@@ -0,0 +1,64 @@
+local activity = {}
+
+
+function activity.days (year)
+ if year % 4 ~= 0 or year % 100 == 0 and year % 400 ~= 0 then
+ return 365
+ end
+ return 366
+end
+
+
+function activity.this_year ()
+ return os.date"%Y"
+end
+
+
+function activity.first_week_day (year)
+ year = year or activity.this_year()
+ return os.date("*t", os.time{year=year, month=1, day=1}).wday
+end
+
+
+function activity.generate_table (year)
+ year = year or activity.this_year()
+
+ local function spot ()
+ return [[<td>]]
+ end
+
+ local function day (level)
+ return ([[<td data-activity-level="%d">]]):format(level)
+ end
+
+ local function cell (exists)
+ if not exists then
+ return spot
+ end
+ return day
+ end
+
+ local function row (weekday, first, last)
+ first = cell(first)
+ last = cell(last)
+ local row = ([[<tr><td class="activity-chart-label"><span>%s</span>]]):format(weekday)
+ row = row .. first(math.random(0, 4))
+ for _=1,51 do
+ row = row .. day(math.random(0, 4))
+ end
+ row = row .. last(math.random(0, 4)) .. "\n"
+ return row
+ end
+
+ local rows = ""
+ local weekdays = {"", "Mon", "", "Wed", "", "Fri", ""}
+ local start_from = activity.first_week_day(year)
+ local end_at = (start_from + activity.days(year) - 1) % 7
+ for index, weekday in pairs(weekdays) do
+ rows = rows .. row(weekday, index >= start_from, index <= end_at)
+ end
+ return [[<table class="activity-chart">]] .. "\n" .. rows .. "</table>"
+end
+
+
+return activity
diff --git a/generate.lua b/generate.lua
new file mode 100644
index 0000000..2c78d61
--- /dev/null
+++ b/generate.lua
@@ -0,0 +1,8 @@
+local activity = require "activity"
+local year = ...
+print([[<!doctype html>]])
+print([[<html lang="en">]])
+print([[<meta charset="utf-8">]])
+print([[<link rel="stylesheet" type="text/css" href="style.css">]])
+print([[<title>Activity</title>]])
+print(activity.generate_table(year))
diff --git a/spec/activity_spec.lua b/spec/activity_spec.lua
new file mode 100644
index 0000000..08160fa
--- /dev/null
+++ b/spec/activity_spec.lua
@@ -0,0 +1,43 @@
+local activity = require "activity"
+
+describe("Days in a year", function()
+ it("should support regular years", function()
+ assert.are.equal(365, activity.days(1970))
+ assert.are.equal(365, activity.days(2001))
+ end)
+
+ it("should support lean years", function()
+ assert.are.equal(366, activity.days(2004))
+ assert.are.equal(366, activity.days(1980))
+ end)
+
+ it("should support *00 years", function()
+ assert.are.equal(366, activity.days(2000))
+ assert.are.equal(365, activity.days(2100))
+ assert.are.equal(365, activity.days(2200))
+ assert.are.equal(365, activity.days(2300))
+ assert.are.equal(366, activity.days(2400))
+ end)
+end)
+
+describe("This year is", function()
+ local this_year = os.date "%Y" -- Quite useless test
+
+ it(tostring(this_year), function()
+ assert.are.equal(this_year, activity.this_year())
+ end)
+end)
+
+describe("First week day of", function()
+ it("2023 is Sunday", function()
+ assert.are.equal(1, activity.first_week_day(2023))
+ end)
+
+ it("2022 is Saturday", function()
+ assert.are.equal(7, activity.first_week_day(2022))
+ end)
+
+ it("2020 is Saturday", function()
+ assert.are.equal(4, activity.first_week_day(2020))
+ end)
+end)