Generate equivalent source for ASTs from whitequarks parser. Excluding the macruby extensions the parser gem implemnents on top of ruby syntax.
Excluding the MacRuby / RubyMotion extensions the parser gem implemenents on top of MRI Ruby syntax starting with parser release 2.3. If you feel the need to get them supported, contact me.
This library is able to reproduce 100% of Ruby 2.1 - 2.3 syntax. Including its own source code.
It serves well for mutant mutators and the in-memory vendoring for self hosting, and other tooling.
While unparser is in the 0.x
versions its public API can change any moment. I recommend to use ~> 0.x.y
style
version constraints that should give the best mileage.
require 'unparser'
Unparser.unparse(your_ast) # => "the code"
To preserve the comments from the source:
require 'parser/current'
require 'unparser'
ast, comments = Parser::CurrentRuby.parse_with_comments(your_source)
Unparser.unparse(ast, comments) # => "the code # with comments"
Passing in manually constructed AST:
require 'parser/current'
require 'unparser'
module YourHelper
def s(type, *children)
Parser::AST::Node.new(type, children)
end
end
include YourHelper
node = s(:def,
:foo,
s(:args,
s(:arg, :x)
),
s(:send,
s(:lvar, :x),
:+,
s(:int, 3)
)
)
Unparser.unparse(node) # => "def foo(x)\n x + 3\nend"
Note: DO NOT attempt to pass in nodes generated via AST::Sexp#s
, these ones return
API incompatible AST::Node
instances, unparser needs Parser::AST::Node
instances.
Equivalent vs identical:
require 'unparser'
code = <<-RUBY
%w(foo bar)
RUBY
node = Parser::CurrentRuby.parse(code)
generated = Unparser.unparse(node) # ["foo", "bar"], NOT %w(foo bar) !
code == generated # false, not identical code
Parser::CurrentRuby.parse(generated) == node # true, but identical AST
Summary: unparser does not reproduce your source! It produces equivalent source.
Unparser currently successfully round trips almost all ruby code around. Using MRI-2.0.0. If there is a non round trippable example that is NOT subjected to known Limitations. please report a bug.
On CI unparser is currently tested against rubyspec with minor excludes.
Source parsed with magic encoding headers other than UTF-8 and that have literal strings. where parts can be represented in UTF-8 will fail to get reproduced.
Please note: If you are on 1.9.3 or any 1.9 mode ruby and use UTF-8 encoded source via the magic encoding header: Unparser does not reproduce these.
A fix might be possible and requires some guessing or parser metadata the raw AST does not carry.
Example:
Original-Source:
# -*- encoding: binary -*-
"\x98\x76\xAB\xCD\x45\x32\xEF\x01\x01\x23\x45\x67\x89\xAB\xCD\xEF"
Original-AST:
(str "\x98v\xAB\xCDE2\xEF\x01\x01#Eg\x89\xAB\xCD\xEF")
Generated-Source:
"\x98v\xAB\xCDE2\xEF\x01\x01#Eg\x89\xAB\xCD\xEF"
Generated-AST:
(str "\x98v\xAB\xCDE2\xEF\u0001\u0001#Eg\x89\xAB\xCD\xEF")
Diff:
@@ -1,2 +1,2 @@
-(str "\x98v\xAB\xCDE2\xEF\x01\x01#Eg\x89\xAB\xCD\xEF")
+(str "\x98v\xAB\xCDE2\xEF\u0001\u0001#Eg\x89\xAB\xCD\xEF")
Install the gem unparser
via your prefered method.
Various people contributed to this repository. See Contributors.
- Fork the project.
- Make your feature addition or bug fix.
- Add tests for it. This is important so I don't break it in a future version unintentionally.
- Commit, do not mess with Rakefile or version (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
- Send me a pull request. Bonus points for topic branches.
See LICENSE file.