# apply_attr

[![Build Status](http://img.shields.io/travis/regexident/apply_attr.svg?style=flat-square)](https://travis-ci.org/regexident/apply_attr)
[![Downloads](https://img.shields.io/crates/d/apply_attr.svg?style=flat-square)](https://crates.io/crates/apply_attr/)
[![Version](https://img.shields.io/crates/v/apply_attr.svg?style=flat-square)](https://crates.io/crates/apply_attr/)
[![License](https://img.shields.io/crates/l/apply_attr.svg?style=flat-square)](https://crates.io/crates/apply_attr/)

## Synopsis

A syntax extension providing higher-order attributes to Rust.

## Motivation

Sometimes it would be desirable to be able to apply certain attributes to all items in a scope (`mod`, `trait` or `impl`). The **`apply_attr`** crate aims to provide a versatile API for this.

Possible use-cases would be:

- Make all structs in mod `xyz` use `#[derive(PartialEq)]`.
- Mark all methods in a certain `impl` with `#[inline(never)]` (for profiling, e.g.).
- …

## Getting Started

Add the most recent [version](https://crates.io/crates/apply_attr) of `apply_attr`  
to your dependencies in your project's `Cargo.toml`.

Then add …

```rust
#![feature(plugin)]
#![plugin(apply_attr)]
```

… to your crate's root file (e.g. `lib.rs`, `main.rs`).

Once that's done you're ready to play!

# Example

```rust
#![feature(plugin)]
#![plugin(apply_attr)]

// Make all top-level structs as well as those
// within top-level mods implement `PartialEq`:
#![apply_attr(to(structs, mods(structs)), as_default(derive(PartialEq)))]

pub struct Foo;

mod Bar {
  pub struct Baz;
  // ...
}

// Disable inlining when `no_inline` feature is present:
#[cfg_attr(feature = "no_inline", apply_attr(to(fns), as_override(inline(never))))]
impl Blee {
  fn foo(&self) { ... }
  fn bar(&self) { ... }
  fn baz(&self) { ... }
  fn blee(&self) { ... }
}

fn main() {
  Foo == Foo;
  Bar::Baz == Bar::Baz;
}
```

## API Reference

The `apply_attr` syntax extension provides a single higher-order attribute,  
conveniently named `apply_attr` expecting two arguments:

1. `to(...)` (with `...` being a list of zero or more selectors).
2. `as_default(...)` or `as_override(...)` (with `...` being a list of zero or more attributes).

Resulting either of:

```rust
#[apply_attr(to(...), as_default(...))]
#[apply_attr(to(...), as_override(...))]
```

The first argument (`to(...)`) accepts a nested list of item selectors.

## Selectors

Selectors behave similar to CSS selectors:

As such a CSS selector like `div > span, p` would translate to `to(div(span), p)`.

### Flat Selectors

The following selectors are supported:

```rust
consts
crates
def_impls
enums
fgn_mods
fns
impls
macros
mods
statics
structs
traits
types
uses
```

### Nested Selectors

With the following ones allowing for nesting:

```rust
mods(...)
impls(...)
traits(...)
```

Nested selectors denote direct ancestry equivalent to CSS's `outer > inner` path operator.

## Attributes

### Default

Attributes can either be applied as using `as_default(...)`, in which case …

```rust
#[apply_attr(to(fns), as_default(inline(never)))]
impl Foo {
  #[inline(always)]
  fn foo() { ... }
}
```

… will be turned into …

```rust
impl Foo {
  #[inline(always)]
  fn foo() { ... }
}
```

… upon completion.

### Overriding

Or using `as_override(...)`, in which case …

```rust
#[apply_attr(to(fns), as_override(inline(never)))]
impl Foo {
  #[inline(always)]
  fn foo() { ... }
}
```

… will be turned into …

```rust
impl Foo {
  #[inline(never)]
  fn foo() { ... }
}
```

… upon completion.

## Debugging

To see how the attributes were applied compile your crate using this (requires `nightly`):

```bash
cargo rustc -- -Z unstable-options --pretty=expanded
```

## Contributing

Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our [code of conduct](https://www.rust-lang.org/conduct.html),  
and the process for submitting pull requests to us.

## Versioning

We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/regexident/apply_attr/tags).

## Authors

* **Vincent Esche** – *Initial work* – [Regexident](https://github.com/Regexident)

See also the list of [contributors](https://github.com/regexident/apply_attr/contributors) who participated in this project.

## License

This project is licensed under the [**MPL-2.0**](https://www.tldrlegal.com/l/mpl-2.0) – see the [LICENSE.md](LICENSE.md) file for details.
