(This post answers pull request 37[1] on github. I think this is the
better medium for discussing this)
Hi Jason,
I was/am aware of the lack of consistency in the execution environment
for parslet's transformation blocks. That's on purpose. Let me explain:
Unlike parsers (< Parslet::Parser), transformations are classes in their
own right that have state and behaviour. Although the elements of a
transformation are also called #rule, (which is unfortunate), they act
very differently. My LISP loving heart wants transformations to be
stateless, purely functional.
I designed the transformations to be good for one thing: Getting out of
the horrible Hash/Array/Slice mixture into the realm of your own AST
classes easily. I think they fulfill that purpose well. Usually, no
state is associated with that operation.
To you it (going into an AST first, then doing work) may look like an
added step with no rationale; I can see that and will try to improve
transformations for people who want to use them to produce results
directly. However. Your pull request encourages users of parslet to keep
state in the transformation instance directly, which strikes me as very
bad OOP - it violates the single responsibility principle.
Having state in the transformation will also make it non-trivial to
update to new parslet versions - I might use @doc in Parslet::Transform
in the future, leaving you with broken tests.
But let me propose something that might work for both of us: How about
injecting context during the apply call?
transform = Parslet::Transform.new do
rule(...) { doc.insert(...) } # doc is defined here
rule(...) { |d| d[:doc].insert(...) } # and also here
end
transform.apply(tree, :doc => MyDocument.new)
My hope is to leave the execution context of transformations officially
undefined, providing for everything needed for nice code without having
to anchor them. If I find a way to inject local variables without the
Context hack, I'll eliminate it, opting for definition scope everywhere.
But I have currently no idea on how to do that. But the above change
would be trivial.
As an aside: I think implementation discussions and feature requests
belong to the mailing list - more people watching this. A pull request
is not a discussion of possibilities, it makes me say 'yes' or 'no',
hard to strike a note between. Instead of giving you a 'no', I want to
say 'yes, but how would you like this?'. Github doesn't let me do that
very well.
How about it?
regards
kaspar
[1] https://github.com/kschiess/parslet/pull/37