Typecasting performance


First, a before optimization picture:

````

hread ID: 70222187027160
Total: 19.178977
Sort by: self_time

 %self     total     self     wait    child    calls   name
 15.15      6.31     2.90     0.00     3.41   217683   ActiveAttr::Typecasting#typecaster_for 
 12.04      2.31     2.31     0.00     0.00  1964597   Kernel#hash 
  6.75     12.25     1.30     0.00    10.95   217684   ActiveAttr::TypecastedAttributes#_attribute_typecaster 
  5.40      2.83     1.04     0.00     1.80   217684   ActiveAttr::Typecasting#typecast_attribute 
  4.33     16.53     0.83     0.00    15.70   217684   ActiveAttr::TypecastedAttributes#attribute 
  4.10      0.79     0.79     0.00     0.00   449968   ActiveAttr::Attributes::ClassMethods#attributes 
  4.10      0.79     0.79     0.00     0.00   445170   ActiveAttr::AttributeDefinition#[] 
  4.01      1.83     0.77     0.00     1.06   217684   ActiveAttr::TypecastedAttributes::ClassMethods#_attribute_type 
  3.80      1.25     0.73     0.00     0.52   215279   ActiveAttr::Typecasting::StringTypecaster#call 
  3.39      6.96     0.65     0.00     6.31   217683   <redacted>::Base(uuid: String)#typecaster_for 
  3.28      2.71     0.63     0.00     2.09   217684   ActiveAttr::TypecastedAttributes#_attribute_type 
  3.23      0.62     0.62     0.00     0.00   217684   ActiveAttr::Attributes#attribute 
  3.07      0.60     0.59     0.00     0.01   449307   Kernel#respond_to? 
  2.99      0.57     0.57     0.00     0.00   445170   Hash#[]
  
````
  
I redacted some names because this coms from a client project, we are seeding a database which (for various reasons) lives entirely in memory. The benchmarks are done by loading a partial section of this database, consisting of roughly 590 objects and associations. We were noticing a significant performance problem (and expect that it will result in a few pull requests). After profiling, we noticed the following code was underperforming:

```` ruby 

49     def typecaster_for(type)                                                                                                                                                                                                                                                                                           
50       typecaster = {                                                                                                                                                                                                                                                                                                    
51         BigDecimal => BigDecimalTypecaster,                                                                                                                                                                                                                                                                            
52         Boolean    => BooleanTypecaster,                                                                                                                                                                                                                                                                                 
53         Date       => DateTypecaster,                                                                                                                                                                                                                                                                                    
54         DateTime   => DateTimeTypecaster,                                                                                                                                                                                                                                                                                
55         Float      => FloatTypecaster,                                                                                                                                                                                                                                                                                   
56         Integer    => IntegerTypecaster,                                                                                                                                                                                                                                                                                
57         Object     => ObjectTypecaster,                                                                                                                                                                                                                                                                                  
58         String     => StringTypecaster,                                                                                                                                                                                                                                                                                  
59       }[type]                                                                                                                                                                                                                                                                                                
60                                                                                                                                                                                                                                                                                                                        
61       typecaster.new if typecaster                                                                                                                                                                                                                                                                                       
62     end

````

in `lib/active_attr/typecasting.rb`. This seemed like an easy fix, so we refactored it to make the hash it creates a constant (called `TYPECASTERS`), that gave:

````
Thread ID: 70343398218460
Total: 15.374124
Sort by: self_time

 %self     total     self     wait    child    calls   name
  8.27      8.76     1.27     0.00     7.49   217684   ActiveAttr::TypecastedAttributes#_attribute_typecaster 
  6.60      2.79     1.02     0.00     1.77   217684   ActiveAttr::Typecasting#typecast_attribute 
  5.86      2.90     0.90     0.00     2.00   217683   ActiveAttr::Typecasting#typecaster_for 
  5.28     12.94     0.81     0.00    12.13   217684   ActiveAttr::TypecastedAttributes#attribute 
  5.08      0.78     0.78     0.00     0.00   449968   ActiveAttr::Attributes::ClassMethods#attributes 
  4.96      1.81     0.76     0.00     1.04   217684   ActiveAttr::TypecastedAttributes::ClassMethods#_attribute_type 
  4.96      0.76     0.76     0.00     0.00   445170   ActiveAttr::AttributeDefinition#[] 
  4.75      1.24     0.73     0.00     0.51   215279   ActiveAttr::Typecasting::StringTypecaster#call 
  4.17      3.54     0.64     0.00     2.90   217683   <redacted>::Base(uuid: String)#typecaster_for 
  4.06      2.68     0.62     0.00     2.06   217684   ActiveAttr::TypecastedAttributes#_attribute_type 
  3.78      0.58     0.58     0.00     0.00   217684   ActiveAttr::Attributes#attribute 
  3.73      0.59     0.57     0.00     0.01   449307   Kernel#respond_to? 
  3.67      0.56     0.56     0.00     0.00   445170   Hash#[]

````

refactoring further, I realized that the hash is an unnecessary overhead, a switch statement would be a bit quicker, and (IMO) more readable. (But I'm also the kind of guy who thinks curly braces are pretty)

````

Thread ID: 70252658645720
Total: 15.139436
Sort by: self_time

 %self     total     self     wait    child    calls   name
  8.77      8.08     1.33     0.00     6.75   217684   ActiveAttr::TypecastedAttributes#_attribute_typecaster 
  6.98      2.91     1.06     0.00     1.85   217684   ActiveAttr::Typecasting#typecast_attribute 
  5.58     12.45     0.85     0.00    11.60   217684   ActiveAttr::TypecastedAttributes#attribute 
  5.35      1.96     0.81     0.00     1.15   217683   ActiveAttr::Typecasting#typecaster_for 
  5.34      0.81     0.81     0.00     0.00   449968   ActiveAttr::Attributes::ClassMethods#attributes 
  5.31      0.80     0.80     0.00     0.00   445170   ActiveAttr::AttributeDefinition#[] 
  5.28      1.89     0.80     0.00     1.09   217684   ActiveAttr::TypecastedAttributes::ClassMethods#_attribute_type 
  5.01      1.30     0.76     0.00     0.54   215279   ActiveAttr::Typecasting::StringTypecaster#call 
  4.44      2.64     0.67     0.00     1.96   217683   <redacted>::Base(uuid: String)#typecaster_for 
  4.28      2.80     0.65     0.00     2.15   217684   ActiveAttr::TypecastedAttributes#_attribute_type 
  4.10      0.62     0.62     0.00     0.00   217684   ActiveAttr::Attributes#attribute 
  3.94      0.60     0.60     0.00     0.00   445170   Hash#[]

````

0.2 seconds difference isn't all that much, so I tossed each optimization in separate commits, in case you prefer the other one.

All tests pass on both commits.