{"id":21909728,"url":"https://github.com/yanivmo/ruler","last_synced_at":"2025-03-22T07:52:55.574Z","repository":{"id":44865950,"uuid":"69144550","full_name":"yanivmo/ruler","owner":"yanivmo","description":"Humane formal grammar library for Python","archived":false,"fork":false,"pushed_at":"2022-12-26T20:30:45.000Z","size":76,"stargazers_count":2,"open_issues_count":12,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-28T21:31:18.961Z","etag":null,"topics":["grammar","regex","regular-expression"],"latest_commit_sha":null,"homepage":"","language":"Python","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/yanivmo.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-09-25T04:54:53.000Z","updated_at":"2018-09-06T11:17:39.000Z","dependencies_parsed_at":"2023-01-31T01:15:15.373Z","dependency_job_id":null,"html_url":"https://github.com/yanivmo/ruler","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanivmo%2Fruler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanivmo%2Fruler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanivmo%2Fruler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanivmo%2Fruler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yanivmo","download_url":"https://codeload.github.com/yanivmo/ruler/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244924801,"owners_count":20532878,"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":["grammar","regex","regular-expression"],"created_at":"2024-11-28T17:25:49.262Z","updated_at":"2025-03-22T07:52:55.543Z","avatar_url":"https://github.com/yanivmo.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"*****\nRuler\n*****\n\n.. image:: https://travis-ci.org/yanivmo/ruler.svg?branch=master\n    :target: https://travis-ci.org/yanivmo/ruler\n    :alt: Build status\n\n.. image:: https://landscape.io/github/yanivmo/ruler/master/landscape.svg?style=flat\n   :target: https://landscape.io/github/yanivmo/ruler/master\n   :alt: Code Health\n\n.. image:: https://coveralls.io/repos/github/yanivmo/ruler/badge.svg?branch=master\n   :target: https://coveralls.io/github/yanivmo/ruler?branch=master\n\n.. image:: https://img.shields.io/pypi/v/ruler.svg\n   :target: https://pypi.python.org/pypi/ruler\n\n\nRuler is a lightweight regular expressions wrapper aiming to make regex definitions more\nmodular, intuitive, readable and the mismatch reporting more informative.\n\nInstallation\n============\n::\n\n    pip install ruler\n\n\nQuick start\n===========\n\nLet's implement the following grammar, given in EBNF_::\n\n    grammar = who, ' likes to drink ', what;\n    who = 'John' | 'Peter' | 'Ann' | 'Paul' | 'Rachel';\n    what = tea | juice;\n    juice = 'juice';\n    tea = 'tea', [milk];\n    milk = ' with milk';\n\nUsing ruler it looks almost identical to EBNF_:\n\n\u003e\u003e\u003e class Morning(Grammar):\n...     who = OneOf('John', 'Peter', 'Ann', 'Paul', 'Rachel')\n...     juice = Rule('juice')\n...     milk = Optional(' with milk')\n...     tea = Rule('tea', milk)\n...     what = OneOf(juice, tea)\n...     grammar = Rule(who, ' likes to drink ', what, '\\.')\n...\n... morning = Morning.create()\n\nA member named ``grammar`` must be always present - it acts as the start rule.\nLet's begin rather with a mismatch:\n\n\u003e\u003e\u003e morning.match('John likes to drink coffee')\nFalse\n\n``match()`` returns ``True`` if the match was successful and ``False`` otherwise.\nOne of the major advantages of ``ruler``, as opposed to working directly with regular expressions,\nis the ability to know exactly what went wrong:\n\n\u003e\u003e\u003e print(morning.error.long_description)\nMismatch at 20:\n  John likes to drink coffee\n                      ^\n\"coffee\" does not match \"juice\"\n\"coffee\" does not match \"tea\"\n\nLet's fix our text:\n\n\u003e\u003e\u003e morning.match('John likes to drink tea.')\nTrue\n\nAny rule that is declared as a member variable of your grammar class acts as a named capture group\narranged hierarchically. Use ``matched`` attribute to retrieve the text matched by a specific rule:\n\n\u003e\u003e\u003e morning.matched\n'John likes to drink tea.'\n\u003e\u003e\u003e morning.who.matched\n'John'\n\u003e\u003e\u003e morning.what.matched\n'tea'\n\nBranches of OneOf rules that didn't match and optional rules that didn't match have ``None`` as\ntheir values making it easy to ask whether they matched:\n\n\u003e\u003e\u003e morning.what.juice.matched is None\nTrue\n\u003e\u003e\u003e morning.what.tea.matched is None\nFalse\n\u003e\u003e\u003e morning.what.tea.milk.matched is None\nTrue\n\nRules can be reused multiple times. If the same rule appears multiple times under the same parent,\nthese rules are collected into a list:\n\n\u003e\u003e\u003e class Morning(Grammar):\n...     person = OneOf('John', 'Peter', 'Ann', 'Paul', 'Rachel')\n...     who = Rule(person, Optional(', ', person), Optional(' and ', person))\n...     juice = Rule('juice')\n...     milk = Optional(' with milk')\n...     tea = Rule('tea', milk)\n...     what = OneOf(juice, tea)\n...     grammar = Rule(who, ' like', Optional('s'), ' to drink ', what, '\\.')\n...\n... morning = Morning.create()\n... morning.match('Peter, Rachel and Ann like to drink juice.')\nTrue\n\u003e\u003e\u003e morning.who.matched\n'Peter, Rachel and Ann'\n\u003e\u003e\u003e morning.who.person[0].matched\n'Peter'\n\u003e\u003e\u003e morning.who.person[1].matched\n'Rachel'\n\u003e\u003e\u003e morning.who.person[2].matched\n'Ann'\n\nNotice that, in the grammar above, ``person`` rule is never a direct child of ``who`` but still\nis accessed as such. That is because when a rule hierarchy is built, a rule is placed under its\nclosest named ancestor.\n\nRules' string arguments may actually be any valid regular expression. So we could rewrite our\ngrammar like this:\n\n\u003e\u003e\u003e class Morning(Grammar):\n...     who = OneOf('\\w+')\n...     juice = Rule('juice')\n...     milk = Optional(' with milk')\n...     tea = Rule('tea', milk)\n...     what = OneOf(juice, tea)\n...     grammar = Rule(who, ' likes to drink ', what, '\\.')\n...\n... morning = Morning()\n... morning.match('R2D2 likes to drink juice. And nothing else matters.')\nTrue\n\u003e\u003e\u003e morning.matched\n'R2D2 likes to drink juice.'\n\u003e\u003e\u003e morning.who.matched\n'R2D2'\n\n\nPerformance\n===========\nThe library is well optimized for fast matching. Nevertheless it is important to remember\nthat this is a Python wrapper of the regex library and as such can never outperform matching\ndirectly using the regex library. Currently ruler measures approximately ten times slower\nthan ``re``.\n\n\nDevelopment\n===========\n\n* To run the tests::\n\n    pytest tests\n\n* To compare the performance to the re library::\n\n    python performance/re_compare.py\n\n* To run performance profiling of a specific method, ``Rule.match`` for example::\n\n    python performance/profile.py Rule.match\n\n  More than one method can be specified in the same command.\n\nTox\n---\nTox takes care of everything without installing anything manually. There are two groups of tox\nenvironments: ``py*-test`` and ``py*-profile``. The test environments run the unit tests while the\nprofile environments run the performance profiling scripts. If tox is not enough then a development\nenvironment can be generated by creating a new virtualenv and then running\n``pip install -r requirements_develop.txt``.\n\n\nDependency management\n---------------------\nFor the development needs, there are three requirements files in the project's root directory:\n\n- ``requirements_test.txt`` contains all the dependencies needed to run the unit tests,\n- ``requirements_profile.txt`` contains all the dependencies needed to run the performance profiling,\n- ``requirements_develop.txt`` contains the testing dependencies, the profiling dependencies and some additional\n  dependencies used in development.\n\nThe requirements files mentioned above are not intended for manual editing. Instead they are managed\nusing `pip-tools`_. The process of updating the requirements is as follows:\n\n#. Add, remove or update a dependency in one of the ``reqs_*.dep`` files:\n\n   - Update ``reqs_install.dep`` if the dependency is needed for the regular installation by the end user,\n   - Update ``reqs_test.dep`` if the dependency is needed to run the unit tests but is not necessary for the\n     regular installation,\n   - Update ``reqs_profile.dep`` if the dependency is needed to run the performance profiling but is not necessary\n     for the regular installation,\n   - Update ``reqs_develop.dep`` if the dependency is not in one of the previous categories.\n\n#. Generate the requirements file running ``pip-compile``. The exact command is documented in the beginning of each\n   requirements file.\n#. Consider running ``pip-sync requirements_develop.txt``.\n\nNotice that there is no need to edit ``setup.py`` - it will pull the dependencies by itself from ``reqs_install.dep``.\n\n\n.. _EBNF: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form\n.. _pip-tools: https://github.com/jazzband/pip-tools","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyanivmo%2Fruler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyanivmo%2Fruler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyanivmo%2Fruler/lists"}