dwhelan/proc_extensions

View on GitHub
README.md

Summary

Maintainability
Test Coverage
[![Gem Version](https://badge.fury.io/rb/proc_extensions.png)](http://badge.fury.io/rb/proc_extensions)
[![Build Status](https://travis-ci.org/dwhelan/proc_extensions.png?branch=master)](https://travis-ci.org/dwhelan/proc_extensions)
[![Code Climate](https://codeclimate.com/github/dwhelan/proc_extensions/badges/gpa.svg)](https://codeclimate.com/github/dwhelan/proc_extensions)
[![Coverage Status](https://coveralls.io/repos/dwhelan/proc_extensions/badge.svg?branch=master&service=github)](https://coveralls.io/github/dwhelan/proc_extensions?branch=master)

### ProcSource Class

The gem includes the `ProcSource` class which provides
access to the proc extensions without monkey patching the `Proc` class itself.

You can create a `ProcSource` with either a proc as a parameter or by passing a block to `ProcSource`.

```ruby
p = proc { |a| a.to_s }


ps1 = ProcSource.new p
ps2 = ProcSource.new { |b| b.to_s }
```

You can use the `raw_source` method to return the original source and
the  `source` method to return the *sanitized* version of the source.

```ruby
ps1.source     # => "proc { |a| a.to_s }"
ps1.raw_source # => "proc { |a| a.to_s }"
ps1.to_s       # => "proc { |a| a.to_s }"
ps1.inspect    # => "proc { |a| a.to_s }"

ps1 == ps2     # => false
ps1.match ps2  # => true
```

You can create a `ProcSource` with no proc or with a `nil` proc and it will simply provide an empty string for `source`
`raw_source`, `to_s` and `inspect`. And two `ProcSource` objects created like this will be considered equal.

```ruby
ps1 = ProcSource.new
ps2 = ProcSource.new nil

ps1.source     # => ""
ps1.raw_source # => ""
ps1.to_s       # => ""
ps1.inspect    # => ""

ps1 == ps2     # => true
ps1.match ps2  # => true
```

# Proc Extensions

Extensions to Proc support source extraction and comparison.

Optionally methods can be added to the `Proc` class:
 * `inspect`: returns source code if it can be extracted
 * `source`, `raw_source`: returns source code
 * `==`: determines if two procs have exactly the same source code
 * `match`, `=~`: determines if two procs have the source code allowing for different parameter names

The above methods are not automatically included into the `Proc` class.
You need to explicitly include modules included in this gem.

**Note** This gem uses the [sourcify](https://github.com/ngty/sourcify) gem to extact proc source code. The `sourcify` gem
is no longer supported although it works as needed for the `proc_extensions` gem.

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'proc_extensions'
```

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install proc_extensions

## Usage

```
require proc_extensions
```

### Extensions to the Proc class

#### inspect Method

The `inspect` methods is added to `Proc` when `ProcExtensions::Inspect` is included with `Proc`:

```ruby
Proc.include ProcExtensions::Inspect        # Ruby 2
Proc.send :include, ProcExtensions::Inspect # Ruby 1.9.3

```

The `inspect` method will return the source code for the proc.

```ruby
p = proc { |a| a.to_s }
l = lambda { |a| a.to_s }

p.inspect # => "proc { |a| a.to_s }"
l.inspect # => "lambda { |a| a.to_s }"
```

If the source code cannot be extracted then the original `Proc#inspect` method will be called:

```ruby
# Can't get source if multiple procs declared on the same line
p = proc { proc {} }
p.inspect # => "#<Proc:0x007fe72b879b90>"
```

#### source Methods

The `source` and `raw_source` methods are added to `Proc` when `ProcExtensions::Source` is included with `Proc`:

```ruby
Proc.include ProcExtensions::Source        # Ruby 2
Proc.send :include, ProcExtensions::Source # Ruby 1.9.3
```

The `Proc#source` method will return the source code for the Proc with
white space and comments removed. The `raw_source` method will return the original source.

```ruby
p = proc { | a |  a.to_s  }
p.source # "proc { |a| a.to_s }"
p.raw_source # "proc { | a |  a.to_s  }"
```
Lambda source will have the prefix 'lambda' rather than 'proc':

```ruby
l = lambda { |a| a.to_s }
l.source # "lambda { |a| a.to_s }"
```

If the source cannot be extracted then an exception will be raised by the `sourcify` gem.

#### match Methods

The `match` and `=~` methods are added to `Proc` when `ProcExtensions::Match` is included with `Proc`:

```ruby
Proc.include ProcExtensions::Match        # Ruby 2
Proc.send :include, ProcExtensions::Match # Ruby 1.9.3
```

The `match(other)` method will return `true` if the procs are the same proc or
if the two procs have the same source code. The `=~` method is created as an alias for `match`.

```ruby
proc1 = proc {}
proc2 = proc {}
proc3 = proc { |a| a.to_s }

proc1.match(proc2) # => true
proc1.match(proc3) # => false

proc1 =~ proc2     # => true
proc1 =~ proc3     # => false
```

The source code for two procs are considered equal if they have the same body
even with different parameter names:

```ruby
proc1 = proc { |a| a.to_s }
proc2 = proc { |b| b.to_s }

proc1.match(proc2) # => true
```

If the procs are created via `&:method` then they will
be considered equal if they reference the same method:

```ruby
proc1 = proc(&:to_s)
proc2 = proc(&:to_s)
proc3 = proc(&:to_a)

proc1.match(proc2) # => true
proc1.match(proc3) # => false
```

If the source code cannot be extracted from either proc then `false` will be returned:

```ruby
# Can't get source if multiple procs declared on the same line
proc1 = proc { proc {} }
proc2 = proc { proc {} }

proc1.match(proc2) # => false
```

## Ruby Versions Supported

* 1.9.3
* 2.0
* 2.1
* 2.2

## Development

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/dwhelan/proc_extensions.
This project is intended to be a safe, welcoming space for collaboration, 
and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) 
code of conduct.

## License

The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).