diff --git a/lib/active_type/virtual_attributes.rb b/lib/active_type/virtual_attributes.rb index 63d08b5..27ce864 100644 --- a/lib/active_type/virtual_attributes.rb +++ b/lib/active_type/virtual_attributes.rb @@ -134,6 +134,19 @@ def self.deep_dup(hash) result end + def self.attribute_for_inspect(value) + if value.is_a?(String) && value.length > 50 + "#{value[0, 50]}...".inspect + elsif value.is_a?(Date) || value.is_a?(Time) + %("#{value.to_formatted_s(:db)}") + elsif value.is_a?(Array) && value.size > 10 + inspected = value.first(10).inspect + %(#{inspected[0...-1]}, ...]) + else + value.inspect + end + end + extend ActiveSupport::Concern included do @@ -141,6 +154,14 @@ def self.deep_dup(hash) class_attribute :virtual_columns_hash self.virtual_columns_hash = {} + if respond_to?(:attributes_for_inspect) + # 7.1 had [:id] as a default, we want a consistent default across all versions + self.attributes_for_inspect = :all + else + # ActiveRecord < 7.2 + class_attribute :attributes_for_inspect, instance_accessor: false, default: :all + end + class << self if method_defined?(:attribute) alias_method :ar_attribute, :attribute @@ -270,25 +291,28 @@ def write_virtual_attribute(name, value) virtual_attributes[name] = value end - # Returns the contents of the record as a nicely formatted string. + def attributes_for_inspect + self.class.attributes_for_inspect == :all ? attributes.keys : self.class.attributes_for_inspect + end + def inspect - inspection = attributes.collect do |name, value| - "#{name}: #{VirtualAttributes.attribute_for_inspect(value)}" - end.sort.compact.join(", ") - "#<#{self.class} #{inspection}>" + inspect_with_attributes(attributes_for_inspect) end - def self.attribute_for_inspect(value) - if value.is_a?(String) && value.length > 50 - "#{value[0, 50]}...".inspect - elsif value.is_a?(Date) || value.is_a?(Time) - %("#{value.to_formatted_s(:db)}") - elsif value.is_a?(Array) && value.size > 10 - inspected = value.first(10).inspect - %(#{inspected[0...-1]}, ...]) - else - value.inspect - end + def full_inspect + inspect_with_attributes(attributes.keys) + end + + # Returns the contents of the record as a nicely formatted string. + def inspect_with_attributes(attribute_names) + inspection = attribute_names.collect do |name| + name = name.to_s + if attributes.key?(name) + value = attributes[name] + "#{name}: #{VirtualAttributes.attribute_for_inspect(value)}" + end + end.compact.sort.join(", ") + "#<#{self.class} #{inspection}>" end private diff --git a/spec/active_type/object_spec.rb b/spec/active_type/object_spec.rb index 126b232..3e20b36 100644 --- a/spec/active_type/object_spec.rb +++ b/spec/active_type/object_spec.rb @@ -131,6 +131,12 @@ class ObjectWithUnsupportedTypes < Object attribute :virtual_hash, :hash end + class ObjectWithClassInspectFilter < ActiveType::Object + attribute :visible, :string + attribute :hidden, :string + + self.attributes_for_inspect = [:visible] + end end @@ -246,7 +252,6 @@ class ObjectWithUnsupportedTypes < Object end describe '#inspect' do - it 'returns the contents of the object as a nicely formatted string' do t = Time.now subject.virtual_string = "string" @@ -258,6 +263,24 @@ class ObjectWithUnsupportedTypes < Object expect(subject.inspect).to eq("#") end + it 'does not filter out any attributes per default' do + object = ObjectSpec::ObjectWithClassInspectFilter.new(visible: 'seen', hidden: 'also-seen') + expect(object.full_inspect).to eq('#') + end + + context 'with attributes_for_inspect class attribute' do + it 'filters attributes based on the class configuration' do + object = ObjectSpec::ObjectWithClassInspectFilter.new(visible: 'seen', hidden: 'invisible') + expect(object.inspect).to eq('#') + end + end + end + + describe '#full_inspect' do + it 'shows all attributes' do + object = ObjectSpec::ObjectWithClassInspectFilter.new(visible: 'seen', hidden: 'not-so-invisible-anymore') + expect(object.full_inspect).to eq('#') + end end describe '#attributes' do