From 3fb702c48e6ba2464179d2a5d293a5028de8fdae Mon Sep 17 00:00:00 2001 From: Masayuki Takeda Date: Sat, 25 Apr 2026 12:43:27 +0900 Subject: [PATCH 1/2] feat: add OCaml Meeting 2026 in Tokyo info alongside distinction between past and future events --- assets/templates/events_index.html | 27 ++++++- bin/dune | 2 + bin/main.ml | 105 +++++++++++++++++++++++--- contents/events/index.md | 2 +- contents/events/ocaml_meeting_2026.md | 33 ++++++++ dune-project | 2 + ocaml-jp.opam | 2 + 7 files changed, 158 insertions(+), 15 deletions(-) create mode 100644 contents/events/ocaml_meeting_2026.md diff --git a/assets/templates/events_index.html b/assets/templates/events_index.html index 28f4c71..89837a4 100644 --- a/assets/templates/events_index.html +++ b/assets/templates/events_index.html @@ -1,8 +1,26 @@ -{% if has_articles %} +{% if has_upcoming_events %}
+

開催予定のイベント

+
+ {% for article in upcoming_events %} + + {% endfor %} +
+
+{% endif %} + +{% if has_past_events %} +

過去のイベント

- {% for article in articles %} + {% for article in past_events %}
-{% else %} +{% endif %} + +{% if not has_upcoming_events and not has_past_events %}

現在、イベント情報はありません。

