kschiess / parslet

A small PEG based parser library. See the Hacking page in the Wiki as well.
kschiess.github.com/parslet
MIT License
809 stars 95 forks source link

Allow options in Parslet::ClassMethods.parse #82

Closed RyanScottLewis closed 11 years ago

RyanScottLewis commented 11 years ago

This pull request allows options to be passed to the rule class method as well as specs to prove that they are working correctly.

Options


:predicate

If true, it defines another rule with the atom .maybe attached to it.

Without

rule(:space) { str(' ') }
rule(:space?) { space.maybe }

With

rule(:space, predicate: true) { str(' ') }

:repeat

If true, it defines another rule with the atom .repeat(1) attached to it.

Without

rule(:space) { str(' ') }
rule(:spaces) { space.repeat(1) }

With

rule(:space, repeat: true) { str(' ') }

If a Hash is passed, it allows for extra options to be passed:

:min and :max

These allow a developer to set the min and max repeat arguments on the "repeated" rule.

Without

rule(:space) { str(' ') }
rule(:spaces) { space.repeat(3, 5) }

With

rule(:space, repeat: { min: 3, max: 5 }) { str(' ') }

:predicate

If true, it defines another "repeated" rule with the atom .maybe attached to it.

Without

rule(:space) { str(' ') }
rule(:spaces) { space.repeat(1) }
rule(:spaces?) { spaces.maybe }

With

rule(:space, repeat: { min: 3, max: 5, predicate: true }) { str(' ') }
kschiess commented 11 years ago

Hi Ryan,

Thanks for the PR & for using parslet!

I don't think the rule API needs extending. What you're proposing can very simply be achieved by something like

def self.maybe_rule name, rule
   define_method name do 
      self.send(rule).maybe
   end
end

rule(:space) { ... }
maybe_rule(:space?, :space)

Obviously this can be extended and made to look exactly like what you're proposing. My point here is: This doesn't add to parslet except sugar - and I am trying to keep things simple and give everyone one way of doing things.

If you look at projects from people that work with parslet (the doc page has a list) - nearly everyone is doing a small amount of meta-programming not unlike the example above to make things easier - but not everyone's metaprogramming looks the same - which is why I don't include it in parslet itself.

In a way, parslets API is unwieldy on purpose - it's also pure Ruby and very hackable - I encourage people to extend parslet for their projects!

Also, I am trying to keep Rails out of parslet ;) That includes methods with options and activesupport. Not every Rubyist likes the Rails style of doing things.

I hope this makes sense to you. If you would like discuss extensions to parslet, I would like to welcome you to our mailing list - it is where an extension like this one might receive the support that it needs to make it past my critical eye. Also - keep the contributions coming, I actually merge from time to time ;)

regards, kaspar

RyanScottLewis commented 11 years ago

Sounds good, I'll make a gem which will allow devs to mixin this functionality using modules and leave the choice up to them.

This was my original plan, but I figured I would shoot this pull request out there and see what would come of it. :+1:

Cheers, -- Ryan