Current section

Files

Jump to
glee src glee.gleam
Raw

src/glee.gleam

//// Glee
//// A simple way to parse JSON without
//// having to implement the JSON module.
//// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//// This is my first time using Gleam, so
//// I'm sure there are some things that
//// could be done better.
import gleam/dict
import gleam/dynamic/decode
import gleam/float
import gleam/int
import gleam/json
import gleam/list
import gleam/string
/// Parse a JSON string and return
/// the string value of a given field.
pub fn parse_json_string(json: String, field: String) -> Result(String, String) {
let json_decoder = {
use json <- decode.field(field, decode.string)
decode.success(json)
}
// Parse the JSON string and return
// the value of the given field.
let json_result =
json
|> json.parse(json_decoder)
// Return the value of the given field.
case json_result {
Ok(json_result) -> Ok(json_result)
Error(_) -> Error("Failed to parse string")
}
}
/// Parse a JSON string and return
/// the float value of a given field.
pub fn parse_json_float(json: String, field: String) -> Result(Float, String) {
// Parse the JSON string and return
// the value of the given field.
let json_decoder = {
use json <- decode.field(field, decode.float)
decode.success(json)
}
// Parse the JSON string and return
// the value of the given field.
let json_result =
json
|> json.parse(json_decoder)
// Return the value of the given field.
case json_result {
Ok(value) -> Ok(value)
Error(_) -> Error("Failed to parse float")
}
}
/// Parse a JSON string and return
/// the int value of a given field.
pub fn parse_json_int(json: String, field: String) -> Result(Int, String) {
// Parse the JSON string and return
// the value of the given field.
let json_decoder = {
use json <- decode.field(field, decode.int)
decode.success(json)
}
// Parse the JSON string and return
// the value of the given field.
let json_result =
json
|> json.parse(json_decoder)
// Return the value of the given field.
case json_result {
Ok(value) -> Ok(value)
Error(_) -> Error("Failed to parse integer")
}
}
/// Extract a value from a JSON string
/// by specifying the parent and key.
pub fn extract_value_from_json(
json: String,
parent: String,
key: String,
) -> String {
let parent_pattern = "\"" <> parent <> "\":{"
let parent_parts = string.split(json, parent_pattern)
case parent_parts {
[_, parent_content, ..] -> {
let key_pattern = "\"" <> key <> "\":"
let key_parts = string.split(parent_content, key_pattern)
case key_parts {
[_, value_part, ..] -> {
let by_comma = string.split(value_part, ",")
let by_brace = string.split(value_part, "}")
let value_by_comma = case by_comma {
[first, ..] -> first
_ -> value_part
}
let value_by_brace = case by_brace {
[first, ..] -> first
_ -> value_part
}
let value = case
string.length(value_by_comma) < string.length(value_by_brace)
{
True -> value_by_comma
False -> value_by_brace
}
let value = string.trim(value)
let value = case
string.starts_with(value, "\"") && string.ends_with(value, "\"")
{
True -> string.slice(value, 1, string.length(value) - 2)
False -> value
}
value
}
_ -> "Unknown"
}
}
_ -> "Unknown"
}
}
/// Encode a string value into a JSON string
pub fn encode_string(value: String) -> String {
let escaped = string.replace(value, "\"", "\\\"")
"\"" <> escaped <> "\""
}
/// Encode an int value into a JSON string
pub fn encode_int(value: Int) -> String {
int.to_string(value)
}
/// Encode a float value into a JSON string
pub fn encode_float(value: Float) -> String {
float.to_string(value)
}
/// Encode a boolean value into a JSON string
pub fn encode_bool(value: Bool) -> String {
case value {
True -> "true"
False -> "false"
}
}
/// Encode a list of values into a JSON array string
pub fn encode_list(values: List(String)) -> String {
let joined_values =
list.fold(values, "", fn(acc, value) {
case acc {
"" -> value
_ -> acc <> "," <> value
}
})
"[" <> joined_values <> "]"
}
/// Encode a map of string keys and string values into a JSON object string
pub fn encode_object(values: dict.Dict(String, String)) -> String {
let entries = dict.to_list(values)
let joined_entries =
list.fold(entries, "", fn(acc, entry) {
let #(key, value) = entry
let formatted_entry = encode_string(key) <> ":" <> value
case acc {
"" -> formatted_entry
_ -> acc <> "," <> formatted_entry
}
})
"{" <> joined_entries <> "}"
}
/// Create a simple JSON object with a single key-value pair
pub fn create_json_object(key: String, value: String) -> String {
let values = dict.new()
let values = dict.insert(values, key, value)
encode_object(values)
}
/// Create a JSON object from multiple key-value pairs
pub fn create_json_object_from_pairs(pairs: List(#(String, String))) -> String {
let values = dict.from_list(pairs)
encode_object(values)
}
/// Parse a JSON string and return
/// the boolean value of a given field.
pub fn parse_json_bool(json: String, field: String) -> Result(Bool, String) {
// Parse the JSON string and return
// the value of the given field.
let json_decoder = {
use json <- decode.field(field, decode.bool)
decode.success(json)
}
// Parse the JSON string and return
// the value of the given field.
let json_result =
json
|> json.parse(json_decoder)
// Return the value of the given field.
case json_result {
Ok(value) -> Ok(value)
Error(_) -> Error("Failed to parse boolean")
}
}