How to make this user-defined function pipe-friendly?

I have this user-defined function that works stand-alone but not in a dplyr pipe.
What am I doing wrong?

# Function to add the object name as a new dataframe column, and 
# move it to first position

library(tidyverse, quietly=TRUE)

name_as_column <- function(.data) {
  object_name <- as.character(substitute(.data))
  .data$obj_name <- object_name
  y <- "obj_name"
  .data <- .data[,c(y, setdiff(names(.data), y))]
return(.data)
}

# Works here
head(name_as_column(mtcars))
#>                   obj_name  mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4           mtcars 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag       mtcars 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
#> Datsun 710          mtcars 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
#> Hornet 4 Drive      mtcars 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
#> Hornet Sportabout   mtcars 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
#> Valiant             mtcars 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
head(name_as_column(iris))
#>   obj_name Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1     iris          5.1         3.5          1.4         0.2  setosa
#> 2     iris          4.9         3.0          1.4         0.2  setosa
#> 3     iris          4.7         3.2          1.3         0.2  setosa
#> 4     iris          4.6         3.1          1.5         0.2  setosa
#> 5     iris          5.0         3.6          1.4         0.2  setosa
#> 6     iris          5.4         3.9          1.7         0.4  setosa

# Doesn't work in dplyr pipe
mtcars %>% 
  name_as_column(.) %>% 
  head()
#>                   obj_name  mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4                . 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag            . 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
#> Datsun 710               . 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
#> Hornet 4 Drive           . 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
#> Hornet Sportabout        . 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
#> Valiant                  . 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

Created on 2021-02-12 by the reprex package (v1.0.0)

There's already a handy function available where you can, optionally, provide the new column name.

library(tidyverse)

mtcars %>% 
  rownames_to_column(var = "obj_name") %>% 
  head()
#>            obj_name  mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> 1         Mazda RX4 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
#> 2     Mazda RX4 Wag 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
#> 3        Datsun 710 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
#> 4    Hornet 4 Drive 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
#> 5 Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
#> 6           Valiant 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

Created on 2021-02-12 by the reprex package (v1.0.0)

Is this helpful? Or is your function more intended as an example to get an hand on using your own defined function within pipes?

I reread your post and I believe I now better understand what your aim is.
Is the following useful?

library(tidyverse)

name_as_column <- function(.data, obj_name = "not_provided") {

  obj_value <- {{obj_name}} %>% as.character()
  
  df <- .data %>% 
    ## add column `obj_name` with `obj_value`
    mutate(obj_name = obj_value) %>% 
    select(obj_name, everything()) %>%
    identity()
  ## return the result
  df
  }

## make sure to add the dot to the substitute function!
mtcars %>% 
  name_as_column(obj_name = substitute(.)) %>% 
  head()
#>                   obj_name  mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4           mtcars 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag       mtcars 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
#> Datsun 710          mtcars 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
#> Hornet 4 Drive      mtcars 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
#> Hornet Sportabout   mtcars 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
#> Valiant             mtcars 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

mtcars %>% 
  name_as_column(obj_name = "whatever you prefer") %>% 
  head()
#>                              obj_name  mpg cyl disp  hp drat    wt  qsec vs am
#> Mazda RX4         whatever you prefer 21.0   6  160 110 3.90 2.620 16.46  0  1
#> Mazda RX4 Wag     whatever you prefer 21.0   6  160 110 3.90 2.875 17.02  0  1
#> Datsun 710        whatever you prefer 22.8   4  108  93 3.85 2.320 18.61  1  1
#> Hornet 4 Drive    whatever you prefer 21.4   6  258 110 3.08 3.215 19.44  1  0
#> Hornet Sportabout whatever you prefer 18.7   8  360 175 3.15 3.440 17.02  0  0
#> Valiant           whatever you prefer 18.1   6  225 105 2.76 3.460 20.22  1  0
#>                   gear carb
#> Mazda RX4            4    4
#> Mazda RX4 Wag        4    4
#> Datsun 710           4    1
#> Hornet 4 Drive       3    1
#> Hornet Sportabout    3    2
#> Valiant              3    1

## use default value as defined in the function
mtcars %>% 
  name_as_column() %>% 
  head()
#>                       obj_name  mpg cyl disp  hp drat    wt  qsec vs am gear
#> Mazda RX4         not_provided 21.0   6  160 110 3.90 2.620 16.46  0  1    4
#> Mazda RX4 Wag     not_provided 21.0   6  160 110 3.90 2.875 17.02  0  1    4
#> Datsun 710        not_provided 22.8   4  108  93 3.85 2.320 18.61  1  1    4
#> Hornet 4 Drive    not_provided 21.4   6  258 110 3.08 3.215 19.44  1  0    3
#> Hornet Sportabout not_provided 18.7   8  360 175 3.15 3.440 17.02  0  0    3
#> Valiant           not_provided 18.1   6  225 105 2.76 3.460 20.22  1  0    3
#>                   carb
#> Mazda RX4            4
#> Mazda RX4 Wag        4
#> Datsun 710           1
#> Hornet 4 Drive       1
#> Hornet Sportabout    2
#> Valiant              1

