manuelmorales/forwarding-dsl

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# ForwardingDsl

[![Gem Version](https://badge.fury.io/rb/forwarding_dsl.svg)](http://badge.fury.io/rb/forwarding_dsl)
[![Code Climate](https://codeclimate.com/github/manuelmorales/forwarding-dsl/badges/gpa.svg)](https://codeclimate.com/github/manuelmorales/forwarding-dsl)
[![Test Coverage](https://codeclimate.com/github/manuelmorales/forwarding-dsl/badges/coverage.svg)](https://codeclimate.com/github/manuelmorales/forwarding-dsl/coverage)
[![Build Status](https://travis-ci.org/manuelmorales/forwarding-dsl.svg)](https://travis-ci.org/manuelmorales/forwarding-dsl)

ForwardingDsl makes it easy to build user friendly DSLs.
While `ForwardingDsl.run` will allow you to create a DSL from a regular object,
`ForwardingDsl::Getsetter` will make easy to declare attributes for it.
It is inspired by the blog post [instance_eval with access to outside scope](http://djellemah.com/blog/2013/10/09/instance-eval-with-access-to-outside-scope/).

Benefits:

* Makes it trivial to provide a DSL. Wrap anything with `ForwardingDsl.run()` and you are done.
* Unlike `instance_eval`, only the public API of your object is reachable from the DSL.
* Unlike `instance_eval`, methods available outside of the DSL are still available inside.
* Compatible with the explicit `yield(self)`, no DSL, style.


## Usage

Wrap any object to make a DSL out of it:

```ruby
require 'forwarding_dsl'

App = Struct.new(:host, :port)
app = App.new("localhost", 80)

ForwardingDsl.run app do
  host
end
# => "localhost"
```

Use `ForwardingDsl::Getsetter` to declare attributes that receive values
on a declarative way:

```ruby
class MyApp
  include ForwardingDsl::Getsetter

  getsetter :host, :port

  def initialize &block
    ForwardingDsl.run(my_object, &block)
  end
end

app = MyApp.new do
  host 'localhost'
  port 80
end

app.host # => 'localhost'
app.port # => 80
```

`ForwardingDsl` is also compatible with the classic `yield(self)`.
The context of the block will remain untouched in that case:

```ruby
app = MyApp.new do |a|
  a.host 'localhost'
  a.port = 80
end
```

Methods available outside of the DSL block are also available inside:

```ruby
def port_configuration
  configuration[:port]
end

app = MyApp.new do
  port port_configuration
end
```

If needed, the yielded object is available explicitly through `this`
and the outer context through `that`:

```ruby
def port_configuration
  configuration[:port]
end

app = MyApp.new do
  this.port = that.port_configuration
end
```


## Contributing

Do not forget to run the tests with:

```bash
rake
```

And bump the version with any of:

```bash
$ gem bump --version 1.1.1       # Bump the gem version to the given version number
$ gem bump --version major       # Bump the gem version to the next major level (e.g. 0.0.1 to 1.0.0)
$ gem bump --version minor       # Bump the gem version to the next minor level (e.g. 0.0.1 to 0.1.0)
$ gem bump --version patch       # Bump the gem version to the next patch level (e.g. 0.0.1 to 0.0.2)
```


## License

Released under the MIT License.
See the [LICENSE](LICENSE.txt) file for further details.