What about Object#to_ruby ?

B

Bernard Lambeau

[Note: parts of this message were removed to make it a legal post.]

Hi!

It's not the first time that I need a to_ruby method which would guarantee
the following invariant:

Kernel.eval(foo.to_ruby) == foo

It actually works when using inspect with most basic objects (Integer,
String,
True & FalseClass, etc.), without actually being the specification of
inspect.

I admit that such a feature probably only makes sense for classes that
actually
capture datatypes, whose instances are then true values.

Does anyone know a gem that provides such a feature? To your knowledge,
would to_ruby be a conflicting name with existing gems in the ecosystem
or future plans for ruby itself?

Just in case you ask yourself whether this feature is needed, have a look
at rubygems itself:
https://github.com/rubygems/rubygems/blob/master/lib/rubygems/specification.rb#L1899-1915

Thanks for any suggestion,
Bernard

--
PhD Student, Computer Science Department, EPL/INGI, UCLouvain, Belgium
Mail: (e-mail address removed)
Mobile: +32 477 24 58 61
Blog: http://revision-zero.org/
Code: http://github.com/blambeau/
Follow: http://twitter.com/blambeau/
 
S

Steve Klabnik

[Note: parts of this message were removed to make it a legal post.]

I believe pry has this kind of thing: https://github.com/banister/pry

From its readme:

pry(Pry):1> show-method rep -l

From: /home/john/ruby/projects/pry/lib/pry/pry_instance.rb @ line 143:
Number of lines: 6

143: def rep(target=TOPLEVEL_BINDING)
144: target = Pry.binding_for(target)
145: result = re(target)
146:
147: show_result(result) if should_print?
148: end
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

Hi!

It's not the first time that I need a to_ruby method which would guarantee
the following invariant:

Kernel.eval(foo.to_ruby) == foo

It actually works when using inspect with most basic objects (Integer,
String,
True & FalseClass, etc.), without actually being the specification of
inspect.

I admit that such a feature probably only makes sense for classes that
actually
capture datatypes, whose instances are then true values.

Does anyone know a gem that provides such a feature? To your knowledge,
would to_ruby be a conflicting name with existing gems in the ecosystem
or future plans for ruby itself?

Just in case you ask yourself whether this feature is needed, have a look
at rubygems itself:

https://github.com/rubygems/rubygems/blob/master/lib/rubygems/specification.rb#L1899-1915

Thanks for any suggestion,
Bernard

--
PhD Student, Computer Science Department, EPL/INGI, UCLouvain, Belgium
Mail: (e-mail address removed)
Mobile: +32 477 24 58 61
Blog: http://revision-zero.org/
Code: http://github.com/blambeau/
Follow: http://twitter.com/blambeau/

# I think the following works for everything except data that contains code
itself (closures / methods)

Datum = Struct.new :some_attribute

data = [
Datum.new("string"),
Datum.new(1234),
Datum.new(/regex/),
]


serial = Marshal.dump data
serial # =>
"\x04\b[\bS:\nDatum\x06:\x13some_attributeI\"\vstring\x06:\x06ETS;\x00\x06;\x06i\x02\xD2\x04S;\x00\x06;\x06I/\nregex\x00\x06;\aF"
Marshal.load(serial) == data # => true

require 'yaml'
serial = YAML.dump data
serial # => "--- \n- !ruby/struct:Datum \n
some_attribute: string\n- !ruby/struct:Datum \n some_attribute: 1234\n-
!ruby/struct:Datum \n some_attribute: !ruby/regexp /regex/\n"
YAML.load(serial) == data # => true

---

I think the closest things that exist right now that would be able to do
this for closures as well, would be some of Ryan Davis' tools (last I heard,
they don't work on 1.9, though):
https://rubygems.org/gems/ruby2ruby
https://rubygems.org/gems/ruby_parser
https://rubygems.org/gems/sexp_processor

Rubinius might also be able to do something like this.


I believe pry has this kind of thing: https://github.com/banister/pry

