Skip to content

Commit ff8be8c

Browse files
committed
JS decode field for objects
1 parent a6b75f6 commit ff8be8c

File tree

4 files changed

+55
-16
lines changed

4 files changed

+55
-16
lines changed

src/gleam/dynamic.gleam

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -382,25 +382,34 @@ if javascript {
382382
"../gleam_stdlib.js" "decode_option"
383383
}
384384

385+
/// Checks to see if a Dynamic value is a map with a specific field, and return
386+
/// the value of the field if it is.
387+
///
388+
/// This will not succeed on a record.
389+
///
390+
/// ## Examples
391+
///
392+
/// > import gleam/map
393+
/// > field(from(map.new("Hello", "World")), "Hello")
394+
/// Ok(Dynamic)
395+
///
396+
/// > field(from(123), "Hello")
397+
/// Error(DecodeError(expected: "Map", found: "Int"))
398+
///
399+
pub fn field(from value: Dynamic, named name: a) -> Result(Dynamic, DecodeError) {
400+
decode_field(value, name)
401+
}
402+
385403
if erlang {
386-
/// Checks to see if a Dynamic value is a map with a specific field, and return
387-
/// the value of the field if it is.
388-
///
389-
/// This will not succeed on a record.
390-
///
391-
/// ## Examples
392-
///
393-
/// > import gleam/map
394-
/// > field(from(map.new("Hello", "World")), "Hello")
395-
/// Ok(Dynamic)
396-
///
397-
/// > field(from(123), "Hello")
398-
/// Error(DecodeError(expected: "Map", found: "Int"))
399-
///
400-
pub external fn field(from: Dynamic, named: a) -> Result(Dynamic, DecodeError) =
404+
external fn decode_field(Dynamic, name) -> Result(Dynamic, DecodeError) =
401405
"gleam_stdlib" "decode_field"
402406
}
403407

408+
if javascript {
409+
external fn decode_field(Dynamic, name) -> Result(Dynamic, DecodeError) =
410+
"../gleam_stdlib.js" "decode_field"
411+
}
412+
404413
/// Checks to see if the Dynamic value is a tuple large enough to have a certain
405414
/// index, and return the value of that index if it is.
406415
///

src/gleam_stdlib.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ decode_list(Data) -> decode_error_msg(<<"List">>, Data).
9494
decode_field(Data, Key) ->
9595
case Data of
9696
#{Key := Value} -> {ok, Value};
97-
_ -> decode_error_msg(io_lib:format("a map with key `~p`", [Key]), Data)
97+
_ -> decode_error_msg(io_lib:format("Value with field `~p`", [Key]), Data)
9898
end.
9999

100100
size_of_tuple(Data) -> tuple_size(Data).

src/gleam_stdlib.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,8 @@ export function decode64(sBase64) {
473473
export function classify_dynamic(data) {
474474
if (typeof data === "string") {
475475
return "String";
476+
} else if (Result.isResult(data)) {
477+
return "Result";
476478
} else if (List.isList(data)) {
477479
return "List";
478480
} else if (Number.isInteger(data)) {
@@ -552,3 +554,9 @@ export function decode_option(data, decoder) {
552554
return result;
553555
}
554556
}
557+
558+
export function decode_field(value, name) {
559+
return name in value
560+
? new Ok(value[name])
561+
: decoder_error(`Value with field ${inspect(name)}`, value);
562+
}

test/gleam/dynamic_test.gleam

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,28 @@ pub fn optional_test() {
224224
|> should.be_error
225225
}
226226

227+
if javascript {
228+
pub fn javascript_object_field_test() {
229+
Ok(123)
230+
|> dynamic.from
231+
|> dynamic.field("0")
232+
|> should.equal(Ok(dynamic.from(123)))
233+
234+
Ok(123)
235+
|> dynamic.from
236+
|> dynamic.field(0)
237+
|> should.equal(Ok(dynamic.from(123)))
238+
239+
Ok(123)
240+
|> dynamic.from
241+
|> dynamic.field("Nope")
242+
|> should.equal(Error(DecodeError(
243+
expected: "Value with field \"Nope\"",
244+
found: "Result",
245+
)))
246+
}
247+
}
248+
227249
if erlang {
228250
pub fn field_test() {
229251
map.new()

0 commit comments

Comments
 (0)