{"id":13778977,"url":"https://github.com/cout/ruby-internal","last_synced_at":"2026-04-09T01:32:51.914Z","repository":{"id":388245,"uuid":"5750","full_name":"cout/ruby-internal","owner":"cout","description":"A library to provide access to the internals of the Ruby interpreter","archived":false,"fork":false,"pushed_at":"2013-09-24T19:33:02.000Z","size":1319,"stargazers_count":58,"open_issues_count":3,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-17T14:41:10.062Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"gitlab-org/gitlab-ce","license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cout.png","metadata":{"files":{"readme":"README.rdoc","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2008-03-28T23:24:30.000Z","updated_at":"2024-08-09T16:51:28.000Z","dependencies_parsed_at":"2022-07-07T12:54:56.725Z","dependency_job_id":null,"html_url":"https://github.com/cout/ruby-internal","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cout%2Fruby-internal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cout%2Fruby-internal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cout%2Fruby-internal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cout%2Fruby-internal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cout","download_url":"https://codeload.github.com/cout/ruby-internal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253567048,"owners_count":21928771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T18:00:59.653Z","updated_at":"2026-04-09T01:32:51.862Z","avatar_url":"https://github.com/cout.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"Ruby-internal is a Ruby library that provides direct access to Ruby's\n(MRI or YARV) internal data structures.\n\nHow is ruby-internal useful? You can:\n\n* dump and load methods and procs and classes\n* inspect and pretty-print ascii charts of node trees\n* inspect and print ascii charts of class hierarchies\n* use the provided code obfuscator (nwobfusc.rb) so your code can't easily be read.\n* use it to build a just-in-time compiler (see Ludicrous).\n\n== Installation\n\nTo install ruby-internal:\n\n  $ gem install ruby-internal\n\n== Building from source\n\nTo build and run the tests:\n  ruby setup.rb config\n  ruby setup.rb setup\n\nOr, if you are on ruby 1.9 (or another version of ruby that doesn't have\npre-parsed ruby source included in the distribution), you'll need to\npass a special command-line option in the config step so the build\nscripts can find ruby's source code:\n\n  ruby setup.rb config --ruby-source-path=/path/to/ruby\n  ruby setup.rb setup\n\nTo install:\n  ruby install.rb install\n\n== Sample code\n\nThis will dump the class Foo (including its instance methods, class variables,\netc.) and re-load it:\n\n  :include: sample/dump_class.rb\n\n== Ruby-internal and irb\n\nRuby-internal is very useful as a tool for digging into the internals of Ruby\nand figuring out what the interpreter is doing with your code. To use\nruby-internal with irb, put the following in your .irbrc:\n\n  :include: sample/irbrc\n\nNow you can print node trees:\n\n  irb(main):001:0\u003e pp (proc { 1 + 1 }.body)\n  NODE_NEWLINE at (irb):1\n  |-nth = 1\n  +-next = NODE_CALL at (irb):1\n    |-recv = NODE_LIT at (irb):1\n    | +-lit = 1\n    |-args = NODE_ARRAY at (irb):1\n    | |-alen = 1\n    | |-head = NODE_LIT at (irb):1\n    | | +-lit = 1\n    | +-next = false\n    +-mid = :+\n  =\u003e nil\n\nAnd view class hierarchies:\n\n  irb(main):004:0\u003e puts Object.new.classtree\n  #\u003cObject:0x40330ce8\u003e\n  +-class = Object\n    |-class = #\u003cClass:Object\u003e\n    | |-class = Class\n    | | |-class = #\u003cClass:Class\u003e\n    | | | |-class = #\u003cClass:Class\u003e (*)\n    | | | +-super = #\u003cClass:Module\u003e\n    | | |   |-class = Class (*)\n    | | |   +-super = #\u003cClass:Object\u003e (*)\n    | | +-super = Module\n    | |   |-class = #\u003cClass:Module\u003e (*)\n    | |   +-super = Object (*)\n    | +-super = Class (*)\n    +-super = #\u003cPP::ObjectMixin?:0x40349568\u003e\n      +-class = PP::ObjectMixin?\n        |-class = Module (*)\n        +-super = #\u003cKernel:0x4033507c\u003e\n          +-class = Kernel\n  =\u003e nil\n\n== YARV support\n\nYes, ruby-internal works with YARV, too. The difference when using YARV\nis that sometimes you have nodes, and sometimes you have instruction\nsequences. So whereas pre-YARV you would have a pure AST, with YARV you\nget structures that look like this:\n\n  irb(main):001:0\u003e def foo; 1 + 1; end\n  =\u003e nil\n  irb(main):002:0\u003e pp method(:foo).body  \n  NODE_METHOD at (irb):1\n  |-noex = PUBLIC\n  |-body = \u003cISeq:foo@(irb)\u003e\n  | |-0000 trace            8\n  | |-0002 trace            1\n  | |-0004 putobject        1\n  | |-0006 putobject        1\n  | |-0008 opt_plus         \n  | |-0009 trace            16\n  | +-0011 leave            \n  +-cnt = 0\n\nYou can also access the original AST with Node.compile:\n\n  irb(main):001:0\u003e n = Node.compile_string('1+1')\n  =\u003e #\u003eNode::SCOPE:0x40420af0\u003e\n  irb(main):002:0\u003e pp n\n  NODE_SCOPE at (compiled):1\n  |-rval = NODE_CALL at (compiled):1\n  | |-recv = NODE_LIT at (compiled):1\n  | | +-lit = 1\n  | |-args = NODE_ARRAY at (compiled):1\n  | | |-alen = 1\n  | | |-head = NODE_LIT at (compiled):1\n  | | | +-lit = 1\n  | | +-next = false\n  | +-mid = :+\n  |-tbl = nil\n  +-next = false\n\ncompile it to a bytecode sequence:\n\n  irb(main):003:0\u003e is = n.bytecode_compile()\n  =\u003e \u003cISeq:\u003cmain\u003e@(compiled)\u003e\n  irb(main):004:0\u003e puts is.disasm\n  == disasm: \u003eISeq:\u003emain\u003e@(compiled)\u003e=====================================\n  0000 trace            1                                               (   1)\n  0002 putobject        1\n  0004 putobject        1\n  0006 opt_plus         \n  0007 leave            \n  =\u003e nil\n\niterate over the bytecode sequence:\n\n  irb(main):004:0\u003e is.each { |i| puts \"#{i.inspect} #{i.length} #{i.operand_types.inspect}\" }\n  #\u003cVM::Instruction::TRACE:0x40412324 @operands=[1]\u003e 2 [:num]\n  #\u003cVM::Instruction::PUTOBJECT:0x404121d0 @operands=[1]\u003e 2 [:value]\n  #\u003cVM::Instruction::PUTOBJECT:0x4041207c @operands=[1]\u003e 2 [:value]\n  #\u003cVM::Instruction::OPT_PLUS:0x40411f28 @operands=[]\u003e 1 []\n  #\u003cVM::Instruction::LEAVE:0x40411e24 @operands=[]\u003e 1 []\n  =\u003e nil\n\nthen decompile it (using ruby-decompiler):\n\n  irb(main):005:0\u003e require 'as_expression'\n  =\u003e true\n  irb(main):006:0\u003e is.as_expression\n  =\u003e \"1 + 1\"\n\nThere are still a few missing features (particularly in the decompiler),\nbut expect to see more exciting tools for working with bytecode in the\nfuture!\n\n== Other tools\n\nRuby-internal comes with two useful tools, nwdump and nwobfusc. The\nnwdump tool works in much the same way as the older Pragmatic nodedump\ntool. If you require it from the command line:\n\n  $ ruby -rinternal/node/dump test.rb\n\nit will dump your program's syntax tree. The nwobfusc tool is similar:\n\n  $ ruby -rinternal/obfusc test.rb \u003e test2.rb\n\nbut its output is an obfuscated version of your program. The program\nmust be run on the same version of both ruby-internal and the\ninterpreter.\n\n== Some notes about security\n\n- Data can always be inspected.\n- Methods that could potentially cause a crash if used incorrectly are\n  disallowed with $SAFE \u003e= 2.\n- Methods that could allow access to potentially sensitive data are\n  disallowed with $SAFE \u003e= 4.\n- Methods that load marshalled data do taint checks with $SAFE \u003e= 1.\n\n== Future directions\n\n* Load/dump the state of the ruby interpreter\n* Manipulate the AST/bytecode on-the-fly \n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcout%2Fruby-internal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcout%2Fruby-internal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcout%2Fruby-internal/lists"}