Skip to content

Commit ffbc58e

Browse files
authored
Merge pull request #71 from hallvard/yaml-support-feature
support yaml as format for patterns
2 parents 5c47b51 + 94188af commit ffbc58e

File tree

4 files changed

+82
-63
lines changed

4 files changed

+82
-63
lines changed

content/collections/collectors-teeing.json

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
id: 26
2+
slug: collectors-teeing
3+
title: Collectors.teeing()
4+
category: collections
5+
difficulty: intermediate
6+
jdkVersion: "12"
7+
oldLabel: Java 8
8+
modernLabel: Java 12+
9+
oldApproach: Two Passes
10+
modernApproach: teeing()
11+
oldCode: |
12+
long count = items.stream().count();
13+
double sum = items.stream()
14+
.mapToDouble(Item::price)
15+
.sum();
16+
var result = new Stats(count, sum);
17+
modernCode: |
18+
var result = items.stream().collect(
19+
Collectors.teeing(
20+
Collectors.counting(),
21+
Collectors.summingDouble(Item::price),
22+
Stats::new
23+
)
24+
);
25+
summary: Compute two aggregations in a single stream pass.
26+
explanation: Collectors.teeing() sends each element to two downstream collectors and merges the results. This avoids streaming the data twice or using a mutable accumulator.
27+
whyModernWins:
28+
- icon:
29+
title: Single pass
30+
desc: Process the stream once instead of twice.
31+
- icon: 🧩
32+
title: Composable
33+
desc: Combine any two collectors with a merger function.
34+
- icon: 🔒
35+
title: Immutable result
36+
desc: Merge into a record or value object directly.
37+
support:
38+
state: available
39+
description: Widely available since JDK 12 (March 2019)
40+
prev: collections/sequenced-collections
41+
next: collections/stream-toarray-typed
42+
related:
43+
- collections/copying-collections-immutably
44+
- collections/unmodifiable-collectors
45+
- collections/stream-toarray-typed
46+
docs:
47+
- title: Collectors.teeing()
48+
href: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Collectors.html#teeing(java.util.stream.Collector,java.util.stream.Collector,java.util.function.BiFunction)

html-generators/generate.java

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
///usr/bin/env jbang "$0" "$@" ; exit $?
22
//JAVA 25
33
//DEPS com.fasterxml.jackson.core:jackson-databind:2.18.3
4+
//DEPS com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.3
45

56
import module java.base;
67
import com.fasterxml.jackson.core.type.TypeReference;
78
import com.fasterxml.jackson.databind.*;
9+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
810

911
/**
1012
* Generate HTML detail pages from JSON snippet files and slug-template.html.
@@ -14,7 +16,13 @@
1416
static final String CONTENT_DIR = "content";
1517
static final String SITE_DIR = "site";
1618
static final Pattern TOKEN = Pattern.compile("\\{\\{(\\w+)}}");
17-
static final ObjectMapper MAPPER = new ObjectMapper();
19+
static final ObjectMapper JSON_MAPPER = new ObjectMapper();
20+
static final ObjectMapper YAML_MAPPER = new ObjectMapper(new YAMLFactory());
21+
static final Map<String, ObjectMapper> MAPPERS = Map.of(
22+
"json", JSON_MAPPER,
23+
"yaml", YAML_MAPPER,
24+
"yml", YAML_MAPPER
25+
);
1826

1927
static final String CATEGORIES_FILE = "html-generators/categories.properties";
2028
static final SequencedMap<String, String> CATEGORY_DISPLAY = loadCategoryDisplay();
@@ -100,7 +108,7 @@ void main() throws IOException {
100108
// Rebuild data/snippets.json
101109
var snippetsList = allSnippets.values().stream()
102110
.map(s -> {
103-
Map<String, Object> map = MAPPER.convertValue(s.node(), new TypeReference<LinkedHashMap<String, Object>>() {});
111+
Map<String, Object> map = JSON_MAPPER.convertValue(s.node(), new TypeReference<LinkedHashMap<String, Object>>() {});
104112
EXCLUDED_KEYS.forEach(map::remove);
105113
return map;
106114
})
@@ -127,14 +135,20 @@ SequencedMap<String, Snippet> loadAllSnippets() throws IOException {
127135
for (var cat : CATEGORY_DISPLAY.sequencedKeySet()) {
128136
var catDir = Path.of(CONTENT_DIR, cat);
129137
if (!Files.isDirectory(catDir)) continue;
130-
try (var stream = Files.newDirectoryStream(catDir, "*.json")) {
131-
var sorted = new ArrayList<Path>();
132-
stream.forEach(sorted::add);
133-
sorted.sort(Path::compareTo);
134-
for (var path : sorted) {
135-
var snippet = new Snippet(MAPPER.readTree(path.toFile()));
136-
snippets.put(snippet.key(), snippet);
137-
}
138+
var sorted = new ArrayList<Path>();
139+
// first collect and sortall files
140+
for (var ext : MAPPERS.keySet()) {
141+
try (var stream = Files.newDirectoryStream(catDir, "*." + ext)) {
142+
stream.forEach(sorted::add);
143+
}
144+
}
145+
sorted.sort(Path::compareTo);
146+
for (var path : sorted) {
147+
var filename = path.getFileName().toString();
148+
var ext = filename.substring(filename.lastIndexOf('.') + 1);
149+
var json = MAPPERS.get(ext).readTree(path.toFile());
150+
var snippet = new Snippet(json);
151+
snippets.put(snippet.key(), snippet);
138152
}
139153
}
140154
return snippets;
@@ -145,7 +159,7 @@ String escape(String text) {
145159
}
146160

147161
String jsonEscape(String text) throws IOException {
148-
var quoted = MAPPER.writeValueAsString(text);
162+
var quoted = JSON_MAPPER.writeValueAsString(text);
149163
var inner = quoted.substring(1, quoted.length() - 1);
150164
var sb = new StringBuilder(inner.length());
151165
for (int i = 0; i < inner.length(); i++) {

html-generators/generate.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"""Generate HTML detail pages from JSON snippet files and slug-template.html."""
33

44
import json
5+
import yaml
56
import glob
67
import os
78
import html
@@ -73,10 +74,16 @@ def load_all_snippets():
7374
snippets = {}
7475
json_files = []
7576
for cat in CATEGORY_DISPLAY:
76-
json_files.extend(sorted(glob.glob(f"{CONTENT_DIR}/{cat}/*.json")))
77+
json_files.extend(glob.glob(f"{CONTENT_DIR}/{cat}/*.json"))
78+
json_files.extend(glob.glob(f"{CONTENT_DIR}/{cat}/*.yaml"))
79+
json_files.extend(glob.glob(f"{CONTENT_DIR}/{cat}/*.yml"))
80+
json_files.sort()
7781
for path in json_files:
7882
with open(path) as f:
79-
data = json.load(f)
83+
if path.endswith(".yaml") or path.endswith(".yml"):
84+
data = yaml.safe_load(f)
85+
else:
86+
data = json.load(f)
8087
key = f"{data['category']}/{data['slug']}"
8188
data["_path"] = key
8289
snippets[key] = data

0 commit comments

Comments
 (0)