{% endif %} - diff --git a/bin/dune b/bin/dune index 7fc92cf..fbac648 100644 --- a/bin/dune +++ b/bin/dune @@ -2,6 +2,8 @@ (public_name ocaml-jp-site) (name main) (libraries + core + core_unix.sys_unix yocaml yocaml_unix yocaml_jingoo diff --git a/bin/main.ml b/bin/main.ml index ab1491a..f7b7143 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -1,3 +1,4 @@ +open Core open Yocaml let into = Path.rel [ "www" ] @@ -11,7 +12,9 @@ let create_css = |> Action.Static.write_file Path.(into / "style.css") ;; -let track_binary = Sys.executable_name |> Yocaml.Path.from_string |> Pipeline.track_file +let track_binary = + Sys_unix.executable_name |> Yocaml.Path.from_string |> Pipeline.track_file +;; let create_index = let source = Path.rel [ "contents"; "index_main.html" ] in @@ -44,7 +47,7 @@ let write_markdown source ~into = Action.Static.write_file page_path pipeline ;; -let with_ext exts file = List.exists (fun ext -> Path.has_extension ext file) exts +let with_ext exts file = List.exists exts ~f:(fun ext -> Path.has_extension ext file) let is_markdown = with_ext [ "md" ] let is_not_index file = @@ -66,13 +69,95 @@ let compute_event_link source = source |> Path.move ~into |> Path.change_extension "html" ;; +module Event = struct + let entity_name = "Event" + + type t = + { title : string + ; date : Archetype.Datetime.t + ; upcoming : bool + } + + let neutral = + Data.Validation.fail_with ~given:"null" "Cannot be null" + |> Result.map_error ~f:(fun error -> + Required.Validation_error { entity = entity_name; error }) + ;; + + let validate = + let open Data.Validation in + record (fun fields -> + let+ title = required fields "title" string + and+ date = required fields "date" Archetype.Datetime.validate + and+ upcoming = optional_or fields ~default:false "upcoming" bool in + { title; date; upcoming }) + ;; + + let normalize { title; date; upcoming } = + Data. + [ "title", string title + ; "date", Archetype.Datetime.normalize date + ; "upcoming", bool upcoming + ] + ;; +end + +module Events = struct + type t = + { page : Archetype.Page.t + ; events : (Path.t * Event.t) list + } + + let with_page ~events ~page = { page; events } + + let sort_by_date events = + List.sort + events + ~compare: + (Comparable.lift + (fun a b -> Archetype.Datetime.compare b a) + ~f:(fun (_, (e : Event.t)) -> e.date)) + ;; + + let normalize_event (path, event) = + Data.record + (("url", Data.string @@ Path.to_string path) :: Event.normalize event) + ;; + + let normalize { page; events } = + let upcoming, past = + List.partition_tf events ~f:(fun (_, (e : Event.t)) -> e.upcoming) + in + Archetype.Page.normalize page + @ Data. + [ "upcoming_events", list_of normalize_event upcoming + ; "past_events", list_of normalize_event past + ; "has_upcoming_events", bool (not (List.is_empty upcoming)) + ; "has_past_events", bool (not (List.is_empty past)) + ] + ;; +end + let fetch_events = let where file = is_markdown file && is_not_index file in - Archetype.Articles.fetch + let open Task in + Pipeline.fetch + ~only:`Files ~where - ~compute_link:compute_event_link - (module Yocaml_yaml) + ~on:`Source + (fun file -> + let open Eff in + let url = compute_event_link file in + let+ metadata, _content = + Eff.read_file_with_metadata + (module Yocaml_yaml) + (module Event) + ~on:`Source + file + in + url, metadata) (Path.rel [ "contents"; "events" ]) + >>| Events.sort_by_date ;; let create_events_index = @@ -89,13 +174,13 @@ let create_events_index = ; assets / "templates" / "page.html" ; assets / "templates" / "layout.html" ] - and+ articles = fetch_events + and+ events = fetch_events and+ metadata, content = Yocaml_yaml.Pipeline.read_file_with_metadata (module Archetype.Page) source in - let metadata = Archetype.Articles.with_page ~page:metadata ~articles in + let metadata = Events.with_page ~page:metadata ~events in Yocaml_markdown.from_string_to_html content - |> apply_templates (module Archetype.Articles) ~metadata + |> apply_templates (module Events) ~metadata in Action.Static.write_file index_path pipeline ;; @@ -119,12 +204,12 @@ let () = let level = `Debug in let target = into in let port = 8080 in - match Sys.argv with + match Sys.get_argv () with | [| _ |] | [| _; "build" |] -> Yocaml_unix.run ~level process | [| _; "serve" |] -> Yocaml_unix.serve ~level ~target ~port process | _ -> let open Printf in - eprintf "Usage: %s [build|serve]\n" Sys.argv.(0); + eprintf "Usage: %s [build|serve]\n" (Sys.get_argv ()).(0); eprintf " build Generate static site (default)\n"; eprintf " serve Start development server on port 8000\n"; exit 1 diff --git a/contents/events/index.md b/contents/events/index.md index 2e5c140..902ebd6 100644 --- a/contents/events/index.md +++ b/contents/events/index.md @@ -2,5 +2,5 @@ page_title: イベント一覧 --- -OCaml.jp では、日本のOCamlコミュニティを盛り上げるために、様々なイベントを開催してきました。このページでは、過去に開催されたイベントの記録を掲載しています。 +OCaml.jp では、日本のOCamlコミュニティを盛り上げるために、様々なイベントを開催しています。このページでは、開催予定のイベントと、過去に開催されたイベントの記録を掲載しています。 diff --git a/contents/events/ocaml_meeting_2026.md b/contents/events/ocaml_meeting_2026.md new file mode 100644 index 0000000..a28e40d --- /dev/null +++ b/contents/events/ocaml_meeting_2026.md @@ -0,0 +1,33 @@ +--- +page_title: OCaml Meeting 2026 in Tokyo +title: OCaml Meeting 2026 in Tokyo +date: 2026-08-22 +upcoming: true +--- + +OCaml Meeting は、OCaml ユーザーによる技術交流会です。[2013 年の名古屋開催](/events/ocaml_meeting_2013.html)以来 13 年ぶりの開催となります。OCaml や関数型プログラミングに興味のある方であれば、初心者からエキスパートまでどなたでも歓迎です。 + +### 日時・場所 + +* 日程:2026/8/22(土) 10:00 - 18:00 +* 会場:DeNA Lounge(渋谷スクランブルスクエア 40F) +* 住所:東京都渋谷区渋谷 2-24-12 +* 受付:当日 10:00 - 10:30 にオフィスフロア(17F)にて + +### プログラム + +* 発表(30 - 45 分):6 名(抽選、発表枠での参加申込締切は 2026/7/27) +* ライトニングトーク(10 - 20 分):6 名(抽選、LT 枠での参加申込締切は 2026/7/27) +* 詳細なタイムテーブルは後日公開予定です。 + +### 参加方法 + +参加申込は connpass からお願いします。参加費は無料です。 + +* 申込ページ:[https://ocamljp.connpass.com/event/391765/](https://ocamljp.connpass.com/event/391765/) +* 一般参加:50 名(先着) +* 発表枠・LT 枠:各 6 名(抽選) + +### お問い合わせ + +発表・LT に関するご相談などは [OCaml.jp Discord](https://discord.gg/qQTbny8KF4) の `#ocaml-meeting-2026-in-tokyo` チャンネルまでお寄せください。 diff --git a/dune-project b/dune-project index 4b6c263..31ef28c 100644 --- a/dune-project +++ b/dune-project @@ -15,6 +15,8 @@ (depends ocaml dune + core + core_unix yocaml yocaml_unix yocaml_omd diff --git a/ocaml-jp.opam b/ocaml-jp.opam index ce88f60..4479d31 100644 --- a/ocaml-jp.opam +++ b/ocaml-jp.opam @@ -9,6 +9,8 @@ license: "MIT" depends: [ "ocaml" "dune" {>= "3.20"} + "core" + "core_unix" "yocaml" "yocaml_unix" "yocaml_omd" From 3a9b38cfd13d4c2fdb1c75c754699ca0908314e3 Mon Sep 17 00:00:00 2001 From: Masayuki Takeda Date: Sat, 25 Apr 2026 12:47:14 +0900 Subject: [PATCH 2/2] minor refactor --- bin/main.ml | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/bin/main.ml b/bin/main.ml index f7b7143..e3eb4c1 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -115,13 +115,12 @@ module Events = struct events ~compare: (Comparable.lift - (fun a b -> Archetype.Datetime.compare b a) + (Comparable.reverse Archetype.Datetime.compare) ~f:(fun (_, (e : Event.t)) -> e.date)) ;; let normalize_event (path, event) = - Data.record - (("url", Data.string @@ Path.to_string path) :: Event.normalize event) + Data.record (("url", Data.string @@ Path.to_string path) :: Event.normalize event) ;; let normalize { page; events } = @@ -146,16 +145,12 @@ let fetch_events = ~where ~on:`Source (fun file -> - let open Eff in - let url = compute_event_link file in - let+ metadata, _content = - Eff.read_file_with_metadata - (module Yocaml_yaml) - (module Event) - ~on:`Source - file - in - url, metadata) + let open Eff in + let url = compute_event_link file in + let+ metadata, _content = + Eff.read_file_with_metadata (module Yocaml_yaml) (module Event) ~on:`Source file + in + url, metadata) (Path.rel [ "contents"; "events" ]) >>| Events.sort_by_date ;;