From its readme:

pry(Pry):1> show-method rep -l

From: /home/john/ruby/projects/pry/lib/pry/pry_instance.rb @ line 143:
Number of lines: 6

143: def rep(target=TOPLEVEL_BINDING)
144: target = Pry.binding_for(target)
145: result = re(target)
146:
147: show_result(result) if should_print?
148: end

I'm admittedly uninformed, but I think they do this by keeping track of
where methods get defined, then opening that file and reading that
definition (as opposed to introspecting on the object itself) in the example
above, for instance, they also report the file and line numbers of the rep
method.
 
B

Bernard Lambeau

[Note: parts of this message were removed to make it a legal post.]

Thanks a lot for your responses. I suspect that my question was not that
clear, though.

I'm not really looking or Marshal or YAML or JSON dump format, but for a
method
to print a ruby *literal* (I should have called it to_ruby_literal) from a
ruby value,
where it makes sense. The goal is to ease human-readable ruby code
generation,
I must add. Nowadays, using inspect works for all but a few basic values:

blambeau@kali:~$ irb -r time to_ruby_literal.rb
ruby-1.8.7-p334 :001 > eval(true.inspect)
=> true
ruby-1.8.7-p334 :002 > eval(1.inspect)
=> 1
ruby-1.8.7-p334 :003 > eval(1.0.inspect)
=> 1.0
ruby-1.8.7-p334 :004 > eval(nil.inspect)
=> nil
ruby-1.8.7-p334 :005 > eval("O'Neil".inspect)
=> "O'Neil"
ruby-1.8.7-p334 :006 > eval('O " Dude'.inspect)
=> "O \" Dude"
ruby-1.8.7-p334 :007 > eval([1, 2, 3].inspect)
=> [1, 2, 3]
ruby-1.8.7-p334 :008 > eval({:hello => "world"}.inspect)
=> {:hello=>"world"}
ruby-1.8.7-p334 :009 > eval(/[a-z]*/.inspect)
=> /[a-z]*/
ruby-1.8.7-p334 :010 > eval((1.0/0).inspect)
NameError: (eval):1:in `irb_binding': uninitialized constant Infinity
from to_ruby_literal.rb:10
from to_ruby_literal.rb:10
ruby-1.8.7-p334 :011 > eval(Time.now.inspect)
SyntaxError: (eval):1:in `irb_binding': compile error
(eval):1: syntax error, unexpected tINTEGER, expecting $end
Mon Jun 20 20:01:19 +0200 2011
^
from to_ruby_literal.rb:11
from to_ruby_literal.rb:11

Bernard

Hi!

It's not the first time that I need a to_ruby method which would guarantee
the following invariant:

Kernel.eval(foo.to_ruby) == foo

It actually works when using inspect with most basic objects (Integer,
String,
True & FalseClass, etc.), without actually being the specification of
inspect.

I admit that such a feature probably only makes sense for classes that
actually
capture datatypes, whose instances are then true values.

Does anyone know a gem that provides such a feature? To your knowledge,
would to_ruby be a conflicting name with existing gems in the ecosystem
or future plans for ruby itself?

Just in case you ask yourself whether this feature is needed, have a look
at rubygems itself:

https://github.com/rubygems/rubygems/blob/master/lib/rubygems/specification.rb#L1899-1915

Thanks for any suggestion,
Bernard

--
PhD Student, Computer Science Department, EPL/INGI, UCLouvain, Belgium
Mail: (e-mail address removed)
Mobile: +32 477 24 58 61
Blog: http://revision-zero.org/
Code: http://github.com/blambeau/
Follow: http://twitter.com/blambeau/

# I think the following works for everything except data that contains code
itself (closures / methods)

Datum = Struct.new :some_attribute

data = [
Datum.new("string"),
Datum.new(1234),
Datum.new(/regex/),
]


serial = Marshal.dump data
serial # =>

