• Stars
    star
    373
  • Rank 109,631 (Top 3 %)
  • Language
    Elixir
  • License
    MIT License
  • Created over 7 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Function decorators for Elixir

Elixir function decorators

Build Status Module Version Hex Docs Total Download License Last Updated

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, "~> 1.2"}
  ]
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 abstract syntax tree (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

Decorating all functions in a module

A shortcut to decorate all functions in a module is to use the @decorate_all attribute, as shown below. It is important to note that the @decorate_all attribute only affects the function clauses below its definition.

defmodule MyApp.APIController
  use MyBackend.LoggerDecorator

  @decorate_all log_request()

  def index(_conn, params) do
    # ...
  end

  def detail(_conn, params) do
    # ...
  end

In this example, the log_request() decorator is applied to both index/2 and detail/2.

Functions with multiple clauses

If you have a function with multiple clauses, and only decorate one clause, you will notice that you get compiler warnings about unused variables and other things. For functions with multiple clauses the general advice is this: You should create an empty function head, and call the decorator on that head, like this:

defmodule DecoratorFunctionHead do
  use DecoratorFunctionHead.PrintDecorator

  @decorate print()
  def hello(first_name, last_name \\ nil)

  def hello(:world, _last_name) do
    :world
  end

  def hello(first_name, last_name) do
    "Hello #{first_name} #{last_name}"
  end
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, function kind, 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} with kind #{context.kind} 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

Copyright (c) 2016 Arjan Scherpenisse

This library is MIT licensed. See the LICENSE for details.

More Repositories

1

singleton

Global, supervised singleton processes for Elixir
Elixir
103
star
2

ast_ninja

The Elixir AST explorer
Erlang
75
star
3

pkgx

Build .deb packages from Erlang releases
Erlang
61
star
4

sworm

A user-friendly distributed process registry and process supervisor
Elixir
33
star
5

exstatic

Compile static files into Elixir bytecode and serve them from memory
Elixir
33
star
6

pixels

Elixir library to read pixels from a PNG file, using libpng (using a NIF)
C
22
star
7

gnome-shell-go-to-last-workspace

Extension for the Gnome Shell to quickly toggle between two workspaces
JavaScript
19
star
8

scribble

Elixir/Phoenix collaborative drawing board demonstration project
Elixir
17
star
9

nerves_io_rc522

RC522 RFID reader support for Nerves
C
16
star
10

espotify

Erlang for your music (libspotify wrapper)
C
13
star
11

instantVideoRecord

No-latency video recording library for Android using ffmpeg
Java
13
star
12

dag

Directed Acyclic Graph (DAG) implementation in Elixir
Elixir
13
star
13

mod_shop

Webshop module for Zotonic
CSS
11
star
14

compiler_cache

Elixir LRU cache for compiling expressions into functions.
Elixir
10
star
15

starpy

Python + Twisted protocol that provides access to the Asterisk PBX's Manager Interface (AMI) and Fast Asterisk Gateway Interface (FastAGI)
Python
9
star
16

stick.im

Source code for stick.im website
Erlang
8
star
17

NoCatSplash

C
7
star
18

cookie_store

Elixir cookie storage
Elixir
7
star
19

vsntool

Lightweight version number utility
Elixir
6
star
20

persi

Persi: Erlang persistence layer
Erlang
6
star
21

geoheap

Erlang-based geoservices aggregation / visualisation
Erlang
6
star
22

absinthe_dsl

Elixir DSL for constructing GraphQL queries
Elixir
5
star
23

zclient

Zotonic API commandline access utility
Python
5
star
24

erlang_xlsx

Excel file writer
Erlang
4
star
25

mod_angular

Angular JS Zotonic interfacing
Erlang
4
star
26

cluttershaderpython

Example code for creating clutter shaders in Python. Uses GObject introspection.
Python
4
star
27

mod_search_solr

Zotonic module for Solr support
JavaScript
4
star
28

zotonic-vagrant-tutorial

EUC 2013 Zotonic tutorial
Erlang
4
star
29

ui-metaframe

jQuery UI widget for a on-hover information box
JavaScript
3
star
30

nerves_io_nfc

Interact with libnfc-compatible USB NFC readers
Elixir
3
star
31

miraclethings

The MiracleThings website source code
HTML
3
star
32

mod_asterisk

Asterisk module for Zotonic based on eastrisk
Erlang
3
star
33

nx-intent-classifier-livebook

Intent classifier in a Livebook, for the Elixir Amsterdam meetup, nov 2021
3
star
34

amazonproductapi

Erlang library for Amazon Product affiliate API
Erlang
3
star
35

