Initial commit

This commit is contained in:
pta 2023-11-27 01:50:14 -05:00
commit cacc836535
8 changed files with 290 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
result
dist-newstyle

11
LICENSE Normal file
View File

@ -0,0 +1,11 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

12
README.org Normal file
View File

@ -0,0 +1,12 @@
Display Weathernews caster ages in an HTML table or as plain text: if there's no "TERM"
environment variable set, HTML output. I'll try to run it as a CGI program.
Learning Haskell, so the code might not be the best.
Run ~nix-build~ to build the executable. A "result" directory will be created wiith the
executable under it.
Run ~nix-shell~ to get a subshell with the packges specified in "default.nix". Actual
Haskell library dependencies of the executable need to be specified only in the cabal
file. Once in the subshell, run ~cabal repl~ to load the executable into ghci and start
experimenting.

1
age.html Normal file
View File

@ -0,0 +1 @@
<!DOCTYPE html><html><head><title>WNI caster birthdays and ages</title><link rel="stylesheet" href="style.css"></head><body><p>2023-11-23 03:51:45.900476504</p><table><thead><tr><td>名前</td><td>生年月日</td><td></td><td>箇月</td><td></td></tr></thead><tbody><tr><td>山岸愛梨</td><td>1987-06-09</td><td>36</td><td>5</td><td>14</td></tr><tr><td>江川清音</td><td>1989-12-03</td><td>33</td><td>11</td><td>20</td></tr><tr><td>眞家泉</td><td>1990-09-07</td><td>33</td><td>2</td><td>16</td></tr><tr><td>白井ゆかり</td><td>1991-06-25</td><td>32</td><td>4</td><td>29</td></tr><tr><td>松雪彩花</td><td>1991-09-06</td><td>32</td><td>2</td><td>17</td></tr><tr><td>高安奈緒子</td><td>1992-11-22</td><td>31</td><td>0</td><td>1</td></tr><tr><td>檜山沙耶</td><td>1993-10-27</td><td>30</td><td>0</td><td>27</td></tr><tr><td>高山奈々</td><td>1994-06-17</td><td>29</td><td>5</td><td>6</td></tr><tr><td>内田侑希</td><td>1995-12-08</td><td>27</td><td>11</td><td>15</td></tr><tr><td>駒木結衣</td><td>1996-06-09</td><td>27</td><td>5</td><td>14</td></tr><tr><td>武藤彩芽</td><td>1996-08-31</td><td>27</td><td>2</td><td>23</td></tr><tr><td>魚住茉由</td><td>1998-12-06</td><td>24</td><td>11</td><td>17</td></tr><tr><td>青原桃香</td><td>1999-01-05</td><td>24</td><td>10</td><td>18</td></tr><tr><td>大島璃音</td><td>1999-03-19</td><td>24</td><td>8</td><td>4</td></tr><tr><td>小川千奈</td><td>1999-06-30</td><td>24</td><td>4</td><td>24</td></tr><tr><td>小林李衣奈</td><td>1999-11-17</td><td>24</td><td>0</td><td>6</td></tr><tr><td>戸北美月</td><td>1999-12-29</td><td>23</td><td>10</td><td>25</td></tr><tr><td>岡本結子リサ</td><td>2000-01-30</td><td>23</td><td>9</td><td>24</td></tr></tbody></table></body></html>

124
app/Main.hs Executable file
View File