"\x04\b[\bS:\nDatum\x06:\x13some_attributeI\"\vstring\x06:\x06ETS;\x00\x06;\x06i\x02\xD2\x04S;\x00\x06;\x06I/\nregex\x00\x06;\aF"
Marshal.load(serial) == data # => true

require 'yaml'
serial = YAML.dump data
serial # => "--- \n- !ruby/struct:Datum \n
some_attribute: string\n- !ruby/struct:Datum \n some_attribute: 1234\n-
!ruby/struct:Datum \n some_attribute: !ruby/regexp /regex/\n"
YAML.load(serial) == data # => true

---

I think the closest things that exist right now that would be able to do
this for closures as well, would be some of Ryan Davis' tools (last I
heard,
they don't work on 1.9, though):
https://rubygems.org/gems/ruby2ruby
https://rubygems.org/gems/ruby_parser
https://rubygems.org/gems/sexp_processor

Rubinius might also be able to do something like this.


I believe pry has this kind of thing: https://github.com/banister/pry

From its readme:

pry(Pry):1> show-method rep -l

From: /home/john/ruby/projects/pry/lib/pry/pry_instance.rb @ line 143:
Number of lines: 6

143: def rep(target=TOPLEVEL_BINDING)
144: target = Pry.binding_for(target)
145: result = re(target)
146:
147: show_result(result) if should_print?
148: end

I'm admittedly uninformed, but I think they do this by keeping track of
where methods get defined, then opening that file and reading that
definition (as opposed to introspecting on the object itself) in the
example
above, for instance, they also report the file and line numbers of the rep
method.



--
PhD Student, Computer Science Department, EPL/INGI, UCLouvain, Belgium
Mail: (e-mail address removed)
Mobile: +32 477 24 58 61
Blog: http://revision-zero.org/
Code: http://github.com/blambeau/
Follow: http://twitter.com/blambeau/
 
M

Michael Edgar

Thanks a lot for your responses. I suspect that my question was not = that
clear, though.
=20
I'm not really looking or Marshal or YAML or JSON dump format, but for = a
method
to print a ruby *literal* (I should have called it to_ruby_literal) = from a
ruby value,
where it makes sense. The goal is to ease human-readable ruby code
generation,
I must add. Nowadays, using inspect works for all but a few basic =
values:


It sounds like you're essentially talking about a marshal format that =
*is*
Ruby code.

Something along the lines of this, without procs, singleton classes, no
cyclic references (ruby 1.9), etc:

class Object
def to_ruby_literal
str =3D "#{self.class.name}.allocate.tap do |obj|\n"
instance_variables.each do |ivar|
str << "obj.instance_variable_set(#{ivar}, =
#{instance_variable_get(ivar).to_ruby_literal})\n"
end
str << "end"
end
end

[TrueClass, FalseClass, NilClass, String, Integer, Float].each do =
|klass|
klass.class_eval do
alias_method :to_ruby_literal, :inspect
end
end

Usage:

class A
def initialize(x, y, z)
@x, @y, @z =3D x, y, z
end
end
puts A.new(1.3, "hello", false).to_ruby_literal

A.allocate.tap do |obj|
obj.instance_variable_set(@x, 1.3)
obj.instance_variable_set(@y, "hello")
obj.instance_variable_set(@z, false)
end

Michael Edgar
(e-mail address removed)
http://carboni.ca/=
 
M

Michael Edgar

str << "obj.instance_variable_set(#{ivar}, =
#{instance_variable_get(ivar).to_ruby_literal})\n"

Correction: this doesn't quote the ivar name, it should be:

str << "obj.instance_variable_set(\"#{ivar}\", =
#{instance_variable_get(ivar).to_ruby_literal})\n"

Which would output, in the previous example:

A.allocate.tap do |obj|
obj.instance_variable_set("@x", 1.3)
obj.instance_variable_set("@y", "hello")
obj.instance_variable_set("@z", false)
end

Michael Edgar
(e-mail address removed)
http://carboni.ca/=
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top