forked from nulang-org/nulang
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path16_realworld.nula
More file actions
148 lines (129 loc) · 5.43 KB
/
Copy path16_realworld.nula
File metadata and controls
148 lines (129 loc) · 5.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// 16_realworld.nula — Real-world CLI: JSON Fetcher & Reporter
//
// Fetches JSON from a URL, parses and inspects it, logs a timestamped
// summary, and writes the result to disk. A realistic workflow exercising
// HTTP, JSON, FS, datetime, args, and env together.
//
// Demonstrates:
// System.arg — read CLI arguments
// Http.get — fetch data from the web
// json.parse / json.stringify / json.get_string — process JSON
// datetime.now — capture a timestamp
// FS.write — persist output to a file
// Env.get — read configuration from the environment
// IO.print — user-facing progress messages
//
// Usage:
// nulang examples/16_realworld.nula <url>
//
// Environment:
// NU_OUTPUT_DIR — output directory (default: ./output/)
//
// Example:
// NU_OUTPUT_DIR=/tmp nulang examples/16_realworld.nula \
// https://jsonplaceholder.typicode.com/todos/1
import stdlib::json
import stdlib::datetime
// ── Helpers ───────────────────────────────────────────────────────────────
// Format a DateTime record as "YYYY-MM-DD HH:MM:SS".
let format_datetime = fn(dt) {
let pad = fn(n) {
if n < 10 then "0" + perform Int.to_string(n)
else perform Int.to_string(n)
};
perform Int.to_string(dt.year) + "-" +
pad(dt.month) + "-" +
pad(dt.day) + " " +
pad(dt.hour) + ":" +
pad(dt.minute) + ":" +
pad(dt.second)
}
// Produce a human-readable description of any JsonValue.
let describe = fn(v) {
match v {
JsonNull => "null",
JsonBool(b) => if b then "true" else "false",
JsonNumber(n) => "number",
JsonString(s) => "string (" + perform Int.to_string(perform String.length(s)) + " chars)",
JsonArray(a) => "array[" + perform Int.to_string(perform Array.length(a)) + " items]",
JsonObject(f) => "object{" + perform Int.to_string(perform Array.length(f)) + " keys}"
}
}
// Check whether a value is non-nil.
let is_some = fn(v) {
v != nil
}
// ── Main program ──────────────────────────────────────────────────────────
// 1. Read the target URL from the command line.
// System.arg(0) = program name, System.arg(1) = script path,
// System.arg(2) = first user argument.
let url = perform System.arg(2)
// 2. Check that a URL was provided.
let got_url = is_some(url)
if got_url then {
// 3. Read output directory from environment, falling back to ./output/.
// Env.get returns nil when the variable is not set.
let env_dir = perform Env.get("NU_OUTPUT_DIR")
let has_env = is_some(env_dir)
let out_dir = if has_env then env_dir else "./output/"
perform IO.print("=== JSON Fetcher ===")
perform IO.print("URL: " + url)
perform IO.print("Output dir: " + out_dir)
// 4. Fetch JSON from the URL.
perform IO.print("Fetching...")
let response = perform Http.get(url)
// 5. Check that the response is valid.
let ok = is_some(response)
if ok then {
let resp_len = perform String.length(response)
perform IO.print("Received " + perform Int.to_string(resp_len) + " bytes")
// 6. Parse the JSON response.
let parsed = parse(response)
let summary = describe(parsed)
perform IO.print("Parsed: " + summary)
// 7. Capture the current timestamp.
let now = now()
let ts = format_datetime(now)
perform IO.print("Timestamp: " + ts)
// 8. Build the output report (plain-text for readability).
let report =
"JSON Fetch Report\n" +
"=================\n" +
"Fetched at: " + ts + "\n" +
"Source URL: " + url + "\n" +
"Response: " + perform Int.to_string(resp_len) + " bytes\n" +
"Data summary: " + summary + "\n" +
"\n" +
"── Original JSON ──\n" +
stringify(parsed) + "\n"
// 9. Write the report to disk.
let out_path = out_dir + "fetch_report.txt"
let write_ok = perform FS.write(out_path, report)
// FS.write returns Unit on success, nil on failure.
// Check whether the write succeeded by reading back the file.
let verify = perform FS.read(out_path)
let wrote = is_some(verify)
if wrote then {
perform IO.print("Wrote output to " + out_path)
perform IO.print("=== Done ===")
unit
} else {
perform IO.print("Error: could not write to " + out_path)
perform IO.print("(Does the output directory exist?)")
}
} else {
perform IO.print("Error: failed to fetch from " + url)
perform IO.print("(Check the URL and network connection)")
}
} else {
perform IO.print("Usage: nulang examples/16_realworld.nula <url>")
perform IO.print("")
perform IO.print(" Fetches JSON from the given URL, parses it, prints a")
perform IO.print(" timestamped summary, and writes a report to disk.")
perform IO.print("")
perform IO.print("Environment:")
perform IO.print(" NU_OUTPUT_DIR output directory (default: ./output/)")
perform IO.print("")
perform IO.print("Example:")
perform IO.print(" nulang examples/16_realworld.nula https://jsonplaceholder.typicode.com/todos/1")
}