Permalink
Browse files

Merge pull request #56 from michaeldiscala/optimize-initializer

Optimize initializer
  • Loading branch information...
tcrayford committed Mar 22, 2017
2 parents 8b78d97 + 56f393b commit 121e18dba5922c1d45051a31fbefa361409c3df1
Showing with 19 additions and 8 deletions.
  1. +19 −8 lib/values.rb
View
@@ -23,17 +23,28 @@ def self.new(*fields, &block)
Class.new do
attr_reader(:hash, *fields)
- define_method(:initialize) do |*values|
- raise ArgumentError.new("wrong number of arguments, #{values.size} for #{fields.size}") if fields.size != values.size
+ # Unroll the fields into a series of assignment Ruby statements that can
+ # be used inside of the initializer for the new class. This was introduced
+ # in PR#56 as a performance optimization -- it ensures that this iteration
+ # happens once per class, instead of happening once per instance of the
+ # class.
+ instance_var_assignments = Array.new(fields.length) do |idx|
+ "@#{fields[idx]} = values[#{idx}]"
+ end.join("\n")
+
+ class_eval <<-RUBY
+ def initialize(*values)
+ if #{fields.size} != values.size
+ raise ArgumentError.new("wrong number of arguments, \#{values.size} for #{fields.size}")
+ end
- fields.zip(values) do |field, value|
- instance_variable_set(:"@#{field}", value)
- end
+ #{instance_var_assignments}
- @hash = self.class.hash ^ values.hash
+ @hash = self.class.hash ^ values.hash
- freeze
- end
+ freeze
+ end
+ RUBY
const_set :VALUE_ATTRS, fields

0 comments on commit 121e18d

Please sign in to comment.