1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
use r_derive::*;
use crate::callable::core::*;
use crate::formals;
use crate::lang::*;
use crate::object::*;
/// Get Names of an Object
///
/// Returns the element names for vector-like objects, or names of
/// symbols assigned in environments.
///
/// # In-Language
///
/// ## Usage
///
/// ```custom,{class=rust}
/// names(x)
/// ```
///
/// ## Arguments
///
/// * `x`: An object from which to retrieve names
///
/// ## Examples
///
/// Accessing the names of elements in a `list`
///
/// ```custom,{class=r-repl}
/// names((a = 1, b = 2, c = 3))
/// ```
///
/// <div class="warning">
///
/// Unlike R, `names()` will always return a `character` vector, even if
/// no element is named.
///
/// </div>
///
/// ```custom,{class=r-repl}
/// names((1, 2, 3))
/// ```
///
/// Accessing names in an `environment`
///
/// ```custom,{class=r-repl}
/// x <- 3; y <- 4
/// names(environment())
/// ```
///
#[doc(alias = "names")]
#[builtin(sym = "names")]
#[derive(Debug, Clone, PartialEq)]
pub struct PrimitiveNames;
formals!(PrimitiveNames, "(x,)");
impl Callable for PrimitiveNames {
fn call_matched(&self, args: List, mut _ellipsis: List, stack: &mut CallStack) -> EvalResult {
let x = Obj::List(args).try_get_named("x")?.force(stack)?;
use Obj::*;
match x {
Null => Ok(Null),
Promise(..) => Ok(Null),
Vector(v) => match v.names() {
Some(n) => Ok(Obj::Vector(n.into())),
None => Ok(Null),
},
Expr(..) => Ok(Null), // handle arg lists?
Function(..) => Ok(Null), // return formals?
List(l) => match l.names() {
Some(n) => Ok(Obj::Vector(n.into())),
None => Ok(Null),
},
Environment(e) => {
let mut names = e.values.borrow().keys().cloned().collect::<Vec<String>>();
names.sort();
Ok(names.into())
}
}
}
}
#[cfg(test)]
mod test {
use crate::error::Error;
use crate::{r, r_expect};
#[test]
fn no_args() {
assert_eq!(r! { names() }, Error::Missing.into())
}
#[test]
fn from_environment() {
assert_eq!(r! { x <- 3; names(environment()) }, r! { "x" })
}
#[test]
fn from_list() {
assert_eq!(
r! { names(list(a = 1, b = 2, 3, d = 4)) },
r! { c("a", "b", NA, "d") }
)
}
#[test]
fn subset() {
r_expect! {{r#"
names([a = 1, b = 2][1]) == "a"
"#}}
}
#[test]
fn unnamed_atomic() {
r_expect! {{r#"
is_null(names([1, 2]))
"#}}
}
#[test]
fn named_atomic() {
r_expect! {{r#"
names([a = 1]) == "a"
"#}}
}
}