mod_slideshow

Slideshow module for Zotonic
Erlang
3
star
36

playgo

Geo-aggregating song data in Zotonic
Erlang
3
star
37

unixsup

Erlang gen_server which supervises a unix daemon.
Erlang
3
star
38

silentmobiledisco

Location-based "silent mobile disco" web app (jQuery Mobile + Angular JS)
Erlang
3
star
39

z-url-shortener-tutorial

Support code for the URL shortener tutorial for Zotonic
2
star
40

mod_adyen

Adyen payment processor integration for Zotonic
Erlang
2
star
41

goldenage-backend

Hollanders van de Gouden Eeuw backend code
Erlang
2
star
42

swarm-takeover-demo

Demonstration for Swarm process takeover
Elixir
2
star
43

mod_pubsub

Pubsub for Zotonic
Erlang
2
star
44

elisp

Elixir
2
star
45

idefix

Elixir
2
star
46

ButtonKeyboardProject

An Arduino project for using pushbuttons as HID keyboard
C
2
star
47

poldercast

(incomplete) WIP implementation of the P2P pubsub system http://acropolis.cs.vu.nl/~spyros/www/papers/PolderCast.pdfβ€Ž
Erlang
2
star
48

epush

Erlang PUbSubHubbub implementation
Erlang
2
star
49

Facebook-Cruise-Control

work-in-progress
JavaScript
2
star
50

mod_audio_echonest

Echonest API for Zotonic
Erlang
2
star
51

reprap-mendel-stuff

Reprap mendel models and configuration
2
star
52

sparked

Python+twisted-based development framework for interactive installations
Python
2
star
53

elixir-course

Elixir
1
star
54

plemp

Commandline flickr upload tool with gui progress bar
Python
1
star
55

nakednoord

Naked Noord - hackathon project for http://zonietdanto.ch festival
Erlang
1
star
56

chef-zotonic-cookbook

Cookbook for Zotonic on hosted Chef
Ruby
1
star
57

FeedReader

Android example app
Java
1
star
58

jaysx

Erlang
1
star
59

mod_github

Zotonic module which implements a Github webhook
Erlang
1
star
60

gdx-platformer

HKU test platformer in libgdx
Java
1
star
61

dot-emacs

Emacs Lisp
1
star
62

miracletools-android

Utility library with commonly used classes and design patterns
Java
1
star
63

iteav2

iTea re-implementation
Python
1
star
64

testing

1
star
65

inlineLightbox

A lightbox script that is aware of its typographical context
JavaScript
1
star
66

mod_broadcast

Zotonic module to broadcast messages in the admin to other users
Erlang
1
star
67

mod_dets

Erlang term storage module for Zotonic
Erlang
1
star
68

mod_calendar

Zotonic module for calendar events and other resources with date ranges.
Erlang
1
star
69

embeddings-server-ref

Example implementation of an embeddings server
Python
1
star
70

hearushere-android

Hear us Here (android version)
Java
1
star
71

iforgiveyou

Python
1
star
72

ouroffice

Who's at @ouroffice?
Erlang
1
star
73

myoffice

Office-co-worker notification on steroids
Erlang
1
star
74

erlang-summer-school

UvA summer school code and assignment
Erlang
1
star
75

escpos

ESC/POS text printing library (thermal Epson USB printers) for Elixir
Elixir
1
star
76

xepcache

In-memory caching server for Elixir, wrapper around Erlang's depcache
Elixir
1
star
77

debian-twisted-gears

The debianization of twisted-gears
Python
1
star
78

exdocker

Mix task to build a docker image from an Elixir project
Elixir
1
star
79

ccdemo

Compiler cache demonstration
Elixir
1
star
80

jb

Erlang-powered REST API Spotify party shuffle jukebox thing. Beta. do not use.
JavaScript
1
star
81

ex_patcher

Elixir
1
star
82

git-svn-util

Some convenience utilities to integrate git and svn.
1
star
83

mod_admin_event

Zotonic modlue for easy editing of event and event-related data in the admin
Erlang
1
star
84

mod_geo

Geographical functions for Zotonic with admin UI based on Google maps
Erlang
1
star
85

ring-doorbel-botsquad

Poll a ring doorbell and broadcast a giphy to a chatbot
Python
1
star
86

ParkeerBeter

Android app providing a better interface to smsparking.nl
Java
1
star
87

bootstrap3-upgrader

Script for upgrading Bootstrap CSS 2.x to 3.x based on string processing so safe to process template files which cannot be processed with DOM
Python
1
star
88

mod_exif

Zotonic module for extracting EXIF info from images on upload
Erlang
1
star