Created on 2021-02-12 by the reprex package (v1.0.0)

Hi @lars,
Many thanks for your suggestions.
I have settled on this compromise which provides a message about use of this function in a pipe:

name_as_column <- function(.data, obj_name = "") {
  require(dplyr)
  if(obj_name=="") {
    message("Did you mean to use 'name_as_column(obj_name=substitute(.))' in a pipe?")
    obj_name <- "not_provided"
  }
  obj_value <- {{obj_name}} %>% as.character()
  df <- .data %>%
    mutate(obj_name = obj_value) %>%
    select(obj_name, everything())
  return(df)
  }

head(name_as_column(mtcars))
#> Loading required package: dplyr
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
#> Did you mean to use 'name_as_column(obj_name=substitute(.))' in a pipe?
#>                       obj_name  mpg cyl disp  hp drat    wt  qsec vs am gear
#> Mazda RX4         not_provided 21.0   6  160 110 3.90 2.620 16.46  0  1    4
#> Mazda RX4 Wag     not_provided 21.0   6  160 110 3.90 2.875 17.02  0  1    4
#> Datsun 710        not_provided 22.8   4  108  93 3.85 2.320 18.61  1  1    4
#> Hornet 4 Drive    not_provided 21.4   6  258 110 3.08 3.215 19.44  1  0    3
#> Hornet Sportabout not_provided 18.7   8  360 175 3.15 3.440 17.02  0  0    3
#> Valiant           not_provided 18.1   6  225 105 2.76 3.460 20.22  1  0    3
#>                   carb
#> Mazda RX4            4
#> Mazda RX4 Wag        4
#> Datsun 710           1
#> Hornet 4 Drive       1
#> Hornet Sportabout    2
#> Valiant              1
head(name_as_column(mtcars, obj_name="testing_name"))
#>                       obj_name  mpg cyl disp  hp drat    wt  qsec vs am gear
#> Mazda RX4         testing_name 21.0   6  160 110 3.90 2.620 16.46  0  1    4
#> Mazda RX4 Wag     testing_name 21.0   6  160 110 3.90 2.875 17.02  0  1    4
#> Datsun 710        testing_name 22.8   4  108  93 3.85 2.320 18.61  1  1    4
#> Hornet 4 Drive    testing_name 21.4   6  258 110 3.08 3.215 19.44  1  0    3
#> Hornet Sportabout testing_name 18.7   8  360 175 3.15 3.440 17.02  0  0    3
#> Valiant           testing_name 18.1   6  225 105 2.76 3.460 20.22  1  0    3
#>                   carb
#> Mazda RX4            4
#> Mazda RX4 Wag        4
#> Datsun 710           1
#> Hornet 4 Drive       1
#> Hornet Sportabout    2
#> Valiant              1

mtcars %>%
  name_as_column(obj_name=substitute(.)) %>%
  head()
#>                   obj_name  mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4           mtcars 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag       mtcars 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
#> Datsun 710          mtcars 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
#> Hornet 4 Drive      mtcars 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
#> Hornet Sportabout   mtcars 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
#> Valiant             mtcars 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

mtcars %>%
  name_as_column() %>%
  head()
#> Did you mean to use 'name_as_column(obj_name=substitute(.))' in a pipe?
#>                       obj_name  mpg cyl disp  hp drat    wt  qsec vs am gear
#> Mazda RX4         not_provided 21.0   6  160 110 3.90 2.620 16.46  0  1    4
#> Mazda RX4 Wag     not_provided 21.0   6  160 110 3.90 2.875 17.02  0  1    4
#> Datsun 710        not_provided 22.8   4  108  93 3.85 2.320 18.61  1  1    4
#> Hornet 4 Drive    not_provided 21.4   6  258 110 3.08 3.215 19.44  1  0    3
#> Hornet Sportabout not_provided 18.7   8  360 175 3.15 3.440 17.02  0  0    3
#> Valiant           not_provided 18.1   6  225 105 2.76 3.460 20.22  1  0    3
#>                   carb
#> Mazda RX4            4
#> Mazda RX4 Wag        4
#> Datsun 710           1
#> Hornet 4 Drive       1
#> Hornet Sportabout    2
#> Valiant              1

Created on 2021-02-13 by the reprex package (v1.0.0)

1 Like

Hi @Yarnabrina,
Thanks for your suggestions. I couldn't make progress with this approach but see my response to @lars.

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.