From e6514912979b2b990653db9a7cd99e19947034fc Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Sun, 8 Oct 2023 18:27:49 +0800 Subject: [PATCH] * Make code "Object Shape friendly" https://island94.org/2023/10/writing-object-shape-friendly-code-in-ruby --- lib/contracted_value/core.rb | 13 ++++++------- spec/contracted_value/value_spec.rb | 8 +++++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/contracted_value/core.rb b/lib/contracted_value/core.rb index 0631699..5b47317 100644 --- a/lib/contracted_value/core.rb +++ b/lib/contracted_value/core.rb @@ -231,6 +231,8 @@ def initialize(input_attr_values = {}) ) end + @attr_values = {} + self.class.send(:attribute_set).each_attribute do |attribute| attr_value = attribute.extract_value(input_attr_values_hash) @@ -253,8 +255,8 @@ def initialize(input_attr_values = {}) # Using symbol since attribute names are limited in number # An alternative would be using frozen string - instance_variable_set( - :"@#{attribute.name}", + @attr_values.store( + attribute.name.to_sym, sometimes_frozen_attr_value, ) end @@ -265,10 +267,7 @@ def initialize(input_attr_values = {}) # rubocop:enable Metrics/CyclomaticComplexity def to_h - self.class.send(:attribute_set). - each_attribute.each_with_object({}) do |attribute, hash| - hash[attribute.name] = instance_variable_get(:"@#{attribute.name}") - end + @attr_values.clone end # == Class interface == # @@ -297,7 +296,7 @@ def attribute( ) @attribute_set = @attribute_set.add(attr) - attr_reader(name) + define_method(name) { @attr_values[name.to_sym] } end # @api private diff --git a/spec/contracted_value/value_spec.rb b/spec/contracted_value/value_spec.rb index 0673bbe..f897157 100644 --- a/spec/contracted_value/value_spec.rb +++ b/spec/contracted_value/value_spec.rb @@ -93,13 +93,19 @@ it "does not raise error when input is a value" do aggregate_failures do + new_val = nil expect { - value_class.new( + new_val = value_class.new( value_class.new( default_inputs, ), ) }.to_not raise_error + if new_val + default_inputs.each_pair do |attr_name, attr_val| + expect(new_val.public_send(attr_name)).to eq(attr_val) + end + end end end