Skip to content

Commit

Permalink
feat: Improve DX for working with ctx
Browse files Browse the repository at this point in the history
  • Loading branch information
Olian04 committed Jun 18, 2024
1 parent 2e5a6d6 commit 3cf057b
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 0 deletions.
91 changes: 91 additions & 0 deletions src/handles/ctx.gleam
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import gleam/dict
import gleam/dynamic
import gleam/list

pub type Prop {
Prop(key: String, value: Value)
}
Expand All @@ -10,3 +14,90 @@ pub type Value {
Dict(value: List(Prop))
List(value: List(Value))
}

/// Transforms String, Int, Float, Bool, List, & Dict to their coresponding ctx.Value type.
///
/// Anny other types will panic
///
/// ## Examples
///
/// ```gleam
/// import handles/ctx
///
/// ctx.from("Hello World")
/// // -> ctx.Str("Hello World")
/// ```
///
/// ```gleam
/// ctx.from(42)
/// // -> ctx.Int(42)
/// ```
///
/// ```gleam
/// ctx.from(3.14)
/// // -> ctx.Float(3.14)
/// ```
///
/// ```gleam
/// ctx.from([1, 2, 3])
/// // -> ctx.List([ctx.Int(1), ctx.Int(2), ctx.Int(3)])
/// ```
///
/// ```gleam
/// ctx.from([
/// 42 |> dynamic.from,
/// 3.14 |> dynamic.from,
/// "Hello" |> dynamic.from,
/// ])
/// // -> ctx.List([ctx.Int(42), ctx.Float(3.14), ctx.Str("Hello")])
/// ```
pub fn from(value: a) -> Value {
from_dynamic(value |> dynamic.from)
}

fn from_dynamic(value: dynamic.Dynamic) -> Value {
case value |> dynamic.classify {
"String" -> {
let assert Ok(val) = value |> dynamic.string
Str(val)
}
"Int" -> {
let assert Ok(val) = value |> dynamic.int
Int(val)
}
"Float" -> {
let assert Ok(val) = value |> dynamic.float
Float(val)
}
"Bool" -> {
let assert Ok(val) = value |> dynamic.bool
Bool(val)
}
"Dict" -> {
let assert Ok(val) =
value |> dynamic.dict(dynamic.string, dynamic.dynamic)
from_dict(val, from_dynamic)
}
"List" -> {
let assert Ok(val) = value |> dynamic.list(dynamic.dynamic)
from_list(val, from_dynamic)
}
_ -> panic as "Unable to construct ctx from dynamic value"
}
}

fn from_dict(
source: dict.Dict(String, a),
value_mapper: fn(a) -> Value,
) -> Value {
source
|> dict.to_list
|> list.map(fn(it) { Prop(it.0, value_mapper(it.1)) })
|> Dict
}

fn from_list(source: List(a), value_mapper: fn(a) -> Value) -> Value {
source
|> list.map(value_mapper)
|> List
}
78 changes: 78 additions & 0 deletions test/unit_tests/ctx_test.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import gleam/dict
import gleam/dynamic
import gleam/iterator
import gleeunit/should
import handles/ctx
import handles/internal/ctx_utils

const expected_string = "expected"

fn gen_levels(levels_to_go: Int) {
case levels_to_go {
0 -> ctx.Str(expected_string)
_ -> ctx.Dict([ctx.Prop("prop", gen_levels(levels_to_go - 1))])
}
}

pub fn drill_shallow_test() {
ctx.Dict([ctx.Prop("prop", ctx.Str(expected_string))])
|> ctx_utils.drill_ctx(["prop"], _)
|> should.be_ok
|> should.equal(ctx.Str(expected_string))
}

pub fn drill_deep_test() {
let depth = 100
iterator.repeat("prop")
|> iterator.take(depth)
|> iterator.to_list
|> ctx_utils.drill_ctx(gen_levels(depth))
|> should.be_ok
|> should.equal(ctx.Str(expected_string))
}

pub fn from_string_test() {
ctx.from("foo")
|> should.equal(ctx.Str("foo"))
}

pub fn from_int_test() {
ctx.from(42)
|> should.equal(ctx.Int(42))
}

pub fn from_float_test() {
ctx.from(3.14)
|> should.equal(ctx.Float(3.14))
}

pub fn from_bool_test() {
ctx.from(True)
|> should.equal(ctx.Bool(True))
}

pub fn from_list_test() {
ctx.from([1, 2, 3])
|> should.equal(ctx.List([ctx.Int(1), ctx.Int(2), ctx.Int(3)]))
}

pub fn from_dict_test() {
ctx.from(
dict.new()
|> dict.insert("first", 1)
|> dict.insert("second", 2)
|> dict.insert("third", 3),
)
|> should.equal(
ctx.Dict([
ctx.Prop("first", ctx.Int(1)),
ctx.Prop("second", ctx.Int(2)),
ctx.Prop("third", ctx.Int(3)),
]),
)
}

pub fn from_mixed_types_test() {
ctx.from([42 |> dynamic.from, 3.14 |> dynamic.from, "Hello" |> dynamic.from])
|> should.equal(ctx.List([ctx.Int(42), ctx.Float(3.14), ctx.Str("Hello")]))
}

0 comments on commit 3cf057b

Please sign in to comment.