Symbol#inspect should return a valid symbol literal, right?
But it doesn't for symbols starting with a digit:
irb(main):001:0> p :"9"
:9
=> nil
irb(main):002:0> :9
SyntaxError: compile error
(irb):2: syntax error
from (irb):2
Dominik
It also doesn't work for many of the operators:
p(:'=')
:=
p(:=)
SyntaxError: compile error
(irb):14: syntax error
p(:=)
It seems like if the symbol string is not a valid identifier, it
should be quoted by Symbol#inspect.
> Symbol#inspect should return a valid symbol literal, right?
Not according to the RDoc:
$ ri Object#inspect
--------------------------------------------------------- Object#inspect
obj.inspect => string
------------------------------------------------------------------------
Returns a string containing a human-readable representation of
_obj_. If not overridden, uses the +to_s+ method to generate the
string.
[ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]"
Time.new.inspect #=> "Wed Apr 09 08:54:39
CDT 2003"
--
Eric Hodel - drb...@segment7.net - http://segment7.net
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04
> On Nov 18, 2005, at 3:22 PM, Dominik Bathon wrote:
>
>> Symbol#inspect should return a valid symbol literal, right?
>
> Not according to the RDoc:
>
> $ ri Object#inspect
> --------------------------------------------------------- Object#inspect
> obj.inspect => string
> ------------------------------------------------------------------------
> Returns a string containing a human-readable representation of
> _obj_. If not overridden, uses the +to_s+ method to generate the
> string.
>
> [ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]"
> Time.new.inspect #=> "Wed Apr 09 08:54:39 CDT
> 2003"
Yes, but:
$ ri Symbol#inspect
--------------------------------------------------------- Symbol#inspect
sym.inspect => string
------------------------------------------------------------------------
Returns the representation of sym as a symbol literal.
:fred.inspect #=> ":fred"
> On Sat, 19 Nov 2005 00:57:28 +0100, Eric Hodel
> <drb...@segment7.net> wrote:
>
>> On Nov 18, 2005, at 3:22 PM, Dominik Bathon wrote:
>>
>>> Symbol#inspect should return a valid symbol literal, right?
>>
>> Not according to the RDoc:
>>
>> $ ri Object#inspect
>> Returns a string containing a human-readable representation of
>> _obj_. If not overridden, uses the +to_s+ method to generate
>> the
>> string.
>
> Yes, but:
>
> $ ri Symbol#inspect
> Returns the representation of sym as a symbol literal.
I consider Object#inspect to set the intent of all the #inspect
methods, but this may be an oversight.
For many of the other core classes (and definitely all other immediate
classes), #inspect returns a representation that is eval'able to get
back an equivalent (or the same) object. When possible, I think that
is what #inspect should do. I think it is a bug that Symbol#inspect
almost does it, but not quite (quotes some cases but not others).
I found this problem when doing code generation. For immediate
objects, I embedded the value in the code directly by using #inspect.
I had to put in a hack for Symbol because of the problem discussed.
I agree this should be fixed. I wrote something that I think shows all
the problem cases (at least for single characters):
32.upto(126) do |i|
c = i.chr
s = ":\"#{c}\""
if c == "\"" or c == "\\"
s = ":\"\\#{c}\""
end
symbol = eval(s)
begin
symbol = eval(symbol.inspect)
rescue SyntaxError
puts "Failed to eval inspected form of #{s}"
end
end
The results:
Failed to eval inspected form of :"!"
Failed to eval inspected form of :"0"
Failed to eval inspected form of :"1"
Failed to eval inspected form of :"2"
Failed to eval inspected form of :"3"
Failed to eval inspected form of :"4"
Failed to eval inspected form of :"5"
Failed to eval inspected form of :"6"
Failed to eval inspected form of :"7"
Failed to eval inspected form of :"8"
Failed to eval inspected form of :"9"
Failed to eval inspected form of :"="
Failed to eval inspected form of :"@"
Ryan
Although I'd agree that Symbol#inspect can be improved and should be
changend (as it's an easy fix) I have a different opinion about the usage of
inspect in general: even inspect methods of core classes fail to return
something that is proper ruby code.
$ ruby -e 'p Object.new'
#<Object:0x100f6b28>
$ ruby -e 'a=[1];a<<a;p a'
[1, [...]]
> I found this problem when doing code generation. For immediate
> objects, I embedded the value in the code directly by using #inspect.
> I had to put in a hack for Symbol because of the problem discussed.
IMHO relying on #inspect for code generation is inappropriate. As the rdoc
of Object#inspect indicates it's meant to yield a human readable
representation. If you want to generate code you should use another
mechanism. For example, you can define a separate method (even if it calls
#inspect as default implementation). Or you use YAML / Marshal for complex
data structures.
Kind regards
robert
In message "Re: Symbol#inspect bug?"
on Sat, 19 Nov 2005 08:22:20 +0900, "Dominik Bathon" <dba...@gmx.de> writes:
|But it doesn't for symbols starting with a digit:
|
|irb(main):001:0> p :"9"
|:9
Which version are you using?
% ruby -ve 'p :"9"'
ruby 1.8.4 (2005-10-29) [i486-linux]
:"9"
So it's reserved to be fixed.
matz.
Thanks matz. I just downloaded 1.8.4 preview1 and tried this out. It
looks like only one case isn't fixed yet (:"["):
[eric@localhost ruby-1.8.4]$ ./ruby -v
ruby 1.8.4 (2005-10-29) [i686-linux]
[eric@localhost ruby-1.8.4]$ ./ruby
1.upto(255) do |c0|
0.upto(255) do |c1|
str = c0.chr
str.concat(c1.chr) if c1.nonzero?
inspect0 = ":#{str.inspect}"
eval0 = eval(inspect0)
inspect1 = eval0.inspect
begin
eval1 = eval(inspect1)
eval1==eval0 or puts "#{eval1}!=#{eval0}"
rescue SyntaxError
puts "Couldn't eval(#{inspect1} = eval(#{inspect0}).inspect)"
end
end
end
Couldn't eval(:[ = eval(:"[").inspect)
I didn't realize that symbols can't handle empty strings or the null
character until I tried this.
I didn't say all core classes return something evalable for #inspect
(I said many). Here's the list I see:
FalseClass, TrueClass, NilClass
Fixnum, Bignum
Float
String
Regexp
Symbol - close but no cigar
Class - kind of - it returns a constant for class that can be evaled
Array, Hash, Range - if no recursion and all elements have an evalable #inspect
> > I found this problem when doing code generation. For immediate
> > objects, I embedded the value in the code directly by using #inspect.
> > I had to put in a hack for Symbol because of the problem discussed.
>
> IMHO relying on #inspect for code generation is inappropriate. As the rdoc
> of Object#inspect indicates it's meant to yield a human readable
> representation. If you want to generate code you should use another
> mechanism. For example, you can define a separate method (even if it calls
> #inspect as default implementation). Or you use YAML / Marshal for complex
> data structures.
Notice I said only immediate objects. This was actually only an
optimization. For non-immediate objects, I'm putting them in an
instance variable to be accessed by the generated code. For immediate
objects there was no reason for this as they were immutable and had no
object creation overhead. Depending on the instance variable usage
overhead vs. object creation overhead, I might do the same for Float
and other immutable, evalable #inspect classes. Again, this is only
an optimization - handling some classes differently doesn't change the
functionality.
> I didn't realize that symbols can't handle empty strings or the null
> character until I tried this.
Well, at least in 1.8.2 they can handle empty strings, but it is
somewhat tricky:
irb(main):001:0> :"#{}"
ArgumentError: interning empty string
from (irb):1
irb(main):002:0> :"#{""}"
=> :
Symbol#inspect doesn't quite work there, though. :)
Also, there was more cases like :"$10" that don't work in 1.8.2 and I'm
not sure if they have already been fixed for 1.9. I think I listed most
of them in [ruby-core:03573].
> Float: NaN, Infinity, -Infinity
It's annoying that these aren't constants.
> Class: Class.new #==> #<Class:0x760fe0>
Yeah, I knew Class#inspect was full of holes for it being evalable.
> Regexp:
> insert = '#{23}'
> ==>"\#{23}"
> re = /#{insert}/
> ==>/#{23}/
> eval(re.inspect)
> ==>/23/
> ... where /#{23}/ is a valid regexp which matches 23 hash characters.
I think this is a bug. These should be equivalent:
irb(main):001:0> /\#{23}/
=> /\#{23}/
irb(main):002:0> /#{'#{23}'}/
=> /#{23}/
Regexp#inspect should always escape '#'.
#inspect is for human-readable strings. If they happen
to be evalable, it's a side effect.
Hal
At Sat, 19 Nov 2005 23:40:16 +0900,
Eric Mahurin wrote in [ruby-talk:166520]:
> Thanks matz. I just downloaded 1.8.4 preview1 and tried this out. It
> looks like only one case isn't fixed yet (:"["):
Thank you, fixed it now.
--
Nobu Nakada