For a while now I've wanted a way to inspect all changes made to a given ruby environment when a particular model is loaded. Furthermore, the ability to compare and contrast the methods and classes available in separate versions of ruby, and different Ruby VMs.
I've created some code which uses meta-programming to generate such a list:
arr = []
arr << "Ruby version " + ::RUBY_VERSION
arr << ""
Module.constants.each do |const|
if ::Module.const_defined? const
#If for whatever reason const_get fails, then rescue.
begin
obj = Module.const_get(const)
if obj
if obj.is_a? Class
# Class methods
arr << (obj.singleton_methods).sort.map do |method_sym|
obj.to_s + "::" + method_sym.to_s
end
# Instance methods
arr << (obj.instance_methods - (obj.superclass ? obj.superclass.instance_methods : []) - Object.methods).sort.map do |method_sym|
"#<" + obj.to_s + ">." + method_sym.to_s
end
elsif obj.is_a? Module
arr << (obj.methods - Module.methods).sort.map do |method_sym|
obj.to_s + "::" + method_sym.to_s
end
else
# Methods
arr << "::" + const.to_s
end
end
rescue
end
end
end
File.new("D:\\methods_#{::RUBY_VERSION}.txt","w").write(arr.flatten.sort.join("\n"))
The criteria for the list is that it should list all non-inherited instance and class methods. Constants are indicated with ::
prefix, Class methods are indicated as MyClass::someMethod
and instance methods are indicated as follows: #<MyClass>.someMethod
.
The script above works for the most part however, it misses out Object
and BasicObject
. IE in the lists created there are no lines prefixed with #<Object>.
or Object::
. Am I missing something obvious?
I suggest you create a hash for each Ruby version and then save that hash or its contents to a file whose name indicates the Ruby version (eg, v_2-5-1.json
or v_2-5-1.txt
)
While I don't fully understand the question, you may find he method ObjectSpace::each_object helpful here. For example,
h = ObjectSpace.each_object(Class).with_object({}) do |c,h|
h[c] = { cm: c.methods(false).sort, im: c.instance_methods(false).sort,
con: c.constants.sort }
end
h.keys && [Object, BasicObject]
# [Object, BasicObject]
As you see Object
and BasicObject
are two keys (classes) in this hash. Let's look at the value of one of the keys: Dir
.
h[Dir]
#=> {:cm=>[:[], :chdir, :children, :chroot, :delete, :each_child, :empty?,
# :entries, :exist?, :exists?, :foreach, :getwd, :glob, :home,
# :mkdir, :open, :pwd, :rmdir, :unlink],
# :im=>[:close, :each, :fileno, :inspect, :path, :pos, :pos=, :read,
# :rewind, :seek, :tell, :to_path],
# :con=>[]}
This is for
RUBY_VERSION
#=> "2.5.1"
Comparing the contents of this hash with the doc for Dir for v2.5.1 we see that the results are correct for the class Dir
.
Obtaining constants defined within a class C
is problematic. C.constants
, which I've used above includes inherited constants. Were I to write C.constants - C.superclass.constants
(mindful that BasicObject.superclass #=> nil
) that would not report inherited constants the are redefined in C
(and redefining an inherited constant does not produce a warning message).
Instead of just looking at classes you may wish to examine all modules ( ObjectSpace.each_object(Module)
) and add a key :is_class
to the hash with value true
or false
):
There may be other keys you may wish to add to the hash. :superclass
and :included_modules
(for classes ) are two that comes to mind; :nesting
(for non-class modules) is another. See Module::nesting . I suspect that these observations just scratch the surface, that a meaningful comparison of two Ruby versions will be highly complex.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.