Coder Social home page Coder Social logo

tinsel's Introduction

tinsel

Decorating functions in R.

Travis-CI Build Status codecov cran status

The tinsel package adds function decorators to R using a special #. comment. Decorators are a means of transforming a function without needing to rewrite the function. They allow for easy integration of new code onto existing code. These benefits are illustrated below with an example about object classes.

What are decorators all about?

Say we develop a Spaceship class. In addition to our standard Spaceship class, we also need a class for a spaceship with a hyperdrive. So we develop a SpaceshipWithHyperdrive class. Hoever, given all our spaceships we also need a mothership. So we develop a MotherSpaceship. But, what if the mothership also has a hyperdrive? In this have to add two new classes, MotherSpaceship and MotherSpaceshipWithHyperdrive. While the situation is not unmanageable adding a new class for each spaceship feature, or even for every couple of features, is less than ideal.

Instead we can create a decorator for each new spaceship feature. Let's call these decorators HyperdriveSpaceshipDecorator and MotherSpaceshipDecorator. The HyperdriveSpaceshipDecorator takes the Spaceship class, with all the Spaceship methods, and adds hyperdrive-related methods. Thus, we are saved the trouble of copying over the Spaceship methods to a new class as would have been necessary to create the SpaceshipWithHyperdrive, MotherSpaceship, and MotherSpaceshipWithHyperdrive classes.

R Decorators (and your decorators)

Let's create a function if_warning which wraps a function f such that if f(...) would generate a warning a default value is returned instead, otherwise f(...) is returned.

if_warning <- function(f, default) {
  function(...) {
    tryCatch(
      f(...),
      warning = function(w) {
        default
      })
  }
}

Now let's transform the default mean function, so instead of generating a warning the function returns Inf. Great!

mean_inf <- if_warning(mean, Inf)

# give it a try!
mean_inf(1:5)
mean_inf(c(1, 'two', 3))

Here is where the special comment #. comes in. The above code can be rewritten as the following,

#. if_warning(Inf)
mean_inf <- mean

The special comment #. is used to denote a function decorator. In this example, #. if_warning denotes if_warning as the decorator of the decoratee mean. mean is passed as the first argument to if_warning and Inf as the second argument. The result of transforming mean with if_warning is assigned to mean_inf.

In order to see the decorator annotation example in action, save the above code in a file, source the file using source_decoratees, and then call mean_inf once more. (Gentle reminder, the output is expected to be the same)

Installing tinsel

tinsel is now available on CRAN.

install.packages('tinsel')

You can install the latest version of tinsel using devtools (currently even with version 0.0.1 on CRAN).

# install.packages('devtools')
devtools::install_github('nteetor/tinsel')

Check out the source_decoratees function to get started.

RStudio Addin

If you are working in RStudio the tinsel package includes an addin for the core function source_decoratees. To bind the addin to a keyboard shortcut in RStudio navigate to Tools > Addins > Browse Addins > Keyboard Shorcuts. For more information about the keyboard shortcuts checkout the RStudio support page. If you choose to setup a keyboard shortcut for the addin I recommend Alt+Shift+S since Cmd+Shift+S (or Ctrl+Shift+S on Linux and Windows) is the source active file shortcut. The end result is you can quickly load your decorated functions like you would source all functions from the active file.


Cheers, Nate.

tinsel's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

tinsel's Issues

Syntax for non REPL environments

I tried to use this library in a Shiny environment but is quite complex to integrate the current special comments syntax.

Have a look to this:
https://github.com/klmr/decorator

Maybe it would be great to have both options in only one library.

Another but much more complex solution is to make an environment aware of decorated functions like in data.table. Have no idea how to start this.

scanner statements

  • string literals
  • numeric literals
  • negative numeric literals
  • arguments to decorators
  • assignments

backticks, white space, and variable names

When parsing variable names one might safely assume "^\\s*[^ ]+" could do the trick.

However, if a variable is assigned to ` (yep)` or `white space` the regular expression above will fail to parse correctly. I want to believe white space would not get used in a variable name, but the possibility exists.

The problem will not be addressed until numerous complaints flood in.

Documentation Suggestion

You might want to create a vignette and/or modify your description to make it more obvious that decorators operate on source files rather than say in an interactive session. Can tinsel be used in package authorship or is it just for files you would directly source?

documenting decorated functions

  1. What are best practices for documenting decorated functions?

    • How do other languages handle documenting decorated functions?
  2. How to double check documented decorators against actual function decorators?

    • Add roxygen tag?

passing connection to `source_decoratees`

If a connection object is passed to source_decoratees and the connection text references a decorator found in a separate file an error occurs,

source_decoratees(
  textConnection("
    #. fizz$bar
    example <- function() 'minimal'
  ")
)

The immediate error is a result of passing a connection object to dirname(), a character string is expected. The larger issue is connection objects have no information regarding file location. In general they would not need to, but in the case of the new source selection addin the text connection is from a specific file and we need to know which file.

fix grammar

The current grammar used by the parser does not handle multiple decorators well, if at all.

decorators in separate files

The initial release of tinsel (0.0.1), source_decoratees expects decorators to be defined in the same file as their decoratee. Allowing decorators to live in a separate file would be beneficial for the programmer and would allow flexible file organization.

In python one can import a decorator buzz like so,

import bazz

@bazz.buzz
class fizz:
    pass

If we consider using something of this fashion for tinsel the following operators are already used for a similar, but not indentical, task: ::, :::. Using :::: seems excessive: #. bazz::::buzz. Note that there would not be an import bazz equivalent. One could already work around this definition issue using source if they felt inclined to do so.

Is there an alternative symbol we could use?

scanner `expected()` vs parser `expected()`

Within the parser class, the expected() function returns a token if the token was expected, otherwise an error is thrown.

Within scanner expected() was removed from the traversal class, is now part of the scanner class, and behaves similarly to the parser expected function. However, the methods of scanner do not currently utilize the return value of expected(). Reviewing and refactoring scanner to utilize the return value of expected could prove useful.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.