So I like to use ruby inspect
for debugging, however I have a class that have an array that have 6000 elements and whenever I puts obj.inspect
the array clutters the entire screen. Is there any way to make the array attribute hidden from inspect?
class Test
def initialize
@x = 1
@array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
end
def myinspect
# ??
end
end
c = Test.new
puts c.inspect # <Test:0x00007f1d49e33b00 @x=1, @array=[1, 2, 3, 4, 5, 6, 7, 8, 9]>
puts c.myinspect # <Test:0x00007f1d49e33b00 @x=1>
CodePudding user response:
You can redefine any method in Ruby.
So, in your case, you may just redefine inspect
in your class Test
.
Here is an example.
class Test
alias_method :inspect_original, :inspect if ! self.method_defined?(:inspect_original) # backup
def inspect
"<#{self.class.name}: @x=#{@x.inspect} @array.size=#{@array.size}>"
end
end
Test.new.inspect
# => "<Test: @x=1 @array.size=9>"
CodePudding user response:
Probably it's possible to use more elegance conversion for object id, but not sure by much
class Test
def initialize
@x = 1
@array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
end
def myinspect
"#<#{self.class.name}:0x#{(object_id * 2).to_s(16).rjust(16, '0')} @x=#{instance_variable_get(:@x)}>"
end
end
And then
test = Test.new
puts test.inspect
#<Test:0x000055e35c5dc4c0 @x=1, @array=[1, 2, 3, 4, 5, 6, 7, 8, 9]>
puts test.myinspect
#<Test:0x000055e35c5dc4c0 @x=1>
Without this conversion your code will be not so ugly
For example rails don't use this object id
Probably you don't need it too
CodePudding user response:
To use my_inspect
we need the following regular expression, which I've written in free-spacing mode to make it self-documenting.
R = /
,\ @ # match ', @'
\w # match one or more word characters
=\[ # match '=['
.*? # match one or more characters lazily
\] # match ']'
/x # invoke free-spacing regex definition mode
This is conventionally written
R = /, @\w =\[.*?\]/
We then create the class Test
to contain one instance variable holding an integer and two instance variables holding arrays, and methods initialize
and my_inspect
.
class Test
def initialize
@x = 1
@array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
@tom_cat = ['Fluffy', 'Tiger', 'Max']
end
def my_inspect
inspect.gsub(R,'')
end
end
When inspect
is invoked on an instance of Test
we want no reference to instance variables holding arrays.
Test.new.inspect
#=> "#<Test:0x00007f962c102740 @x=1>"
Voilà!
Another approach is to override the built-in inspect
. There are two ways to do that. The first is create an alias for the built-in method inspect
, as @MasaSakano has done in his/her answer. Another way is to prepend a module containing the new method inspect
. I'll describe that option below.
The first step is to create a module with the new method inspect
that will be prepended to the class Test
.
module M
def inspect
method(__method__).super_method
.call
.gsub(R,'')
end
end
See Kernel#__method__ and Method#super_method.
Next create the class Test
which prepends module M
.
class Test
def initialize
@x = 1
@array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
@tom_cat = ['Fluffy', 'Tiger', 'Max']
end
prepend M
end
See Module#prepend.
Try it!
Test.new.inspect
#=> "#<Test:0x00007f962c852900 @x=1>"
Voilà again!
CodePudding user response:
So I've decided to make an inspect_except
class Test
def initialize
@x = 1
@array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
end
def inspect_except(*attrs)
r = "<#{self.class.name}:#{object_id}"
instance_variables.each do |var|
next if attrs.include? var
r = " #{var}=#{instance_variable_get var}"
end
r = ">"
end
end
c = Test.new
puts c.inspect_except(:@array)