Giter Site home page Giter Site logo

decorator's Introduction

Elixir function decorators

Build Status Hex pm

A function decorator is a "@decorate" annotation that is put just before a function definition. It can be used to add extra functionality to Elixir functions. The runtime overhead of a function decorator is zero, as it is executed on compile time.

Examples of function decorators include: loggers, instrumentation (timing), precondition checks, et cetera.

Some remarks in advance

Some people think function decorators are a bad idea, as they can perform magic stuff on your functions (side effects!). Personally, I think they are just another form of metaprogramming, one of Elixir's selling points. But use decorators wisely, and always study the decorator code itself, so you know what it is doing.

Decorators are always marked with the @decorate literal, so that it's clear in the code that decorators are being used.

Installation

Add decorator to your list of dependencies in mix.exs:

def deps do
  [{:decorator, "~> 0.0"}]
end

You can now define your function decorators.

Usage

Function decorators are macros which you put just before defining a function. It looks like this:

defmodule MyModule do
  use PrintDecorator

  @decorate print()
  def square(a) do
    a * a
  end
end

Now whenever you call MyModule.square(), you'll see the message: Function called: square in the console.

Defining the decorator is pretty easy. Create a module in which you use the Decorator.Define module, passing in the decorator name and arity, or more than one if you want.

The following declares the above @print decorator which prints a message every time the decorated function is called:

defmodule PrintDecorator do
  use Decorator.Define, [print: 0]

  def print(body, context) do
    quote do
      IO.puts("Function called: " <> Atom.to_string(unquote(context.name)))
      unquote(body)
    end
  end

end

The arguments to the decorator function (the def print(...)) are the function's body (the AST), as well as a context argument which holds information like the function's name, defining module, arity and the arguments AST.

Compile-time arguments

Decorators can have compile-time arguments passed into the decorator macros.

For instance, you could let the print function only print when a certain logging level has been set:

@decorate print(:debug)
def foo() do
...

In this case, you specify the arity 1 for the decorator:

defmodule PrintDecorator do
  use Decorator.Define, [print: 1]

And then your print/3 decorator function gets the level passed in as the first argument:

def print(level, body, context) do
# ...
end

Decorator context

Besides the function body AST, the decorator function also gets a context argument passed in. This context holds information about the function being decorated, namely its module, function name, arity, and arguments as a list of AST nodes.

The print decorator can print its function name like this:

def print(body, context) do
  Logger.debug("Function #{context.name}/#{context.arity} called in module #{context.module}!"
end

Even more advanced, you can use the function arguments in the decorator. To create an is_authorized decorator which performs some checks on the Phoenix %Conn{} structure, you can create a decorator function like this:

def is_authorized(body, %{args: [conn, _params]}) do
  quote do
    if unquote(conn).assigns.user do
      unquote(body)
    else
      unquote(conn)
      |> send_resp(401, "unauthorized")
      |> halt()
    end
  end
end

decorator's People

Contributors

sobolevn avatar vic avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

Forkers

isabella232

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.