@ -0,0 +1,124 @@
#!/usr/bin/env nix-shell
#!nix-shell --pure -i runghc -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ json ])"
-- https://wiki.haskell.org/Getting_the_current_date
-- https://hackage.haskell.org/package/time-1.13/docs/Data-Time.html datetime modules overview
-- https://hackage.haskell.org/package/time-1.12.2/docs/Data-Time-Clock.html
-- https://hackage.haskell.org/package/time-1.12.2/docs/Data-Time-Calendar.html
-- https://hackage.haskell.org/package/time-1.12.2/docs/Data-Time-LocalTime.html
-- https://mmhaskell.com/monads/reader-writer
-- https://hackage.haskell.org/package/type-of-html-1.6.2.0/docs/Html.html
-- https://github.com/knupfer/type-of-html
-- Overview of all language extension
-- https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/table.html
-- {-# LANGUAGE DuplicateRecordFields #-}
-- super sick extension learned here https://stackoverflow.com/questions/38052553/haskell-record-pattern-matching
{-# LANGUAGE RecordWildCards #-}
import Data.Time
import Data.List
import Html
import Control.Monad.Reader
import System.Environment
data Caster = Caster
{ casterName :: String
, casterBday :: Day }
deriving (Show)
data Age = Age
{ ageY :: String
, ageM :: String
, ageD :: String }
deriving (Show)
casters :: [Caster]
casters = [ Caster "山岸愛梨" $ YearMonthDay 1987 06 09
, Caster "松雪彩花" $ YearMonthDay 1991 09 06
, Caster "武藤彩芽" $ YearMonthDay 1996 08 31
, Caster "眞家泉" $ YearMonthDay 1990 09 07
, Caster "魚住茉由" $ YearMonthDay 1998 12 06
, Caster "戸北美月" $ YearMonthDay 1999 12 29
, Caster "青原桃香" $ YearMonthDay 1999 01 05
, Caster "高山奈々" $ YearMonthDay 1994 06 17
, Caster "高安奈緒子" $ YearMonthDay 1992 11 22
, Caster "小林李衣奈" $ YearMonthDay 1999 11 17
, Caster "大島璃音" $ YearMonthDay 1999 03 19
, Caster "檜山沙耶" $ YearMonthDay 1993 10 27
, Caster "江川清音" $ YearMonthDay 1989 12 03
, Caster "小川千奈" $ YearMonthDay 1999 06 30
, Caster "駒木結衣" $ YearMonthDay 1996 06 09
, Caster "岡本結子リサ" $ YearMonthDay 2000 01 30
, Caster "白井ゆかり" $ YearMonthDay 1991 06 25
, Caster "内田侑希" $ YearMonthDay 1995 12 08 ]
jptz :: TimeZone
jptz = TimeZone (9 * 60) False "JST" -- define JST time zone as 9 hours past UTC https://time.is/ja/Japan
jplocaltime :: IO LocalTime
jplocaltime = (utcToLocalTime jptz) <$> getCurrentTime
dayToTime :: Day -> LocalTime
dayToTime day = LocalTime day midnight
timeSinceBirth :: Reader LocalTime (Day -> Age)
timeSinceBirth = do
jptime <- ask
return (\bday ->
let today = localDay jptime
monthsAndDays = diffGregorianDurationClip today bday
totalMonths = cdMonths monthsAndDays
y = div totalMonths 12
m = rem totalMonths 12
d = cdDays monthsAndDays
in Age (show y) (show m) (show d))
casterAgeInfo :: Reader LocalTime (Caster -> (Caster, Age))
casterAgeInfo = do
timeSinceBirth' <- timeSinceBirth
return (\caster ->
let age = timeSinceBirth' $ casterBday caster
in (caster,age))
textline :: (Caster, Age) -> String
textline (Caster{..}, Age{..}) =
casterName ++ "born " ++ (show casterBday) ++ " " ++
ageY ++ " years, " ++ ageM ++ " months, " ++ ageD ++ " days old."
textoutput :: [(Caster, Age)] -> IO ()
textoutput datalist = do
jptime <- jplocaltime
putStrLn $ "日本での現在時刻 " ++ (show jptime)
putStr . unlines $ map textline datalist
webpage jptime tds =
DOCTYPE # Html :>
(Head :>
(Title :> "WNI caster birthdays and ages" #
Link :@ (RelA := "stylesheet" # HrefA := "style.css")) #
Body :>
(P :> ("日本での現在時刻 " ++ (show jptime)) #
Table :>
(Thead :>
Tr :> (Td :> "名前" # Td :> "生年月日" # Td :> "" # Td :> "箇月" # Td :> "") #
Tbody :> tds)))
tablerow (Caster{..}, Age{..}) =
Tr :> (Td :> casterName # Td :> (show casterBday) # Td :> ageY # Td :> ageM # Td :> ageD)
htmloutput :: [(Caster,Age)] -> IO ()
htmloutput datalist = do
jptime <- jplocaltime
putStr . renderString . webpage jptime $ map tablerow datalist
main :: IO ()
main = do
console <- lookupEnv "TERM"
jptime <- jplocaltime
let output = if console /= Nothing then textoutput else htmloutput
sortedByBday = sortOn casterBday casters :: [Caster]
datalist = map (runReader casterAgeInfo jptime) sortedByBday :: [(Caster,Age)]
in output datalist

80
caster-age.cabal Normal file
View File

@ -0,0 +1,80 @@
cabal-version: 3.0
-- The cabal-version field refers to the version of the .cabal specification,
-- and can be different from the cabal-install (the tool) version and the
-- Cabal (the library) version you are using. As such, the Cabal (the library)
-- version used must be equal or greater than the version stated in this field.
-- Starting from the specification version 2.2, the cabal-version field must be
-- the first thing in the cabal file.
-- Initial package description 'hask' generated by
-- 'cabal init'. For further documentation, see:
-- http://haskell.org/cabal/users-guide/
--
-- The name of the package.
name: caster-age
-- The package version.
-- See the Haskell package versioning policy (PVP) for standards
-- guiding when and how versions should be incremented.
-- https://pvp.haskell.org
-- PVP summary: +-+------- breaking API changes
-- | | +----- non-breaking API additions
-- | | | +--- code changes with no API change
version: 0.1.0.0
-- A short (one-line) description of the package.
-- synopsis:
-- A longer description of the package.
-- description:
-- The license under which the package is released.
license: GPL-3.0-only
-- The file containing the license text.
license-file: LICENSE
-- The package author(s).
author: pta
-- An email address to which users can send suggestions, bug reports, and patches.
maintainer: in your walls
-- A copyright notice.
-- copyright:
category: Database
build-type: Simple
-- Extra doc files to be distributed with the package, such as a CHANGELOG or a README.
extra-doc-files: CHANGELOG.md
-- Extra source files to be distributed with the package, such as examples, or a tutorial module.
-- extra-source-files:
common warnings
ghc-options: -Wall
executable caster-age
-- Import common warning flags.
import: warnings
-- .hs or .lhs file containing the Main module.
main-is: Main.hs
-- Modules included in this executable, other than Main.
-- other-modules:
-- LANGUAGE extensions used by modules in this package.
-- other-extensions:
-- Other library packages from which modules are imported.
build-depends: base ^>=4.17.2.0,
type-of-html,
time,
mtl
-- Directories containing source files.
hs-source-dirs: app
-- Base language which the package is written in.
default-language: Haskell2010

11
default.nix Normal file
View File

@ -0,0 +1,11 @@
let
pkgs = import <nixpkgs> { }; # pin the channel to ensure reproducibility!
in
pkgs.haskellPackages.developPackage {
root = ./.;
modifier = drv:
pkgs.haskell.lib.addBuildTools drv ((with pkgs.haskellPackages;
[ cabal-install
ghcid
]) ++ (with pkgs; [sqlite]));
}

49
style.css Normal file
View File

@ -0,0 +1,49 @@
/* https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Styling_tables */
/* spacing */
table {
table-layout: fixed;
border-collapse: collapse;
text-align: end;
/* border: 3px solid purple; */
}
thead {
background-color: #ccf3ff;
}
thead th:nth-child(1) {
width: 30%;
}
thead th:nth-child(2) {
width: 20%;
}
thead th:nth-child(3) {
width: 15%;
}
thead th:nth-child(4) {
width: 35%;
}
th,
td {
padding: 1px 16px 1px 0px;
}
/* zebra striping */
/* tbody tr:nth-child(odd) { */
/* background-color: #dadada; */
/* } */
tbody tr:nth-child(even) {
background-color: #ececec;
}
/* table { */
/* background-color: #ff33cc; */
/* } */