Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mbj/unparser
Turn Ruby AST into semantically equivalent Ruby source
https://github.com/mbj/unparser
parser ruby ruby-syntax unparser
Last synced: 2 days ago
JSON representation
Turn Ruby AST into semantically equivalent Ruby source
- Host: GitHub
- URL: https://github.com/mbj/unparser
- Owner: mbj
- License: mit
- Created: 2013-04-08T09:54:20.000Z (over 11 years ago)
- Default Branch: main
- Last Pushed: 2024-10-28T18:33:41.000Z (about 2 months ago)
- Last Synced: 2024-10-29T13:04:07.919Z (about 1 month ago)
- Topics: parser, ruby, ruby-syntax, unparser
- Language: Ruby
- Homepage:
- Size: 1.22 MB
- Stars: 310
- Watchers: 12
- Forks: 52
- Open Issues: 11
-
Metadata Files:
- Readme: README.md
- Changelog: Changelog.md
- License: LICENSE
Awesome Lists containing this project
- awesome-ruby-ast - unparser
README
unparser
========![CI](https://github.com/mbj/unparser/workflows/CI/badge.svg)
[![Gem Version](https://img.shields.io/gem/v/unparser.svg)](https://rubygems.org/gems/unparser)Generate equivalent source for ASTs from [parser](https://github.com/whitequark/parser).
The following constraints apply:
* No support for macruby extensions
* Only support for the [modern AST](https://github.com/whitequark/parser/#usage) format
* Only support for Ruby >= 3.1Notable Users:
* [mutant](https://github.com/mbj/mutant) - Code review engine via mutation testing.
* [ruby-next](https://github.com/ruby-next/ruby-next) - Ruby Syntax Backports.
* Many other [reverse-dependencies](https://rubygems.org/gems/unparser/reverse_dependencies).(if you want your tool to be mentioned here please PR the addition with a TLDR of your use case).
Public API:
-----------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.Usage
-----```ruby
require 'parser/current'
require 'unparser'ast = Unparser.parse('your(ruby(code))')
Unparser.unparse(ast) # => 'your(ruby(code))'
```To preserve the comments from the source:
```ruby
require 'parser/current'
require 'unparser'ast, comments = Unparser.parse_with_comments('your(ruby(code)) # with comments')
Unparser.unparse(ast, comments) # => 'your(ruby(code)) # with comments'
```Passing in manually constructed AST:
```ruby
require 'parser/current'
require 'unparser'module YourHelper
def s(type, *children)
Parser::AST::Node.new(type, children)
end
endinclude 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:
```ruby
require 'unparser'node = Unparser.parse(<<~'RUBY')
%w[foo bar]
RUBYgenerated = Unparser.unparse(node) # ["foo", "bar"], NOT %w[foo bar] !
code == generated # false, not identical code
Unparser.parse(generated) == node # true, but identical AST
```Summary: unparser does not reproduce your source! It produces equivalent source.
Ruby Versions:
--------------Unparsers primay reason for existance is mutant and its
supported [Ruby-Versions](https://github.com/mbj/mutant#ruby-versions).Basically: All non EOL MRI releases.
If you need to generate Ruby Syntax outside of this band feel free to contact me (email in gemspec).
Testing:
--------Unparser currently successfully round trips almost all ruby code around. Using Ruby >= 2.6.
If there is a non round trippable example that is NOT subjected to known [Limitations](#limitations).
please report a bug.On CI unparser is currently tested against rubyspec with minor [excludes](https://github.com/mbj/unparser/blob/master/spec/integrations.yml).
Limitations:
------------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.A fix is possible as with latest updates the parser gem carries the information.
Example:
Original-Source:
```ruby
# -*- 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:
```ruby
"\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")
```Installation
------------Install the gem `unparser` via your prefered method.
People
------Various people contributed to this repository. See [Contributors](https://github.com/mbj/unparser/graphs/contributors).
Included Libraries
------------------For dependency reduction reasons unparser ships vendored (and reduced) versions of:
* [abstract_type](https://github.com/mbj/concord) -> Unparser::AbstractType
* [adamantium](https://github.com/dkubb/adamantium) -> Unparser::Adamantium
* [anima](https://github.com/mbj/concord) -> Unparser::Anima
* [concord](https://github.com/mbj/concord) -> Unparser::Concord
* [memoizable](https://github.com/dkubb/memoizable) -> Unparser::Adamantium
* [mprelude](https://github.com/dkubb/memoizable) -> Unparser::EitherContributing
-------------* 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 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.Known Users
-------------* [RailsRocket](https://www.railsrocket.app) - A no-code app builder that creates Rails apps
License
-------See LICENSE file.