{"id":15240465,"url":"https://github.com/marcelotto/parspec","last_synced_at":"2025-04-10T13:42:58.657Z","repository":{"id":22364911,"uuid":"25701143","full_name":"marcelotto/parspec","owner":"marcelotto","description":"A testing framework for Parslet grammars","archived":false,"fork":false,"pushed_at":"2017-09-08T17:39:57.000Z","size":26,"stargazers_count":7,"open_issues_count":2,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-24T18:13:48.980Z","etag":null,"topics":["gunit","parser","parser-specifications","parslet","rspec","ruby","testing"],"latest_commit_sha":null,"homepage":"http://rubygems.org/gems/parspec","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcelotto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-24T18:03:19.000Z","updated_at":"2019-05-11T09:30:00.000Z","dependencies_parsed_at":"2022-08-21T00:50:50.140Z","dependency_job_id":null,"html_url":"https://github.com/marcelotto/parspec","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelotto%2Fparspec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelotto%2Fparspec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelotto%2Fparspec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelotto%2Fparspec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcelotto","download_url":"https://codeload.github.com/marcelotto/parspec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248226275,"owners_count":21068173,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gunit","parser","parser-specifications","parslet","rspec","ruby","testing"],"created_at":"2024-09-29T11:05:08.063Z","updated_at":"2025-04-10T13:42:58.630Z","avatar_url":"https://github.com/marcelotto.png","language":"Ruby","readme":"# Parspec\n\nA [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.\n\n\n## Status\n\nThis 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.\n\n\n\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'parspec', group: :test\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install with gem:\n\n    $ gem install parspec\n\n\n## Specification language\n\n### Example\n\nThe following example shows parts of the [TOML spec](https://github.com/zerowidth/toml-parslet/blob/master/spec/toml/parser_spec.rb) translated to Parspec:\n\n    parser TOML::Parser\n    \n    value:\n        \"120381\" OK\n        \"0181\" FAIL\n        \"3.14159\" OK\n        \".1\" FAIL\n        \"true\" OK\n        \"truefalse\" FAIL\n        \"1979-05-27T07:32:00Z\" OK\n        \"1979l05-27 07:32:00\" FAIL\n        \"\\\"hello world\\\"\" OK\n        \"\\\"hello\\nworld\\\"\" FAIL\n        \"\\\"hello/world\\\"\" FAIL\n    \n        \"1234\"                 -\u003e \":integer =\u003e '1234'\"\n        \"-0.123\"               -\u003e \":float   =\u003e '-0.123'\"\n        \"true\"                 -\u003e \":boolean =\u003e 'true'\"\n        \"1979-05-27T07:32:00Z\" -\u003e \":datetime =\u003e '1979-05-27T07:32:00Z'\"\n        \"\\\"hello world\\\"\"      -\u003e \":string =\u003e 'hello world'\"\n        \"\\\"hello\\nworld\\\"\"     -\u003e \":string =\u003e \\\"hello\\nworld\\\"\"\n    \n    array:\n        \"[]\" OK\n        \"[1]\" OK\n        \"[0.1, -0.1, 3.14159]\" OK\n        \"[ true, false, true, true ]\" OK\n        \"[1979-05-27T07:32:00Z]\" OK  # [2013-02-24T17:26:21Z]\n        \"[\\n1\\n,\\n2\\n]\" OK\n        \"[\\n\\n\\t1  , 2,     3\\\\t,4\\n]\" OK\n        \"[1, 2, \\\"three\\\"]\" FAIL\n        \"[1,2,]\" OK\n        \"[1,2\\n,\\\\t]\" OK\n    \n         \"[1,2]\"     -\u003e \":array =\u003e [ {:integer =\u003e '1'}, {:integer =\u003e '2'}]\"\n         \"[]\"        -\u003e \":array =\u003e '[]'\"\n         \"[ [1,2] ]\"\n            -\u003e \":array =\u003e [\n                  {:array =\u003e [ {:integer =\u003e '1'}, {:integer =\u003e '2'}]}\n               ]\"\n    \n    key:\n         \"foobar\" OK\n         \"lolwhat.noWAY\" OK\n         \"no white\\\\tspace\" FAIL\n         \"noequal=thing\" FAIL\n    \n    assignment:\n          \"key=3.14\" OK\n          \"key = 10\" OK\n          \"key = true\" OK\n          \"key = \\\"value\\\"\" OK\n          \"#comment=1\" FAIL\n          \"thing = 1\" -\u003e \":key =\u003e 'thing', :value =\u003e {:integer =\u003e '1'}\"\n\n\n### Description\n\n#### Header\n\nA Parspec specification starts with a definition of the subject:\n\n    \u003ctype\u003e \u003cinstantiation expression\u003e\n\nThere 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.\n\nThe 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.\n\n\n#### Rule examples\n\nAfter the definition, a series of examples for the grammar rules follows. Rules start with a rule name followed by a colon.\n\nThere are two types of examples: validations and mapping examples.\n\n\n##### Validations\n\nA 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.\n\nFor example, the following validation:\n\n    some_rule:\n      \"some input\" OK\n      \"another input\" FAIL\n\nwill translate to this RSpec description:\n\n```ruby\ncontext 'some_rule parsing' do\n  subject { parser.some_rule }\n\n  it { should parse 'some input' }\n  it { should_not parse 'another input' }\nend\n```\n\n\n##### Mapping examples\n\nMapping examples describe the input-output-behaviour of a rule. Syntactically they consist of two strings separated by `-\u003e`. Since the semantics of parser and transformer specifications differ, let's discuss them separately, starting with the parser case:\n\nWhile 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.\n\nFor example, the following mapping:\n\n    some_rule:\n      \"some input\"    -\u003e \"42\"\n      \"another input\" -\u003e \"{ foo: 'bar' }\"\n\nwill be translated to the following RSpec parser specification:\n\n```ruby\ncontext 'some_rule parsing' do\n  subject { parser.some_rule }\n\n  it \"should parse 'some input' to 42\" do\n    expect(subject.parse('some input')).to eq 42\n  end\n\n  it \"should parse 'another input' to { foo: 'bar' }\" do\n    expect(subject.parse('another input')).to eq { foo: 'bar' }\n  end\nend\n```\n\nIn the case of a transformer specification, both sides must contain Ruby expressions.\n\n\n#### Shared examples\n\nThe examples of a rule can be reused inside other rules with the `include` keyword:\n\n    some_rule:\n      \"some input\"    -\u003e \"42\"\n      \"another input\" -\u003e \"{ foo: 'bar' }\"\n\n    another_rule:\n      include some_rule\n\n\n#### String escaping\n\nParspec strings in general support the following escape sequences: `\\t`, `\\n`, `\\r`, `\\\"`, `\\\\`. \n  \n\n#### Comments\n\nOne-line comments are supported in the `#`-style.\n\n\n## Usage\n\n### Command-line interface\n\nParspec comes with a command-line interface through the `parspec` command.\n\nFor a full description of the available parameters, run:\n\n    $ parspec --help\n    Usage: parspec [options] PARSPEC_FILE\n        -h, --help                       Display this information\n        -v, --version                    Print version information\n        -s, --stdout                     Print the translation to stdout only\n        -o, --out OUTPUT_FILE            Path where translated RSpec file should be stored\n        -b, --beside-input               Put the output file into the same directory as the input\n        -e, --header HEADER              A block of code to be put in front of the translation\n            --no-debug-parse             Don't print the whole Parslet ascii_tree on errors\n\nUnless specified otherwise, the default header is:\n\n```ruby\n# coding: utf-8\nrequire 'spec_helper'\nrequire 'parslet/convenience'\nrequire 'parslet/rig/rspec'\n```\n\n\n### `load_parspec` \n\nYou can use the command-line interface to integrate Parspec in your testing tool chain, e.g. via Rake or Guard. \n\nBut you can also load your Parspec spec from a normal Ruby file in your spec directory with the `load_parspec` command:   \n\n```ruby\nrequire 'spec_helper'\nrequire 'parspec'\nrequire 'my_parser'\n\nload_parspec __FILE__\n```\n\nIf 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`.\n\n\nNote: 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).\n\n\n## Contributing\n\n1. Fork it ( https://github.com/marcelotto/parspec/fork )\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## Author\n\n- Marcel Otto\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcelotto%2Fparspec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcelotto%2Fparspec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcelotto%2Fparspec/lists"}