remiprev/her — pull request #307 by toddmazierski (2014-12-10 22:42:10+00:00)
Title: Memoize user-defined methods during Her attribute definition

585e91c fixed a bug where attributes defined by Her would overwrite user-defined methods, however, it also appears to have introduced a performance regression. According to the profiler tool [ruby-prof](https://github.com/ruby-prof/ruby-prof), when initializing new objects, `Module#instance_methods` takes up a significant chunk of time (observed with Ruby 1.9.3 and 2.1.5).

If it's safe to assume that it's unlikely the set of user-defined methods will change *while* this method is being evaluated, memoizing them can result in a performance boost.

### Before

```ruby
Benchmark.realtime { User.all.count }
# => 1.083330651
```

#### ruby-prof report

```
Thread ID: 70011050636080
Fiber ID: 70011059749060
Total: 0.987885
Sort by: self_time

%self total self wait child calls name
40.69 0.402 0.402 0.000 0.000 6610 Module#instance_methods
5.14 0.051 0.051 0.000 0.000 64530 Symbol#to_s
3.82 0.057 0.038 0.000 0.019 19833 String#%
2.95 0.057 0.029 0.000 0.028 13702 Array#include?
2.43 0.050 0.024 0.000 0.026 19830 ActiveModel::AttributeMethods::ClassMethods#instance_method_already_implemented?
2.39 0.036 0.024 0.000 0.012 19530 ActiveSupport::HashWithIndifferentAccess#convert_key
2.15 0.021 0.021 0.000 0.000 67642 Symbol#==
2.03 0.069 0.020 0.000 0.049 9579 ActiveSupport::HashWithIndifferentAccess#[]=
1.92 0.028 0.019 0.000 0.009 10287 *ActiveSupport::HashWithIndifferentAccess#convert_value
1.85 0.075 0.018 0.000 0.057 19830 ActiveModel::AttributeMethods::ClassMethods::AttributeMethodMatcher#method_name
```

### After

```ruby
Benchmark.realtime { User.all.count }
# => 0.695653897
```

#### ruby-prof report

```
Thread ID: 69820109198100
Fiber ID: 69820121752620
Total: 0.606979
Sort by: self_time

%self total self wait child calls name
5.77 0.045 0.035 0.000 0.010 19833 String#%
5.35 0.032 0.032 0.000 0.000 64670 Symbol#to_s
4.92 0.059 0.030 0.000 0.029 13719 Array#include?
4.49 0.236 0.027 0.000 0.209 722 Hash#each
4.04 0.052 0.025 0.000 0.027 19830 ActiveModel::AttributeMethods::ClassMethods#instance_method_already_implemented?
3.90 0.036 0.024 0.000 0.012 19530 ActiveSupport::HashWithIndifferentAccess#convert_key
3.75 0.023 0.023 0.000 0.000 354 Module#instance_methods
3.59 0.022 0.022 0.000 0.000 67653 Symbol#==
3.28 0.070 0.020 0.000 0.050 9579 ActiveSupport::HashWithIndifferentAccess#[]=
3.15 0.064 0.019 0.000 0.045 19830 ActiveModel::AttributeMethods::ClassMethods::AttributeMethodMatcher#method_name
```