Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/marcelotto/parspec
A testing framework for Parslet grammars
https://github.com/marcelotto/parspec
gunit parser parser-specifications parslet rspec ruby testing
Last synced: 4 months ago
JSON representation
A testing framework for Parslet grammars
- Host: GitHub
- URL: https://github.com/marcelotto/parspec
- Owner: marcelotto
- License: mit
- Created: 2014-10-24T18:03:19.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2017-09-08T17:39:57.000Z (over 7 years ago)
- Last Synced: 2024-04-24T18:13:48.980Z (9 months ago)
- Topics: gunit, parser, parser-specifications, parslet, rspec, ruby, testing
- Language: Ruby
- Homepage: http://rubygems.org/gems/parspec
- Size: 25.4 KB
- Stars: 7
- Watchers: 4
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Parspec
A [gUnit](https://theantlrguy.atlassian.net/wiki/display/ANTLR3/gUnit+-+Grammar+Unit+Testing)-like specification language for [Parslet](http://kschiess.github.io/parslet/) parsers and transformers, which gets translated to [RSpec](http://rspec.info/) specs.
## Status
This software is feature-complete, since it realizes the features of [gUnit](https://theantlrguy.atlassian.net/wiki/display/ANTLR3/gUnit+-+Grammar+Unit+Testing) (with some additions) completely and can successfully be used as a full [gUnit](https://theantlrguy.atlassian.net/wiki/display/ANTLR3/gUnit+-+Grammar+Unit+Testing)-like replacement of handmade [RSpec](http://rspec.info/) specs. I won't implement any new features. Feel free to fork and take over maintainership.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'parspec', group: :test
```And then execute:
$ bundle
Or install with gem:
$ gem install parspec
## Specification language
### Example
The following example shows parts of the [TOML spec](https://github.com/zerowidth/toml-parslet/blob/master/spec/toml/parser_spec.rb) translated to Parspec:
parser TOML::Parser
value:
"120381" OK
"0181" FAIL
"3.14159" OK
".1" FAIL
"true" OK
"truefalse" FAIL
"1979-05-27T07:32:00Z" OK
"1979l05-27 07:32:00" FAIL
"\"hello world\"" OK
"\"hello\nworld\"" FAIL
"\"hello/world\"" FAIL
"1234" -> ":integer => '1234'"
"-0.123" -> ":float => '-0.123'"
"true" -> ":boolean => 'true'"
"1979-05-27T07:32:00Z" -> ":datetime => '1979-05-27T07:32:00Z'"
"\"hello world\"" -> ":string => 'hello world'"
"\"hello\nworld\"" -> ":string => \"hello\nworld\""
array:
"[]" OK
"[1]" OK
"[0.1, -0.1, 3.14159]" OK
"[ true, false, true, true ]" OK
"[1979-05-27T07:32:00Z]" OK # [2013-02-24T17:26:21Z]
"[\n1\n,\n2\n]" OK
"[\n\n\t1 , 2, 3\\t,4\n]" OK
"[1, 2, \"three\"]" FAIL
"[1,2,]" OK
"[1,2\n,\\t]" OK
"[1,2]" -> ":array => [ {:integer => '1'}, {:integer => '2'}]"
"[]" -> ":array => '[]'"
"[ [1,2] ]"
-> ":array => [
{:array => [ {:integer => '1'}, {:integer => '2'}]}
]"
key:
"foobar" OK
"lolwhat.noWAY" OK
"no white\\tspace" FAIL
"noequal=thing" FAIL
assignment:
"key=3.14" OK
"key = 10" OK
"key = true" OK
"key = \"value\"" OK
"#comment=1" FAIL
"thing = 1" -> ":key => 'thing', :value => {:integer => '1'}"### Description
#### Header
A Parspec specification starts with a definition of the subject:
There are two types of specifications: `parser` and `transformer`. A parser specification describes a `Parslet::Parser`, a transformer specification describes a `Parslet::Transform`. Syntactically these types of specifications are equal, but the generated RSpec descriptions will differ.
The instantiation expression is used to create a RSpec test subject. It usually consists of a constant for a `Parslet::Parser` or `Parslet::Transform` class, according to the type of specification, but can be any valid Ruby expression, which responds to `new` with a `Parslet::Parser` or `Parslet::Tranform` instance.
#### Rule examples
After the definition, a series of examples for the grammar rules follows. Rules start with a rule name followed by a colon.
There are two types of examples: validations and mapping examples.
##### Validations
A validation is a string in double-quotes followed either by the keyword `OK` or `FAIL`, according to the expected outcome of parsing the given string under the given rule. Currently, it is supported in parser specifications only.
For example, the following validation:
some_rule:
"some input" OK
"another input" FAILwill translate to this RSpec description:
```ruby
context 'some_rule parsing' do
subject { parser.some_rule }it { should parse 'some input' }
it { should_not parse 'another input' }
end
```##### Mapping examples
Mapping examples describe the input-output-behaviour of a rule. Syntactically they consist of two strings separated by `->`. Since the semantics of parser and transformer specifications differ, let's discuss them separately, starting with the parser case:
While the input string on the left side is simply some sample text as in a validity example, the output string on the right must contain a valid Ruby expression, which should evaluate to the expected outcome of the respective rule parsing.
For example, the following mapping:
some_rule:
"some input" -> "42"
"another input" -> "{ foo: 'bar' }"will be translated to the following RSpec parser specification:
```ruby
context 'some_rule parsing' do
subject { parser.some_rule }it "should parse 'some input' to 42" do
expect(subject.parse('some input')).to eq 42
endit "should parse 'another input' to { foo: 'bar' }" do
expect(subject.parse('another input')).to eq { foo: 'bar' }
end
end
```In the case of a transformer specification, both sides must contain Ruby expressions.
#### Shared examples
The examples of a rule can be reused inside other rules with the `include` keyword:
some_rule:
"some input" -> "42"
"another input" -> "{ foo: 'bar' }"another_rule:
include some_rule#### String escaping
Parspec strings in general support the following escape sequences: `\t`, `\n`, `\r`, `\"`, `\\`.
#### Comments
One-line comments are supported in the `#`-style.
## Usage
### Command-line interface
Parspec comes with a command-line interface through the `parspec` command.
For a full description of the available parameters, run:
$ parspec --help
Usage: parspec [options] PARSPEC_FILE
-h, --help Display this information
-v, --version Print version information
-s, --stdout Print the translation to stdout only
-o, --out OUTPUT_FILE Path where translated RSpec file should be stored
-b, --beside-input Put the output file into the same directory as the input
-e, --header HEADER A block of code to be put in front of the translation
--no-debug-parse Don't print the whole Parslet ascii_tree on errorsUnless specified otherwise, the default header is:
```ruby
# coding: utf-8
require 'spec_helper'
require 'parslet/convenience'
require 'parslet/rig/rspec'
```### `load_parspec`
You can use the command-line interface to integrate Parspec in your testing tool chain, e.g. via Rake or Guard.
But you can also load your Parspec spec from a normal Ruby file in your spec directory with the `load_parspec` command:
```ruby
require 'spec_helper'
require 'parspec'
require 'my_parser'load_parspec __FILE__
```If the `load_parspec` command gets a filename with the extension `.rb`, it looks for a file with the same name, but the extension `.parspec`. For example, if the former Ruby file would be at `spec/my_parser/my_parser_spec.rb`, the `load_parspec` command would try to load a Parspec spec from a file `spec/my_parser/my_parser_spec.parspec`.
Note: This feature is currently implemented via `eval`, till I find a way to include specs from other RSpec files or another alternative. If you have any advice, please share it in [issue #1](https://github.com/marcelotto/parspec/issues/1).
## Contributing
1. Fork it ( https://github.com/marcelotto/parspec/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request## Author
- Marcel Otto