125 lines
4.4 KiB
Zig
125 lines
4.4 KiB
Zig
const std = @import("std");
|
|
const types = @import("../weather/types.zig");
|
|
|
|
pub fn render(allocator: std.mem.Allocator, weather: types.WeatherData, use_imperial: bool) ![]const u8 {
|
|
var output: std.ArrayList(u8) = .empty;
|
|
errdefer output.deinit(allocator);
|
|
const writer = output.writer(allocator);
|
|
|
|
// Header with location
|
|
try writer.print("Weather report: {s}\n\n", .{weather.location});
|
|
|
|
// Current conditions
|
|
try writer.print(" Current conditions\n", .{});
|
|
try writer.print(" {s}\n", .{weather.current.condition});
|
|
try writer.writeAll(" 🌡️ ");
|
|
if (use_imperial) {
|
|
try writer.print("{d:.1}°F\n", .{weather.current.temp_f});
|
|
} else {
|
|
try writer.print("{d:.1}°C ({d:.1}°F)\n", .{ weather.current.temp_c, weather.current.temp_f });
|
|
}
|
|
try writer.writeAll(" 💧 ");
|
|
try writer.print("{d}%\n", .{weather.current.humidity});
|
|
try writer.writeAll(" 🌬️ ");
|
|
if (use_imperial) {
|
|
const wind_mph = weather.current.wind_kph * 0.621371;
|
|
try writer.print("{d:.1} mph {s}\n", .{ wind_mph, weather.current.wind_dir });
|
|
} else {
|
|
try writer.print("{d:.1} km/h {s}\n", .{ weather.current.wind_kph, weather.current.wind_dir });
|
|
}
|
|
try writer.writeAll(" 🔽 ");
|
|
if (use_imperial) {
|
|
const pressure_inhg = weather.current.pressure_mb * 0.02953;
|
|
try writer.print("{d:.2} inHg\n", .{pressure_inhg});
|
|
} else {
|
|
try writer.print("{d:.1} hPa\n", .{weather.current.pressure_mb});
|
|
}
|
|
try writer.writeAll(" 💦 ");
|
|
if (use_imperial) {
|
|
const precip_in = weather.current.precip_mm * 0.0393701;
|
|
try writer.print("{d:.2} in\n\n", .{precip_in});
|
|
} else {
|
|
try writer.print("{d:.1} mm\n\n", .{weather.current.precip_mm});
|
|
}
|
|
|
|
// Forecast
|
|
if (weather.forecast.len > 0) {
|
|
try writer.print(" Forecast\n", .{});
|
|
for (weather.forecast) |day| {
|
|
try writer.print(" {s}: {s}\n", .{ day.date, day.condition });
|
|
try writer.writeAll(" ↑ ");
|
|
if (use_imperial) {
|
|
const max_f = day.max_temp_c * 9.0 / 5.0 + 32.0;
|
|
try writer.print("{d:.1}°F ", .{max_f});
|
|
} else {
|
|
try writer.print("{d:.1}°C ", .{day.max_temp_c});
|
|
}
|
|
try writer.writeAll("↓ ");
|
|
if (use_imperial) {
|
|
const min_f = day.min_temp_c * 9.0 / 5.0 + 32.0;
|
|
try writer.print("{d:.1}°F\n", .{min_f});
|
|
} else {
|
|
try writer.print("{d:.1}°C\n", .{day.min_temp_c});
|
|
}
|
|
}
|
|
}
|
|
|
|
return output.toOwnedSlice(allocator);
|
|
}
|
|
|
|
test "render v2 format" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
const weather = types.WeatherData{
|
|
.location = "Munich",
|
|
.current = .{
|
|
.temp_c = 12.0,
|
|
.temp_f = 53.6,
|
|
.condition = "Overcast",
|
|
.weather_code = 122,
|
|
.humidity = 80,
|
|
.wind_kph = 15.0,
|
|
.wind_dir = "NW",
|
|
.pressure_mb = 1015.0,
|
|
.precip_mm = 0.5,
|
|
},
|
|
.forecast = &[_]types.ForecastDay{},
|
|
.allocator = allocator,
|
|
};
|
|
|
|
const output = try render(allocator, weather, false);
|
|
defer allocator.free(output);
|
|
|
|
try std.testing.expect(output.len > 0);
|
|
try std.testing.expect(std.mem.indexOf(u8, output, "Munich") != null);
|
|
try std.testing.expect(std.mem.indexOf(u8, output, "Current conditions") != null);
|
|
try std.testing.expect(std.mem.indexOf(u8, output, "12.0°C") != null);
|
|
}
|
|
|
|
test "render v2 format with imperial units" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
const weather = types.WeatherData{
|
|
.location = "Boston",
|
|
.current = .{
|
|
.temp_c = 10.0,
|
|
.temp_f = 50.0,
|
|
.condition = "Clear",
|
|
.weather_code = 113,
|
|
.humidity = 65,
|
|
.wind_kph = 16.0,
|
|
.wind_dir = "N",
|
|
.pressure_mb = 1013.0,
|
|
.precip_mm = 0.0,
|
|
},
|
|
.forecast = &[_]types.ForecastDay{},
|
|
.allocator = allocator,
|
|
};
|
|
|
|
const output = try render(allocator, weather, true);
|
|
defer allocator.free(output);
|
|
|
|
try std.testing.expect(std.mem.indexOf(u8, output, "50.0°F") != null);
|
|
try std.testing.expect(std.mem.indexOf(u8, output, "mph") != null);
|
|
try std.testing.expect(std.mem.indexOf(u8, output, "inHg") != null);
|
|
}
|