aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2021-07-26 19:37:38 +0100
committerLouis Pilfold <louis@lpil.uk>2021-07-26 19:37:38 +0100
commit34d7d8697123eada9fb1d4a36ee1aee2c71a8b9d (patch)
tree18066f57f29fa8be0f9621ed85e4ae7ab6b711ba /src
parent0cc6c9002b781af900bd5da2b7c974c6d3e2a9ab (diff)
downloadgleam_stdlib-34d7d8697123eada9fb1d4a36ee1aee2c71a8b9d.tar.gz
gleam_stdlib-34d7d8697123eada9fb1d4a36ee1aee2c71a8b9d.zip
Gleam native string padding. Iterator tests
Diffstat (limited to 'src')
-rw-r--r--src/gleam/iterator.gleam286
-rw-r--r--src/gleam/string.gleam66
-rw-r--r--src/gleam_stdlib.js8
3 files changed, 175 insertions, 185 deletions
diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam
index e7405bb..4f8b7ff 100644
--- a/src/gleam/iterator.gleam
+++ b/src/gleam/iterator.gleam
@@ -922,159 +922,159 @@ if erlang {
|> fold(map.new(), group_updater(key))
|> map.map_values(fn(_, group) { list.reverse(group) })
}
+}
- /// This function acts similar to fold, but does not take an initial state.
- /// Instead, it starts from the first yielded element
- /// and combines it with each subsequent element in turn using the given function.
- /// The function is called as f(current_element, accumulator).
- ///
- /// Returns `Ok` to indicate a successful run, and `Error` if called on an empty iterator.
- ///
- /// ## Examples
- ///
- /// > from_list([]) |> reduce(fn(x, y) { x + y })
- /// Error(Nil)
- ///
- /// > from_list([1, 2, 3, 4, 5]) |> reduce(fn(x, y) { x + y })
- /// Ok(15)
- ///
- pub fn reduce(
- over iterator: Iterator(e),
- with f: fn(e, e) -> e,
- ) -> Result(e, Nil) {
- case iterator.continuation() {
- Stop -> Error(Nil)
- Continue(e, next) ->
- do_fold(next, f, e)
- |> Ok
- }
+/// This function acts similar to fold, but does not take an initial state.
+/// Instead, it starts from the first yielded element
+/// and combines it with each subsequent element in turn using the given function.
+/// The function is called as f(current_element, accumulator).
+///
+/// Returns `Ok` to indicate a successful run, and `Error` if called on an empty iterator.
+///
+/// ## Examples
+///
+/// > from_list([]) |> reduce(fn(x, y) { x + y })
+/// Error(Nil)
+///
+/// > from_list([1, 2, 3, 4, 5]) |> reduce(fn(x, y) { x + y })
+/// Ok(15)
+///
+pub fn reduce(
+ over iterator: Iterator(e),
+ with f: fn(e, e) -> e,
+) -> Result(e, Nil) {
+ case iterator.continuation() {
+ Stop -> Error(Nil)
+ Continue(e, next) ->
+ do_fold(next, f, e)
+ |> Ok
}
+}
- /// Returns the last element in the given iterator.
- ///
- /// Returns `Error(Nil)` if the iterator is empty.
- ///
- /// This function runs in linear time.
- ///
- /// ## Examples
- ///
- /// > empty() |> last
- /// Error(Nil)
- ///
- /// > range(1, 10) |> last
- /// Ok(9)
- ///
- pub fn last(iterator: Iterator(element)) -> Result(element, Nil) {
- iterator
- |> reduce(fn(elem, _) { elem })
- }
+/// Returns the last element in the given iterator.
+///
+/// Returns `Error(Nil)` if the iterator is empty.
+///
+/// This function runs in linear time.
+///
+/// ## Examples
+///
+/// > empty() |> last
+/// Error(Nil)
+///
+/// > range(1, 10) |> last
+/// Ok(9)
+///
+pub fn last(iterator: Iterator(element)) -> Result(element, Nil) {
+ iterator
+ |> reduce(fn(elem, _) { elem })
+}
- /// Creates an iterator that yields no elements.
- ///
- /// ## Examples
- ///
- /// > empty() |> to_list
- /// []
- ///
- pub fn empty() -> Iterator(element) {
- Iterator(stop)
- }
+/// Creates an iterator that yields no elements.
+///
+/// ## Examples
+///
+/// > empty() |> to_list
+/// []
+///
+pub fn empty() -> Iterator(element) {
+ Iterator(stop)
+}
- /// Creates an iterator that yields exactly one element provided by calling the given function.
- ///
- /// ## Examples
- ///
- /// > once(fn() { 1 }) |> to_list
- /// [1]
- ///
- pub fn once(f: fn() -> element) -> Iterator(element) {
- fn() { Continue(f(), stop) }
- |> Iterator
- }
+/// Creates an iterator that yields exactly one element provided by calling the given function.
+///
+/// ## Examples
+///
+/// > once(fn() { 1 }) |> to_list
+/// [1]
+///
+pub fn once(f: fn() -> element) -> Iterator(element) {
+ fn() { Continue(f(), stop) }
+ |> Iterator
+}
- /// Creates an iterator that yields the given element exactly once.
- ///
- /// ## Examples
- ///
- /// > single(1) |> to_list
- /// [1]
- ///
- pub fn single(elem: element) -> Iterator(element) {
- once(fn() { elem })
- }
+/// Creates an iterator that yields the given element exactly once.
+///
+/// ## Examples
+///
+/// > single(1) |> to_list
+/// [1]
+///
+pub fn single(elem: element) -> Iterator(element) {
+ once(fn() { elem })
+}
- fn do_interleave(
- current: fn() -> Action(element),
- next: fn() -> Action(element),
- ) -> Action(element) {
- case current() {
- Stop -> next()
- Continue(e, next_other) ->
- Continue(e, fn() { do_interleave(next, next_other) })
- }
+fn do_interleave(
+ current: fn() -> Action(element),
+ next: fn() -> Action(element),
+) -> Action(element) {
+ case current() {
+ Stop -> next()
+ Continue(e, next_other) ->
+ Continue(e, fn() { do_interleave(next, next_other) })
}
+}
- /// Creates an iterator that alternates between the two given iterators
- /// until both have run out.
- ///
- /// ## Examples
- ///
- /// > from_list([1, 2, 3, 4]) |> interleave(from_list([11, 12, 13, 14])) |> to_list
- /// [1, 11, 2, 12, 3, 13, 4, 14]
- ///
- /// > from_list([1, 2, 3, 4]) |> interleave(from_list([100])) |> to_list
- /// [1, 100, 2, 3, 4]
- ///
- pub fn interleave(
- left: Iterator(element),
- with right: Iterator(element),
- ) -> Iterator(element) {
- fn() { do_interleave(left.continuation, right.continuation) }
- |> Iterator
- }
+/// Creates an iterator that alternates between the two given iterators
+/// until both have run out.
+///
+/// ## Examples
+///
+/// > from_list([1, 2, 3, 4]) |> interleave(from_list([11, 12, 13, 14])) |> to_list
+/// [1, 11, 2, 12, 3, 13, 4, 14]
+///
+/// > from_list([1, 2, 3, 4]) |> interleave(from_list([100])) |> to_list
+/// [1, 100, 2, 3, 4]
+///
+pub fn interleave(
+ left: Iterator(element),
+ with right: Iterator(element),
+) -> Iterator(element) {
+ fn() { do_interleave(left.continuation, right.continuation) }
+ |> Iterator
+}
- fn do_fold_until(
- continuation: fn() -> Action(e),
- f: fn(e, acc) -> list.ContinueOrStop(acc),
- accumulator: acc,
- ) -> acc {
- case continuation() {
- Stop -> accumulator
- Continue(elem, next) ->
- case f(elem, accumulator) {
- list.Continue(accumulator) -> do_fold_until(next, f, accumulator)
- list.Stop(accumulator) -> accumulator
- }
- }
+fn do_fold_until(
+ continuation: fn() -> Action(e),
+ f: fn(e, acc) -> list.ContinueOrStop(acc),
+ accumulator: acc,
+) -> acc {
+ case continuation() {
+ Stop -> accumulator
+ Continue(elem, next) ->
+ case f(elem, accumulator) {
+ list.Continue(accumulator) -> do_fold_until(next, f, accumulator)
+ list.Stop(accumulator) -> accumulator
+ }
}
+}
- /// Like `fold`, `fold_until` reduces an iterator of elements into a single value by calling a given
- /// function on each element in turn, but uses a `list.ContinueOrStop` to determine
- /// whether or not to keep iterating.
- ///
- /// If called on an iterator of infinite length then this function will only ever
- /// return if the give function returns list.Stop.
- ///
- ///
- /// ## Examples
- /// > let f = fn(e, acc) {
- /// > case e {
- /// > _ if e < 4 -> list.Continue(e + acc)
- /// > _ -> list.Stop(acc)
- /// > }
- /// > }
- /// >
- /// > [1, 2, 3, 4]
- /// > |> from_list
- /// > |> iterator.fold_until(from: acc, with: f)
- /// 6
- ///
- pub fn fold_until(
- over iterator: Iterator(e),
- from initial: acc,
- with f: fn(e, acc) -> list.ContinueOrStop(acc),
- ) -> acc {
- iterator.continuation
- |> do_fold_until(f, initial)
- }
+/// Like `fold`, `fold_until` reduces an iterator of elements into a single value by calling a given
+/// function on each element in turn, but uses a `list.ContinueOrStop` to determine
+/// whether or not to keep iterating.
+///
+/// If called on an iterator of infinite length then this function will only ever
+/// return if the give function returns list.Stop.
+///
+///
+/// ## Examples
+/// > let f = fn(e, acc) {
+/// > case e {
+/// > _ if e < 4 -> list.Continue(e + acc)
+/// > _ -> list.Stop(acc)
+/// > }
+/// > }
+/// >
+/// > [1, 2, 3, 4]
+/// > |> from_list
+/// > |> iterator.fold_until(from: acc, with: f)
+/// 6
+///
+pub fn fold_until(
+ over iterator: Iterator(e),
+ from initial: acc,
+ with f: fn(e, acc) -> list.ContinueOrStop(acc),
+) -> acc {
+ iterator.continuation
+ |> do_fold_until(f, initial)
}
diff --git a/src/gleam/string.gleam b/src/gleam/string.gleam
index 0703dd7..d9d2c63 100644
--- a/src/gleam/string.gleam
+++ b/src/gleam/string.gleam
@@ -2,7 +2,7 @@
//// text surrounded by `"double quotes"`.
import gleam/string_builder
-import gleam/iterator
+import gleam/iterator.{Iterator}
import gleam/list
import gleam/order
import gleam/result
@@ -494,28 +494,13 @@ pub fn join(strings: List(String), with separator: String) -> String {
/// > pad_left("121", to: 2, with: ".")
/// "121"
///
-pub fn pad_left(string: String, to length: Int, with pad_string: String) {
- do_pad_left(string, length, pad_string)
-}
-
-if erlang {
- type Direction {
- Leading
- Trailing
- Both
- }
-
- fn do_pad_left(string: String, to length: Int, with pad_string: String) {
- erl_pad(string, length, Leading, pad_string)
- }
-
- external fn erl_pad(String, Int, Direction, String) -> String =
- "gleam_stdlib" "string_pad"
-}
-
-if javascript {
- external fn do_pad_left(String, Int, String) -> String =
- "../gleam_stdlib.js" "pad_left"
+pub fn pad_left(string: String, to desired_length: Int, with pad_string: String) {
+ let current_length = length(string)
+ let to_pad_length = desired_length - current_length
+ padding(to_pad_length, pad_string)
+ |> iterator.append(iterator.single(string))
+ |> iterator.to_list
+ |> concat
}
/// Pads a string on the right until it has a given length.
@@ -531,19 +516,26 @@ if javascript {
/// > pad_right("121", to: 2, with: ".")
/// "121"
///
-pub fn pad_right(string: String, to length: Int, with pad_string: String) {
- do_pad_right(string, length, pad_string)
-}
-
-if erlang {
- fn do_pad_right(string: String, to length: Int, with pad_string: String) {
- erl_pad(string, length, Trailing, pad_string)
- }
+pub fn pad_right(
+ string: String,
+ to desired_length: Int,
+ with pad_string: String,
+) {
+ let current_length = length(string)
+ let to_pad_length = desired_length - current_length
+ iterator.single(string)
+ |> iterator.append(padding(to_pad_length, pad_string))
+ |> iterator.to_list
+ |> concat
}
-if javascript {
- external fn do_pad_right(String, Int, String) -> String =
- "../gleam_stdlib.js" "pad_right"
+fn padding(size: Int, pad_string: String) -> Iterator(String) {
+ let pad_length = length(pad_string)
+ let num_pads = size / pad_length
+ let extra = size % pad_length
+ iterator.repeat(pad_string)
+ |> iterator.take(num_pads)
+ |> iterator.append(iterator.single(slice(pad_string, 0, extra)))
}
/// Removes whitespace on both sides of a String.
@@ -562,6 +554,12 @@ if erlang {
erl_trim(string, Both)
}
+ type Direction {
+ Leading
+ Trailing
+ Both
+ }
+
external fn erl_trim(String, Direction) -> String =
"string" "trim"
}
diff --git a/src/gleam_stdlib.js b/src/gleam_stdlib.js
index 65dd45c..89908de 100644
--- a/src/gleam_stdlib.js
+++ b/src/gleam_stdlib.js
@@ -158,11 +158,3 @@ export function trim_left(string) {
export function trim_right(string) {
return string.trimRight();
}
-
-export function pad_left(string, length, pad) {
- return string.padStart(length, pad);
-}
-
-export function pad_right(string, length, pad) {
- return string.padEnd(length, pad);
-}