README.md in ripper-plus-1.2.0 vs README.md in ripper-plus-1.2.1
- old
+ new
@@ -117,22 +117,22 @@
#=>[:program,
[[:alias_error,
[:var_alias, [:@gvar, "$foo", [1, 6]], [:@backref, "$2", [1, 11]]]]]]
# Invalid class name
pp Ripper.sexp('class abc; end')
- #=> [:program,
+ => [:program,
[[:class,
[:const_ref, [:class_name_error, [:@ident, "abc", [1, 6]]]],
nil,
[:bodystmt, [[:void_stmt]], nil, nil, nil]]]]
[/code]
The first error, a disallowed alias, results in an `:alias_error` node wrapping the entire `:var_alias` node. This is good: anybody walking this AST would see that the entire contents of the node are semantically invalid *before* any information about the attempted alias. The second error, an invalid class name, results in a `:class_name_error` node deep in the `:class` node structure. This is bad: it puts the onus on every consumer of the AST to check all class/module definitions for `:class_name_error` nodes before assuming *anything* about the meaning of the `:class` node. This unfortunate placement also occurs when a parameter is named with a non-identifier:
[code]
pp Ripper.sexp('def foo(a, @b); end')
- #=> [:program,
+ => [:program,
[[:def,
[:@ident, "foo", [1, 4]],
[:paren,
[:params,
[[:@ident, "a", [1, 8]], [:param_error, [:@ivar, "@b", [1, 11]]]],
@@ -142,11 +142,11 @@
Worse, some errors are not caught at all:
[code]
pp Ripper.sexp('def foo(a, a, a); end')
- #=> [:program,
+ => [:program,
[[:def,
[:@ident, "foo", [1, 4]],
[:paren,
[:params,
[[:@ident, "a", [1, 8]],
@@ -158,11 +158,11 @@
This is very bad. Now every consumer of the Ripper parse tree must check *all method definitions* for repeated arguments, and bail accordingly. Don't forget about subassignments in block argument declarations; you'll need to check those yourself, too:
[code]
pp Ripper.sexp('something.each { |a, (b, *c, (d, e), a), f| }')
- #=> [:program,
+ => [:program,
[[:method_add_block,
[:call,
[:var_ref, [:@ident, "something", [1, 0]]], :".",
[:@ident, "each", [1, 10]]],
[:brace_block, [:block_var,
@@ -195,11 +195,9 @@
## Conclusion
Overall, Ripper is very complete for a library covered in "EXPERIMENTAL" warning labels, and gives concise, traditional ASTs. What I've put forward is all I ask after nearly a year of being neck-deep in Ripper output. I think the main two points I've covered need to be addressed in the 1.9 branch of Ruby, and over the coming months, hope to work to get that done.
In the meantime, I'll be using `ripper-plus` in Laser to statically analyze all kinds of stuff about Ruby, but I look forward to the day where I can add `RipperPlus = Ripper if RUBY_VERSION >= MERGED_VERSION` to ripper-plus's main file. `ripper-plus` is O(N), though it's not blazingly fast: it takes about 20-30 ms on my machine to transform the Ripper AST for [the biggest, ugliest Laser code file: the CFG compiler](https://github.com/michaeledgar/laser/blob/master/lib/laser/analysis/control_flow/cfg_builder.rb) to a RipperPlus AST. It takes 50ms for Ripper to parse it in the first place. (That benchmarked transformation is done in-place: `ripper-plus`'s default behavior is to duplicate the Ripper AST.)
-
-If you have ideas or thoughts, please discuss them on ruby-talk and/or ruby-core! I don't have comments implemented for a reason: I feel it fragments the center of discussion.
## Contributing to ripper-plus
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
\ No newline at end of file