Full Code of jawira/case-converter for AI

master 869a0780f069 cached
80 files
147.0 KB
39.6k tokens
149 symbols
1 requests
Download .txt
Repository: jawira/case-converter
Branch: master
Commit: 869a0780f069
Files: 80
Total size: 147.0 KB

Directory structure:
gitextract_86zso1k9/

├── .codeclimate.yml
├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       ├── docs.yaml
│       └── qa.yaml
├── .gitignore
├── LICENSE.md
├── README.md
├── build.xml
├── composer.json
├── config/
│   ├── behat.yml
│   └── phpunit.xml
├── docs/
│   ├── api.md
│   ├── case-mapping.md
│   ├── detection-algorithm.md
│   ├── dev.md
│   ├── images/
│   │   ├── build.puml
│   │   ├── detection-algorithm.puml
│   │   ├── number-problem.puml
│   │   ├── railroad.js
│   │   ├── uml-case-converter.puml
│   │   ├── uml-glue.puml
│   │   └── uml-split.puml
│   ├── index.md
│   ├── known-issues.md
│   ├── naming-conventions.md
│   └── using-the-factory.md
├── mkdocs.yml
├── src/
│   ├── CaseConverter.php
│   ├── CaseConverterException.php
│   ├── CaseConverterInterface.php
│   ├── Convert.php
│   ├── Glue/
│   │   ├── AdaCase.php
│   │   ├── CamelCase.php
│   │   ├── CobolCase.php
│   │   ├── DashGluer.php
│   │   ├── DotNotation.php
│   │   ├── Gluer.php
│   │   ├── KebabCase.php
│   │   ├── LowerCase.php
│   │   ├── MacroCase.php
│   │   ├── PascalCase.php
│   │   ├── SentenceCase.php
│   │   ├── SnakeCase.php
│   │   ├── SpaceGluer.php
│   │   ├── TitleCase.php
│   │   ├── TrainCase.php
│   │   ├── UnderscoreGluer.php
│   │   ├── UpperCase.php
│   │   └── UppercaseGluer.php
│   └── Split/
│       ├── DashSplitter.php
│       ├── DotSplitter.php
│       ├── SpaceSplitter.php
│       ├── Splitter.php
│       ├── UnderscoreSplitter.php
│       └── UppercaseSplitter.php
└── tests/
    ├── behat/
    │   ├── bootstrap/
    │   │   └── FeatureContext.php
    │   └── case-converter.feature
    └── phpunit/
        ├── AdaCaseTest.php
        ├── CamelCaseTest.php
        ├── CaseConverterTest.php
        ├── CobolCaseTest.php
        ├── ConvertTest.php
        ├── DashSplitterTest.php
        ├── DotNotationTest.php
        ├── DotSplitterTest.php
        ├── GluerTest.php
        ├── KebabCaseTest.php
        ├── LowerCaseTest.php
        ├── MacroCaseTest.php
        ├── PascalCaseTest.php
        ├── SentenceCaseTest.php
        ├── SnakeCaseTest.php
        ├── SpaceSplitterTest.php
        ├── SplitterTest.php
        ├── TitleCaseTest.php
        ├── TrainCaseTest.php
        ├── UnderscoreSplitterTest.php
        ├── UpperCaseTest.php
        └── UppercaseSplitterTest.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .codeclimate.yml
================================================
plugins:
  sonar-php:
    enabled: true
    config:
      tests_patterns:
        - tests/**
  fixme:
    enabled: true


================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
trim_trailing_whitespace = true
end_of_line = lf
insert_final_newline = true
indent_style = space
ij_visual_guides = 80, 120

[*.php]
indent_size = 4
max_line_length = 120
ij_php_align_multiline_chained_methods = true
ij_php_align_phpdoc_comments = true
ij_php_align_phpdoc_param_names = true
ij_php_align_assignments = true
ij_php_align_multiline_array_initializer_expression = true
ij_php_align_key_value_pairs = true
ij_php_align_match_arm_bodies = true
ij_php_phpdoc_use_fqcn = true

[*.{yml, yaml, neon, xml, svg, json, js}]
indent_size = 2

[*.{md, markdown}]
trim_trailing_whitespace = false
indent_size = 2
max_line_length = 80
ij_markdown_wrap_text_if_long = true


================================================
FILE: .gitattributes
================================================
/.github            export-ignore
/.idea              export-ignore
/config             export-ignore
/docs               export-ignore
/resources          export-ignore
/tests              export-ignore
/.codeclimate.yml   export-ignore
/.editorconfig      export-ignore
/.gitattributes     export-ignore
/.gitignore         export-ignore
/build.xml          export-ignore
/mkdocs.yml         export-ignore
/README.md          export-ignore


================================================
FILE: .github/workflows/docs.yaml
================================================
name: Publish documentation

on:
  release:
    types: [ published ]

jobs:
  build:
    name: Deploy docs
    runs-on: ubuntu-20.04
    steps:

      - name: Checkout main
        uses: actions/checkout@v2

      - name: Deploy docs
        uses: mhausenblas/mkdocs-deploy-gh-pages@master
        env:
          SITE_NAME: "Case Converter ${{ github.event.release.tag_name }}"
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/qa.yaml
================================================
name: Quality assurance

on:
  pull_request:
  push:
    branches:
      - master

jobs:
  tests:
    strategy:
      matrix:
        php: [ '7.4','8.0','8.1','8.2','8.3','8.4' ]
    runs-on: ubuntu-24.04
    steps:

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          extensions: mbstring, intl
          coverage: xdebug
          tools: phing:v3

      - uses: actions/checkout@v2

      - name: Phing setup
        run: phing setup

      - name: lint php
        run: phing php:lint

      - name: validate composer
        run: phing composer:validate

      - name: behat
        run: phing behat:run

      - name: phpstan
        run: phing phpstan:analyse

      - name: CC before build
        run: phing cc:before-build
        env:
          CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}

      - name: PHPUnit
        run: phing phpunit:run

      - name: CC after build
        run: phing cc:after-build
        env:
          CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}


================================================
FILE: .gitignore
================================================
/.idea/
!/.idea/dictionaries/
/resources/coverage/
/resources/phpdoc/
/vendor/
/bin/
/composer-setup.php
/composer.lock
/coverage/codeclimate.json
/resources/phploc.txt
/resources/coverage-html/
/site/
/docs/CONTRIBUTING.md
/docs/LICENSE.md
/docs/license.md
/docs/contributing.md
/docs/changelog.md
/build.png
/build.svg
/config/.phpunit.result.cache
/clover.xml


================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)
=====================

Copyright © 2015-2022 Jawira Portugal

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
Case converter
==============

Use this library to convert string between:

| Name              | Method         | Output example    |
|-------------------|----------------|-------------------|
| 🐪 Camel case     | `toCamel()`    | `myNameIsBond`    |
| 👨‍🏫 Pascal case | `toPascal()`   | `MyNameIsBond`    |
| 🐍 Snake case     | `toSnake()`    | `my_name_is_bond` |
| 👩‍🏫 Ada case    | `toAda()`      | `My_Name_Is_Bond` |
| Ⓜ️ Macro case     | `toMacro()`    | `MY_NAME_IS_BOND` |
| 🥙 Kebab case     | `toKebab()`    | `my-name-is-bond` |
| 🚂 Train case     | `toTrain()`    | `My-Name-Is-Bond` |
| 🏦 Cobol case     | `toCobol()`    | `MY-NAME-IS-BOND` |
| 🔡 Lower case     | `toLower()`    | `my name is bond` |
| 🔠 Upper case     | `toUpper()`    | `MY NAME IS BOND` |
| 📰 Title case     | `toTitle()`    | `My Name Is Bond` |
| ✍️ Sentence case  | `toSentence()` | `My name is bond` |
| ⚙️ Dot notation   | `toDot()`      | `my.name.is.bond` |

Features:

* 🔁 [automatic case detection][detection algorithm]
* 🏭 [factory][]
* 🌐 [i18n](#i18n)

[![Packagist Version](https://img.shields.io/packagist/v/jawira/case-converter?style=for-the-badge)](https://packagist.org/packages/jawira/case-converter)
[![Packagist PHP Version Support](https://img.shields.io/packagist/php-v/jawira/case-converter?style=for-the-badge)](https://packagist.org/packages/jawira/case-converter)
[![Packagist Downloads](https://img.shields.io/packagist/dt/jawira/case-converter?style=for-the-badge)](https://packagist.org/packages/jawira/case-converter)
[![Packagist License](https://img.shields.io/packagist/l/jawira/case-converter?style=for-the-badge)](https://packagist.org/packages/jawira/case-converter)  
[![Maintainability](https://api.codeclimate.com/v1/badges/35677f6ce7dac27a5d0c/maintainability)](https://codeclimate.com/github/jawira/case-converter/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/35677f6ce7dac27a5d0c/test_coverage)](https://codeclimate.com/github/jawira/case-converter/test_coverage)

Usage
-----

Input string (i.e. _john-connor_) format is going to be
[detected automatically][detection algorithm]. Here's an example:

```php
use Jawira\CaseConverter\Convert;

$hero = new Convert('john-connor');

echo $hero->toCamel();   // output: johnConnor
```

Of course you can explicitly set the format of input string:

```php
echo $hero->fromKebab()->toSnake();   // output: john_connor
```

You can also use the [provided factory][factory] to instantiate `Convert` class.
A list of [all public methods] is also available.

i18n
----

Fully compatible with non-english alphabets:

```php
// Spanish
$esp = new Convert('DON_RAMÓN_Y_ÑOÑO');
echo $esp->toCamel();   // output: donRamónYÑoño

// Greek
$grc = new Convert('πολύ-Καλό');
echo $grc->toCamel();   // output: πολύΚαλό

// Russian
$rus = new Convert('ОЧЕНЬ_ПРИЯТНО');
echo $rus->toCamel();   // output: оченьПриятно
```

`case-converter` is compatible with _Simple Case-Mapping_ and _Full
Case-Mapping_.
[Learn more about Case-Mapping][Case-Mapping].

Installation
------------

```console
composer require jawira/case-converter
```

Documentation
-------------

<https://jawira.github.io/case-converter/>

Contributing
------------

- If you liked this project, ⭐ star it on GitHub.
  [![GitHub Repo stars](https://img.shields.io/github/stars/jawira/case-converter?style=social)](https://github.com/jawira/case-converter)
- Or follow me on X.
  [![Twitter Follow](https://img.shields.io/twitter/follow/jawira?style=social)](https://twitter.com/jawira)

License
-------

This library is licensed under the [MIT LICENSE].

<!--mkdocs: Do not use relative path for links and images-->

[all public methods]: https://jawira.github.io/case-converter/api.html

[CONTRIBUTING.md]: https://jawira.github.io/case-converter/contributing.html

[Countable interface]: https://php.net/manual/en/class.countable.php

[Case-Mapping]: https://jawira.github.io/case-converter/case-mapping.html

[magic method]: https://www.php.net/manual/en/language.oop5.magic.php#object.tostring

[MIT LICENSE]: https://jawira.github.io/case-converter/license.html

[open an issue]: https://github.com/jawira/case-converter/issues/new

[detection algorithm]: https://jawira.github.io/case-converter/detection-algorithm.html

[factory]: https://jawira.github.io/case-converter/using-the-factory.html

[GitHub]: https://github.com/jawira/case-converter/

***

Packages from jawira
--------------------

<dl>

<dt>
    <a href="https://packagist.org/packages/jawira/emoji-catalog">jawira/emoji-catalog
    <img alt="GitHub stars" src="https://badgen.net/github/stars/jawira/emoji-catalog?icon=github"/></a>
</dt>
<dd>Get access to +3000 emojis as class constants.</dd>

<dt>
    <a href="https://packagist.org/packages/jawira/plantuml-client"> jawira/plantuml-client
    <img alt="GitHub stars" src="https://badgen.net/github/stars/jawira/plantuml-client?icon=github"/></a>
</dt>
<dd>Convert PlantUML diagrams into images (svg, png, ...).</dd>

<dt>
    <a href="https://packagist.org/packages/jawira/doctrine-diagram-bundle">jawira/doctrine-diagram-bundle
    <img alt="GitHub stars" src="https://badgen.net/github/stars/jawira/doctrine-diagram-bundle?icon=github"/></a>
</dt>
<dd>Symfony Bundle to generate database diagrams.</dd>

<dt><a href="https://packagist.org/packages/jawira/">more...</a></dt>
</dl>


================================================
FILE: build.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project name="Case Converter" description="Case Converter class" default="help" phingVersion="3">

  <defaultexcludes default="true"/><!--Initializing default excludes-->
  <defaultexcludes add="**/.idea"/>
  <defaultexcludes add="**/.idea/**"/>

  <target name="help">
    <visualizer format="svg"/>
    <open path="build.svg"/>
  </target>

  <target name="setup" description="Install dependencies" depends="composer:install, cc:get"/>

  <target name="qa" description="Run quality tests"
          depends="php:lint, composer:validate, phpunit:run, behat:run, phpstan:analyse"/>

  <target name="docs:refresh-images" description="Update and regenerate docs images"
          depends="phing:visualize, plantuml:puml-to-png"/>

  <target name="composer:validate" description="Check composer.json syntax">
    <composer command="validate">
      <arg value="--strict"/>
      <arg value="--no-check-lock"/>
    </composer>
  </target>

  <target name="composer:install">
    <composer command="install">
      <arg value="--no-interaction"/>
      <arg value="--profile"/>
      <arg value="--ansi"/>
      <arg value="--prefer-dist"/>
    </composer>
  </target>

  <target name="phpunit:open-coverage" description="Open coverage site" depends="phpunit:run">
    <exec executable="xdg-open">
      <arg file="resources/coverage-html/index.html"/>
    </exec>
  </target>

  <target name="php:lint" description="Check syntax on PHP files">
    <phplint haltonfailure="true">
      <fileset dir="${project.basedir}">
        <include name="**/*.php"/>
        <exclude name="vendor/"/>
      </fileset>
    </phplint>
  </target>

  <target name="behat:run" description="Run behat tests">
    <exec executable="vendor/bin/behat" passthru="true" checkreturn="true">
      <arg value="--colors"/>
      <arg value="--no-interaction"/>
      <arg value="--stop-on-failure"/>
      <arg value="--rerun"/>
      <arg value="--strict"/>
    </exec>
  </target>

  <target name="phpunit:run" description="Run unit tests">
    <mkdir dir="resources/coverage-html/"/>
    <exec executable="vendor/bin/phpunit" passthru="true" checkreturn="true">
      <env key="XDEBUG_MODE" value="coverage"/>
      <arg line="--configuration=config/phpunit.xml"/>
      <arg value="--testdox"/>
    </exec>
  </target>

  <target name="changelog:links" description="Update links in composer.json">
    <composer command="require">
      <arg value="symplify/changelog-linker:^v6"/>
    </composer>
    <exec executable="vendor/bin/changelog-linker">
      <arg value="link"/>
    </exec>
    <composer command="remove">
      <arg value="symplify/changelog-linker"/>
    </composer>
  </target>

  <target name="cc:get" description="Download Code Climate">
    <property name="cc.dir" value="bin"/>
    <property name="cc.filename" value="cc-test-reporter"/>
    <if>
      <not>
        <available file="${cc.dir}/${cc.filename}"/>
      </not>
      <then>
        <mkdir dir="${cc.dir}"/>
        <httpget dir="${cc.dir}" filename="${cc.filename}" followRedirects="true"
                 url="https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64"/>
      </then>
    </if>
    <chmod file="${cc.dir}/${cc.filename}" mode="0775"/>
    <exec executable="${cc.dir}/${cc.filename}" passthru="true" checkreturn="true">
      <arg value="--version"/>
    </exec>
  </target>

  <target name="cc:before-build" description="To run before a build">
    <fail unless="env.CC_TEST_REPORTER_ID" message="you must supply a CC_TEST_REPORTER_ID ENV variable"/>
    <exec executable="bin/cc-test-reporter" passthru="true" checkreturn="true">
      <arg value="before-build"/>
    </exec>
  </target>

  <target name="cc:after-build" description="Handle &amp; upload coverage payload">
    <fail unless="env.CC_TEST_REPORTER_ID" message="you must supply a CC_TEST_REPORTER_ID ENV variable"/>
    <exec executable="bin/cc-test-reporter" passthru="true" checkreturn="true">
      <arg value="after-build"/>
      <arg line="--coverage-input-type clover"/>
    </exec>
  </target>

  <target name="plantuml:puml-to-png" description="Parse PlantUML files to image from docs dir">
    <composer command="require">
      <arg value="jawira/plantuml"/>
    </composer>
    <exec executable="vendor/bin/plantuml" passthru="true" checkreturn="true">
      <arg value="-checkmetadata"/>
      <arg path="docs/**.puml"/>
    </exec>
    <composer command="remove">
      <arg value="jawira/plantuml"/>
    </composer>
  </target>

  <target name="git:tags-listing" description="List all git tags">
    <!-- https://stackoverflow.com/a/34239190/4345061 -->
    <exec executable="git" passthru="true">
      <arg value="log"/>
      <arg line="--graph --all --decorate --oneline --simplify-by-decoration"/>
    </exec>
  </target>

  <target name="phing:visualize" description="Update build.png">
    <visualizer format="puml" destination="docs/images"/>
  </target>

  <target name="docs:serve" description="Generate and open static site" depends="docs:build">
    <parallel threadCount="2">
      <exec executable="mkdocs" passthru="true" checkreturn="true">
        <arg value="serve"/>
      </exec>
      <exec executable="xdg-open" passthru="true" checkreturn="true">
        <!--Please F5 after some seconds-->
        <arg value="http://127.0.0.1:8000/"/>
      </exec>
    </parallel>
  </target>

  <target name="docs:build" description="Builds static site" depends="docs:refresh-images">
    <exec executable="mkdocs" passthru="true" checkreturn="true">
      <arg value="build"/>
    </exec>
  </target>

  <target name="phpstan:analyse" description="Analyse at max level">
    <exec executable="vendor/bin/phpstan" passthru="true" checkreturn="true">
      <arg value="analyse"/>
      <arg line="--level=max"/>
      <arg value="--no-progress"/>
      <arg value="--no-interaction"/>
      <arg value="--ansi"/>
      <arg path="src"/>
    </exec>
  </target>

</project>


================================================
FILE: composer.json
================================================
{
  "name": "jawira/case-converter",
  "type": "library",
  "description": "Convert strings between 13 naming conventions: Snake case, Camel case, Pascal case, Kebab case, Ada case, Train case, Cobol case, Macro case, Upper case, Lower case, Sentence case, Title case and Dot notation.",
  "keywords": [
    "Ada case",
    "Camel case",
    "Cobol case",
    "Dot notation",
    "Kebab case",
    "Lower case",
    "Macro case",
    "Pascal case",
    "Sentence case",
    "Snake case",
    "Title case",
    "Train case",
    "Upper case"
  ],
  "homepage": "https://jawira.github.io/case-converter/",
  "license": "MIT",
  "authors": [
    {
      "name": "Jawira Portugal",
      "email": "dev@tugal.be"
    }
  ],
  "require": {
    "php": ">=7.4",
    "ext-mbstring": "*"
  },
  "require-dev": {
    "behat/behat": "^3.0",
    "phpstan/phpstan": "^v2",
    "phpunit/phpunit": "^9.0"
  },
  "suggest": {
    "pds/skeleton": "PHP Package Development Standards",
    "phing/phing": "PHP Build Tool"
  },
  "config": {
    "preferred-install": "dist",
    "sort-packages": true
  },
  "autoload": {
    "psr-4": {
      "Jawira\\CaseConverter\\": "src/"
    }
  }
}


================================================
FILE: config/behat.yml
================================================
default:
  autoload:
    '': '%paths.base%/../tests/behat/bootstrap/'
  suites:
    default:
      paths:
      - '%paths.base%/../tests/behat/'
      contexts:
      - FeatureContext
  formatters:
    pretty: true


================================================
FILE: config/phpunit.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
         bootstrap="../vendor/autoload.php"
         forceCoversAnnotation="true"
         beStrictAboutCoversAnnotation="true"
         beStrictAboutOutputDuringTests="true"
         beStrictAboutTodoAnnotatedTests="true"
         colors="true"
         stopOnFailure="true"
         stopOnRisky="true"
         stopOnDefect="true"
         stopOnWarning="true"
         stopOnIncomplete="true"
         stopOnSkipped="true"
         stopOnError="true">

  <coverage processUncoveredFiles="true">
    <include>
      <directory suffix=".php">../src</directory>
    </include>
    <report>
      <clover outputFile="../clover.xml"/>
      <html outputDirectory="../resources/coverage-html/"/>
      <text outputFile="php://stdout" showUncoveredFiles="true"/>
    </report>
  </coverage>

  <testsuite name="default">
    <directory>../tests/phpunit</directory>
  </testsuite>

  <logging/>

</phpunit>


================================================
FILE: docs/api.md
================================================
API
===

List of public methods.

`\Jawira\CaseConverter\Convert`
-------------------------------

### String conversion

| Method         | Description                             |
|----------------|-----------------------------------------|
| `toCamel()`    | Return string in _Camel case_ format    |
| `toPascal()`   | Return string in _Pascal case_ format   |
| `toSnake()`    | Return string in _Snake case_ format    |
| `toAda()`      | Return string in _Ada case_ format      |
| `toMacro()`    | Return string in _Macro case_ format    |
| `toKebab()`    | Return string in _Kebab case_ format    |
| `toTrain()`    | Return string in _Train case_ format    |
| `toCobol()`    | Return string in _Cobol case_ format    |
| `toLower()`    | Return string in _Lower case_ format    |
| `toUpper()`    | Return string in _Upper case_ format    |
| `toTitle()`    | Return string in _Title case_ format    |
| `toSentence()` | Return string in _Sentence case_ format |
| `toDot()`      | Return string in _Dot notation_         |

### Explicit case detection

| Method           | Description                                         |
|------------------|-----------------------------------------------------|
| `fromAuto()`     | (default) Auto-detect naming convention             |
| `fromCamel()`    | Split input string using uppercase characters       |
| `fromPascal()`   | Split input string using uppercase characters       |
| `fromSnake()`    | Split input string using `_` (underscore character) |
| `fromAda()`      | Split input string using `_` (underscore character) |
| `fromMacro()`    | Split input string using `_` (underscore character) |
| `fromKebab()`    | Split input string using `-` (dash character)       |
| `fromTrain()`    | Split input string using `-` (dash character)       |
| `fromCobol()`    | Split input string using `-` (dash character)       |
| `fromLower()`    | Split input string using `␣` (space character)      |
| `fromUpper()`    | Split input string using `␣` (space character)      |
| `fromTitle()`    | Split input string using `␣` (space character)      |
| `fromSentence()` | Split input string using `␣` (space character)      |
| `fromDot()`      | Split input string using `.` (dot character)        |

Please note that some methods are equivalent and have the same effect:

- `fromDot()`
- `fromCamel()` ≈ `fromPascal()`
- `fromSnake()` ≈ `fromAda()` ≈ `fromMacro()`
- `fromKebab()` ≈ `fromTrain()` ≈ `fromCobol()`
- `fromLower()` ≈ `fromUpper()` ≈ `fromTitle()` ≈ `fromSentence()`

All these methods exists only for sake of completeness.

### Utility methods

| Method                     | Description                                                                    |
|----------------------------|--------------------------------------------------------------------------------|
| `getSource()`              | Returns original input string                                                  |
| `toArray()`                | Returns array with detected words                                              |
| `forceSimpleCaseMapping()` | Output sting uses [Simple Case-Mapping] even if you are using PHP 7.3 or newer |

`\Jawira\CaseConverter\CaseConverter`
-------------------------------------

### Factory method

| Method      | Description                |
|-------------|----------------------------|
| `convert()` | Creates a `Convert` object |

[Simple Case-Mapping]: ./case-mapping.md



================================================
FILE: docs/case-mapping.md
================================================
Case-Mapping
============

Introduction
------------

_Case-mapping_ or _case conversion_ is performed everytime a character is
changed from _upper case_ to _lower case_, or from _lower case_ to _upper case_.
_Case converter_ performs _case-mapping_ everytime you use it.

There are two kind of case-mapping:

1. _Simple case-mapping_
2. _Full case-mapping_

_Simple case-mapping_ is one-to-one character mapping, for example a single
character "`A`" is replaced with another single character "`a`".

As you can image, _Full case-mapping_ performs one-to-many character
replacements (more precisely one-to-many code-points).
In real world use-cases, it's rare to perform _full case-mapping_, this is
because it only concerns a very small set of characters. For example in german
language, the letter "`ß`" is strictly lowercase and should be mapped to "`SS`"
in uppercase words.

Case-Converter behaviour
------------------------

By default, Case-Converter will perform _full case-mapping_

```php
// Full case-mapping
$ger = new Convert('Straße');
echo $ger->toUpper(); // output: STRASSE
```

If you want to perform _simple case-mapping_ then you have to
call `->forceSimpleCaseMapping()`:

```php
// Simple case-mapping
$ger = new Convert('Straße');
$ger->forceSimpleCaseMapping();
echo $ger->toUpper(); // output: STRAßE
```

As you can see, in _full case-mapping_ string length can change.

Case-Mapping in PHP
-------------------

PHP 7.3 introduced _full case-mapping_, you can have one-to-many character
mapping. In practice this means than you can have different results depending on
your PHP version.

Internally Case-Converter uses _mb_convert_case()_ . This function works in
conjunction with specific constants to tell what action to perform. For example:

```php
mb_convert_case('Foo', MB_CASE_UPPER); // FOO
```

Prior to PHP 7.3, these were the available constants and their use:

| Constant      | Meaning                                     |
|---------------|---------------------------------------------|
| MB_CASE_UPPER | Performs simple upper-case fold conversion. |
| MB_CASE_LOWER | Performs simple lower-case fold conversion. |
| MB_CASE_TITLE | Performs simple title-case fold conversion. |

But from PHP 7.3, new constants were added and their meaning changed:

| Constant             | Meaning                                     |
|----------------------|---------------------------------------------|
| MB_CASE_UPPER        | Performs a full upper-case folding.         |
| MB_CASE_LOWER        | Performs a full lower-case folding.         |
| MB_CASE_TITLE        | Performs a full title-case conversion.      |
| MB_CASE_UPPER_SIMPLE | Performs simple upper-case fold conversion. |
| MB_CASE_LOWER_SIMPLE | Performs simple lower-case fold conversion. |
| MB_CASE_TITLE_SIMPLE | Performs simple title-case fold conversion. |

Locale dependent mapping
------------------------

Some case-mapping are locale dependent. This is the case of Turkish where the
small letter "`i`" should be replaced by a capital letter with a dot "`İ`".
However, according to documentation:

> Only unconditional, language agnostic full case-mapping is performed.

This means that locale dependent mapping are ignored and not performed.

Resources
---------

<dl>
<dt>PHP 7.3 Full Case-Mapping and Case-Folding Support</dt>
<dd><a href="https://www.php.net/manual/en/migration73.new-features.php#migration73.new-features.mbstring.case-mapping-folding">https://www.php.net/manual/en/migration73.new-features.php#migration73.new-features.mbstring.case-mapping-folding</a></dd>
<dt>mb_convert_case()</dt>
<dd><a href="https://www.php.net/manual/en/function.mb-convert-case.php">https://www.php.net/manual/en/function.mb-convert-case.php</a></dd>
<dt>mbstring constant</dt>
<dd><a href="https://www.php.net/manual/en/mbstring.constants.php">https://www.php.net/manual/en/mbstring.constants.php</a></dd>
</dl>


================================================
FILE: docs/detection-algorithm.md
================================================
Detection algorithm
===================

When `\Jawira\CaseConverter\Convert` class is instantiated, the input string is
analyzed to detect the words in it.

This is also the algorithm used by `Convert::fromAuto` method.

![Detection algorithm](images/detection-algorithm.png "Detection algorithm")

1. If input string contains `_` (underscore character), then `_` is used to
   split string.
2. If input string contains `-` (dash character), then `-` is used to split
   string.
3. If input string contains `␣` (space character), then `␣` is used to split
   string.
4. If input string contains `.` (space character), then `.` is used to split
   string.
5. If input string contains uppercase characters only, then the input string is
   considered to be a single word.
6. Finally, uppercase characters are used to split string.


================================================
FILE: docs/dev.md
================================================
Development notes
=================

Phing targets
-------------

[![Phing targets](./images/build.png "Phing targets")](./images/build.png)

- `$ phing setup`: Prepare project for development.
- `$ phing qa`: Run quality tests, use this before every commit.

Documentation
-------------

Documentation is built when a `release` is created.

To install **mkdocs** locally type:

[comment]: <> (https://stackoverflow.com/a/41352413/4345061)

```console
sudo -H pip install mkdocs
```

Using Phing behind a proxy
--------------------------

If you are developing behind a proxy, you have to set the environment
variable `http_proxy`. This variable already is imported in `build.xml`, so you
have nothing to do.

Creating new convention
-----------------------

1. Create new Gluer class.
2. Create new Split class.
3. Update `\Jawira\CaseConverter\Convert::analyse` if needed.
4. Register into `\Jawira\CaseConverter\Convert::handleSplitterMethod`.
5. Register into `\Jawira\CaseConverter\Convert::handleGluerMethod`.
6. Update docblock `\Jawira\CaseConverter\Convert` to register new methods.
7. Update documentation.

Railroad diagram
----------------

- <https://tabatkins.github.io/railroad-diagrams/generator.html>

Class diagrams
--------------

[![Phing targets](./images/uml-case-converter.png "CaseConverter namespace")](./images/uml-case-converter.png)

[![Phing targets](./images/uml-glue.png "Glue namespace")](./images/uml-glue.png)

[![Phing targets](./images/uml-split.png "Split namespace")](./images/uml-split.png)

[git-flow]: https://github.com/petervanderdoes/gitflow-avh

[Keep a changelog]: http://keepachangelog.com/en/1.0.0/

[mkdocs]: https://www.mkdocs.org/#installation

[mkdocs-material]: https://github.com/squidfunk/mkdocs-material

[pds/skeleton]: https://github.com/php-pds/skeleton

[Phive]: https://phar.io/

[Semantic Versioning]: http://semver.org/

[Composer]: https://getcomposer.org/


================================================
FILE: docs/images/build.puml
================================================
@startuml

title
Case Converter
end title

top to bottom direction

skinparam Shadowing false
skinparam ArrowFontColor Black
skinparam ArrowThickness 2
skinparam UseCaseBackgroundColor #FFFECC
skinparam UseCaseBorderColor #333333
skinparam UseCaseBorderThickness 2
skinparam UseCaseFontColor Black


(setup) -[#1A85FF]-> (composer:install) : depend:1
(setup) -[#1A85FF]-> (cc:get) : depend:2
(qa) -[#1A85FF]-> (php:lint) : depend:1
(qa) -[#1A85FF]-> (composer:validate) : depend:2
(qa) -[#1A85FF]-> (phpunit:run) : depend:3
(qa) -[#1A85FF]-> (behat:run) : depend:4
(qa) -[#1A85FF]-> (phpstan:analyse) : depend:5
(qa) -[#1A85FF]-> (psalm:run) : depend:6
(docs:refresh-images) -[#1A85FF]-> (phing:visualize) : depend:1
(docs:refresh-images) -[#1A85FF]-> (plantuml:puml-to-png) : depend:2
(phpunit:open-coverage) -[#1A85FF]-> (phpunit:run) : depend:1
(docs:serve) -[#1A85FF]-> (docs:build) : depend:1
(docs:build) -[#1A85FF]-> (docs:refresh-images) : depend:1
(help)
(setup)
(qa)
(docs:refresh-images)
(composer:validate)
(composer:install)
(phpunit:open-coverage)
(php:lint)
(behat:run)
(phpunit:run)
(changelog:links)
(cc:get)
(cc:before-build)
(cc:after-build)
(plantuml:puml-to-png)
(git:tags-listing)
(phing:visualize)
(docs:serve)
(docs:build)
(psalm:run)
(phpstan:analyse)


@enduml


================================================
FILE: docs/images/detection-algorithm.puml
================================================
@startuml
start
if ($input  contains "**_**") then (yes)
  :Split using "**_**";
elseif ($input contains "**-**") then (yes)
  :Split using "**-**";
elseif ($input contains "**␣**") then (yes)
  :Split using "**␣**";
elseif ($input contains "**.**") then (yes)
  :Split using "**.**";
elseif ($input is in uppercase only) then (yes)
  :$input is a single word;
else (no)
  :Split using capital letters;
endif
stop
@enduml


================================================
FILE: docs/images/number-problem.puml
================================================
@startuml
left to right direction
hide empty description

state "hello-8-world" as state1
state "hello8World" as state2
state "hello8-world" as state3

state1 --> state2: toCamel
state2 --> state3: toKebab
state3 --> state2: toCamel

center footer It's impossible to go back to original string when a number is used as a word
@enduml


================================================
FILE: docs/images/railroad.js
================================================
// https://tabatkins.github.io/railroad-diagrams/generator.html
Diagram(
  Choice(0,
    Sequence(
      Optional('->forceSimpleCaseMapping()', 'skip'),
      Choice(7,
        '->fromAda()',
        '->fromAuto()',
        '->fromCamel()',
        '->fromCobol()',
        '->fromDot()',
        '->fromKebab()',
        '->fromLower()',
        Skip(),
        '->fromMacro()',
        '->fromPascal()',
        '->fromSentence()',
        '->fromSnake()',
        '->fromTitle()',
        '->fromTrain()',
        '->fromUpper()'
      ),
      Choice(7,
        '->toAda()',
        '->toArray()',
        '->toCamel()',
        '->toCobol()',
        '->toDot()',
        '->toKebab()',
        '->toLower()',
        '->toMacro()',
        '->toPascal()',
        '->toSentence()',
        '->toSnake()',
        '->toTitle()',
        '->toTrain()',
        '->toUpper()'
      )
    ),
    '->getSource()'
  )
);


================================================
FILE: docs/images/uml-case-converter.puml
================================================
@startuml
namespace Jawira.CaseConverter  {
	exception CaseConverterException {
	}
	interface CaseConverterInterface << interface >> {
		+convert()
	}
	class CaseConverter << class >> {
		+convert()
	}
	class Convert << class >> {
		#source
		#words
		#forceSimpleCaseMapping
		--
		+__construct()
		+fromAuto()
		#analyse()
		#contains()
		#isUppercaseWord()
		#extractWords()
		+getSource()
		+__call()
		#handleSplitterMethod()
		#createSplitter()
		#handleGluerMethod()
		#createGluer()
		+toArray()
		+forceSimpleCaseMapping()
	}
}
	exception Exception {
	}
Exception <|-- Jawira.CaseConverter.CaseConverterException
Jawira.CaseConverter.CaseConverterInterface <|.. Jawira.CaseConverter.CaseConverter
@enduml



================================================
FILE: docs/images/uml-glue.puml
================================================
@startuml
namespace Jawira.CaseConverter.Glue  {
	class TitleCase << class >> {
		+glue()
	}
	abstract SpaceGluer << abstract >> {
		+DELIMITER
	}
	abstract Gluer << abstract >> {
		+ENCODING
		..
		#words
		#lowerCase
		#upperCase
		#titleCase
		--
		+__construct()
		#setSimpleCaseMappingConstants()
		+<i>glue</i>()
		#glueUsingRules()
		#changeWordsCase()
		#changeFirstWordCase()
	}
	abstract DashGluer << abstract >> {
		+DELIMITER
	}
	class CamelCase << class >> {
		+glue()
	}
	abstract UppercaseGluer << abstract >> {
		+DELIMITER
	}
	class AdaCase << class >> {
		+glue()
	}
	abstract UnderscoreGluer << abstract >> {
		+DELIMITER
	}
	class SnakeCase << class >> {
		+glue()
	}
	class KebabCase << class >> {
		+glue()
	}
	class CobolCase << class >> {
		+glue()
	}
	class DotNotation << class >> {
		+DELIMITER
		--
		+glue()
	}
	class UpperCase << class >> {
		+glue()
	}
	class TrainCase << class >> {
		+glue()
	}
	class SentenceCase << class >> {
		+glue()
	}
	class PascalCase << class >> {
		+glue()
	}
	class MacroCase << class >> {
		+glue()
	}
	class LowerCase << class >> {
		+glue()
	}
}
Jawira.CaseConverter.Glue.SpaceGluer --|> Jawira.CaseConverter.Glue.Gluer
Jawira.CaseConverter.Glue.TitleCase --|> Jawira.CaseConverter.Glue.SpaceGluer
Jawira.CaseConverter.Glue.DashGluer --|> Jawira.CaseConverter.Glue.Gluer
Jawira.CaseConverter.Glue.UppercaseGluer --|> Jawira.CaseConverter.Glue.Gluer
Jawira.CaseConverter.Glue.CamelCase --|> Jawira.CaseConverter.Glue.UppercaseGluer
Jawira.CaseConverter.Glue.UnderscoreGluer --|> Jawira.CaseConverter.Glue.Gluer
Jawira.CaseConverter.Glue.AdaCase --|> Jawira.CaseConverter.Glue.UnderscoreGluer
Jawira.CaseConverter.Glue.SnakeCase --|> Jawira.CaseConverter.Glue.UnderscoreGluer
Jawira.CaseConverter.Glue.KebabCase --|> Jawira.CaseConverter.Glue.DashGluer
Jawira.CaseConverter.Glue.CobolCase --|> Jawira.CaseConverter.Glue.DashGluer
Jawira.CaseConverter.Glue.DotNotation --|> Jawira.CaseConverter.Glue.Gluer
Jawira.CaseConverter.Glue.UpperCase --|> Jawira.CaseConverter.Glue.SpaceGluer
Jawira.CaseConverter.Glue.TrainCase --|> Jawira.CaseConverter.Glue.DashGluer
Jawira.CaseConverter.Glue.SentenceCase --|> Jawira.CaseConverter.Glue.SpaceGluer
Jawira.CaseConverter.Glue.PascalCase --|> Jawira.CaseConverter.Glue.UppercaseGluer
Jawira.CaseConverter.Glue.MacroCase --|> Jawira.CaseConverter.Glue.UnderscoreGluer
Jawira.CaseConverter.Glue.LowerCase --|> Jawira.CaseConverter.Glue.SpaceGluer
@enduml



================================================
FILE: docs/images/uml-split.puml
================================================
@startuml
namespace Jawira.CaseConverter.Split  {
	abstract Splitter << abstract >> {
		#inputString
		--
		+__construct()
		+<i>split</i>()
		#splitUsingPattern()
	}
	class SpaceSplitter << class >> {
		+PATTERN
		--
		+split()
	}
	class DotSplitter << class >> {
		+PATTERN
		--
		+split()
	}
	class UppercaseSplitter << class >> {
		+PATTERN
		--
		+split()
	}
	class UnderscoreSplitter << class >> {
		+PATTERN
		--
		+split()
	}
	class DashSplitter << class >> {
		+PATTERN
		--
		+split()
	}
}
Jawira.CaseConverter.Split.SpaceSplitter --|> Jawira.CaseConverter.Split.Splitter
Jawira.CaseConverter.Split.DotSplitter --|> Jawira.CaseConverter.Split.Splitter
Jawira.CaseConverter.Split.UppercaseSplitter --|> Jawira.CaseConverter.Split.Splitter
Jawira.CaseConverter.Split.UnderscoreSplitter --|> Jawira.CaseConverter.Split.Splitter
Jawira.CaseConverter.Split.DashSplitter --|> Jawira.CaseConverter.Split.Splitter
@enduml



================================================
FILE: docs/index.md
================================================
Case Converter
==============

To use **Case Converter** you have to instantiate `Convert` class, to do so you
can use the `new` keyword or the [CaseConverter factory] class.

The string you want to convert should be passed at instantiation. This cannot be
changed later since `Convert` class is immutable.

```php
$var = new Convert('string-to-convert');
```

Typically, you are going to call `Convert` methods this way:

![Method call](./images/railroad.png)

Basic usage
-----------

Code:

```php
use Jawira\CaseConverter\Convert;

$robot = new Convert('The-Terminator');

echo $robot->toPascal(); // TheTerminator
echo $robot->toCobol();  // THE-TERMINATOR
echo $robot->toSnake();  // the_terminator
```

Explicit case detection
-----------------------

In some edge cases you have to explicitly set the format of input string to have
the desired output:

```php
use Jawira\CaseConverter\Convert;

$agency = new Convert('FBI');

$agency->fromAda();
echo $agency->toCobol();   // FBI
echo $agency->toSnake();   // fbi

$agency->fromCamel();
echo $agency->toCobol();   // F-B-I
echo $agency->toSnake();   // f_b_i

$agency->fromAuto();
echo $agency->toCobol();   // FBI
echo $agency->toSnake();   // fbi
```

Force _Simple Case-Mapping_
---------------------------

You can still use _Simple Case-Mapping_ even if you are using PHP 7.3 or newer:

```php
<?php declare(strict_types=1);

require __DIR__ . '/vendor/autoload.php';

use Jawira\CaseConverter\Convert;

$robot = new Convert('Straße');

$robot->forceSimpleCaseMapping();
echo $robot->toMacro();     // output: STRAßE
```

[Learn more about Case-Mapping][Case-Mapping].

Using the factory
-----------------

[CaseConverter factory] is going to instantiate `Convert` class for you.

In the following code `$this->cc` is an instance of
`\Jawira\CaseConverter\CaseConverter` and implements
`\Jawira\CaseConverter\CaseConverterInterface`. This is useful because the
factory should be instantiated by the _Dependency Injection_ mechanism provided
by your favorite framework.

```php
// Convert string to Pascal case
$this->cc->convert('XML')->toPascal(); // Xml

// Convert string to Snake case
$this->cc->convert('v3.0.2')->toSnake(); // v3_0_2

// Convert string to Camel case
$this->cc->convert('first-name')->toCamel(); // firstName

// Convert from Lower case to Dot case
$this->cc->convert('non-SI units')->fromLower()->toDot(); // non-si.units

// Get detected words
$this->cc->convert('Mario Bros')->toArray(); // ['Mario', 'Bros']

// Retrieve original string
$this->cc->convert('use_the_force')->getSource(); // use_the_force
```

More about [CaseConverter factory].

[Case-Mapping]: ./case-mapping.md

[CaseConverter factory]: ./using-the-factory.md


================================================
FILE: docs/known-issues.md
================================================
Known issues
============

Number is not a word
--------------------

When using `case-converter` you cannot use a number as separator.
In practice this means a number is always identified as a lower case letter.

![Phing targets](./images/number-problem.png "Phing targets")

As shown in the previous example, there is no way to go back to the original input string (i.e. `hello-8-world`), in _
kebab case_ this sting is written as
`hello8-world`.

Other examples (with automatic case detection):

```php
(new Convert('REEL2REAL'))->toDot(); // r.e.e.l2.r.e.a.l
(new Convert('reel2real'))->toDot(); // reel2real
(new Convert('Reel2Real'))->toDot(); // reel2.real
```

I strongly suggest to avoid numbers in strings to be converted.

Mixed conventions
-----------------

It might be evident, but _Case Converter_ cannot handle string with mixed naming conventions.

For example the string `XMLHttpRequest` will result in `x.m.l.http.request` when using _dot notation_:

```php
$xhr = new Convert('XMLHttpRequest');
$xhr->toDot() // x.m.l.http.request
```

The correct way to name this string (for Case Converter) should have been `XmlHttpRequest`.

Another example of mixed conventions:

| ❌ Wrong         | ✅ Good           |
|-----------------|------------------|
| PHP_CodeSniffer | php_code_sniffer |
| PHP_CodeSniffer | PhpCodeSniffer   |
| PHPUnit         | PhpUnit          |
| PHPUnit         | php-unit         |


================================================
FILE: docs/naming-conventions.md
================================================
Naming conventions
==================

Naming conventions are also referred as:

- Naming style
- Case convention

Reference matrix
----------------

|                    | Lower case   | Title case                | Upper case | Sentence case |
|--------------------|--------------|---------------------------|------------|---------------|
| `_` (underscore)   | Snake case   | Ada case                  | Macro case | -             |
| `-` (dash)         | Kebab case   | Train case                | Cobol case | -             |
| `.` (dot)          | Dot notation | -                         | -          | -             |
| `␣` (space)        | Lower case   | Title case                | Upper case | Sentence case |
| ` ` (empty string) | -            | Camel case<br>Pascal case | -          | -             |

Description table (wip)
-----------------

| Convention name | Description                                                 | Usage            | AKA                                           |
|-----------------|-------------------------------------------------------------|------------------|-----------------------------------------------|
| Camel case      |                                                             | PHP method names | Camel caps, Medial capitals, Lower camel case |
| Pascal case     |                                                             | PHP class names  | Upper camel case                              |
| Snake case      | All letters in lower-case separated with a `_` (underscore) | PHP functions    |                                               |
| Ada case        |                                                             |                  |                                               |
| Macro case      |                                                             | PHP constants    |                                               |
| Kebab case      |                                                             |                  |                                               |
| Train case      |                                                             |                  |                                               |
| Cobol case      |                                                             |                  |                                               |
| Dot notation    |                                                             |                  |                                               |
| Lower case      |                                                             |                  |                                               |
| Title case      |                                                             |                  |                                               |
| Upper case      |                                                             |                  |                                               |
| Sentence case   |                                                             |                  |                                               |

Resources
---------

- <https://dev.to/prahladyeri/underscores-camelcasing-and-pascalcasing-the-three-naming-conventions-every-programmer-should-be-aware-of-3aed>
- <https://en.wikipedia.org/wiki/Letter_case>
- <https://en.wikipedia.org/wiki/Naming_convention_(programming)>


================================================
FILE: docs/using-the-factory.md
================================================
Using the factory
=================

Besides `\Jawira\CaseConverter\Convert` you also have at your disposal:

- `\Jawira\CaseConverter\CaseConverter`
- `\Jawira\CaseConverter\CaseConverterInterface`

Instead of using `new Convert();` you can use the convenience method from
`CaseConverter` class.

In concrete, you have to call `\Jawira\CaseConverter\CaseConverter::convert` to
create `Convert` objects.

Here an example:

```php
<?php
namespace App;

use Jawira\CaseConverter\CaseConverterInterface;

class MySuperNameCreator
{
    protected $cc;

    public function __construct(CaseConverterInterface $cc)
    {
        $this->cc = $cc;
    }

    public function variableName(string $slug): string
    {
        // `->convert()` returns a `Convert` object.
        $myConvert = $this->cc->convert($slug);
        return $myConvert->toCamel();
    }

    public function constantName(string $slug): string
    {
        // Of course you can also chain everything.
        return $this->cc->convert($slug)->fromKebab()->toMacro();
    }
}
```

Please note that an interface -`CaseConverterInterface`- is also provided. If
you are using _Symfony_ you can use this interface with [Symfony autowiring][]
to automatically instantiate `CaseConverter`, otherwise if you are working in a
standalone project you should try [php-di project][].

Using `\Jawira\CaseConverter\CaseConverter::convert` is preferred because:

- Usually the `new` operator is considered harmful.
- You can easily mock dependencies when writing tests.
- [It's SOLID]

[It's SOLID]: https://github.com/jawira/case-converter/issues/40

[php-di project]: http://php-di.org/#autowiring

[Symfony autowiring]: https://symfony.com/doc/current/service_container/autowiring.html


================================================
FILE: mkdocs.yml
================================================
site_name: !ENV [SITE_NAME, 'Case Converter']
site_author: 'Jawira Portugal'
site_url: 'https://jawira.github.io/case-converter/'
copyright: 'The MIT License (MIT)'
theme:
  name: 'material'
  highlightjs: true
  titles_only: true
  prev_next_buttons_location: 'both'
  collapse_navigation: false
use_directory_urls: false
strict: true
repo_url: 'https://github.com/jawira/case-converter/'
edit_uri: ''
markdown_extensions:
  - codehilite
extra:
  disqus: case-converter


================================================
FILE: src/CaseConverter.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter;

/**
 * Class CaseConverter
 *
 * Factory class which returns a Convert object.
 *
 * @author  Jawira Portugal <dev@tugal.be>
 */
class CaseConverter implements CaseConverterInterface
{
    /**
     * Returns a Convert object
     *
     * @param string $source Input string to be converted
     *
     * @return \Jawira\CaseConverter\Convert
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function convert(string $source): Convert
    {
        return new Convert($source);
    }
}


================================================
FILE: src/CaseConverterException.php
================================================
<?php

namespace Jawira\CaseConverter;

use RuntimeException;

class CaseConverterException extends RuntimeException
{
}


================================================
FILE: src/CaseConverterInterface.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter;

/**
 * Interface CaseConverterInterface
 *
 * @author  Jawira Portugal <dev@tugal.be>
 */
interface CaseConverterInterface
{
    public function convert(string $source): Convert;
}


================================================
FILE: src/Convert.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter;

use Jawira\CaseConverter\Glue\AdaCase;
use Jawira\CaseConverter\Glue\CamelCase;
use Jawira\CaseConverter\Glue\CobolCase;
use Jawira\CaseConverter\Glue\DashGluer;
use Jawira\CaseConverter\Glue\DotNotation;
use Jawira\CaseConverter\Glue\Gluer;
use Jawira\CaseConverter\Glue\KebabCase;
use Jawira\CaseConverter\Glue\LowerCase;
use Jawira\CaseConverter\Glue\MacroCase;
use Jawira\CaseConverter\Glue\PascalCase;
use Jawira\CaseConverter\Glue\SentenceCase;
use Jawira\CaseConverter\Glue\SnakeCase;
use Jawira\CaseConverter\Glue\SpaceGluer;
use Jawira\CaseConverter\Glue\TitleCase;
use Jawira\CaseConverter\Glue\TrainCase;
use Jawira\CaseConverter\Glue\UnderscoreGluer;
use Jawira\CaseConverter\Glue\UpperCase;
use Jawira\CaseConverter\Split\DashSplitter;
use Jawira\CaseConverter\Split\DotSplitter;
use Jawira\CaseConverter\Split\SpaceSplitter;
use Jawira\CaseConverter\Split\Splitter;
use Jawira\CaseConverter\Split\UnderscoreSplitter;
use Jawira\CaseConverter\Split\UppercaseSplitter;
use function is_subclass_of;
use function preg_match;

/**
 * Convert string between different naming conventions.
 *
 * Handled formats:
 *
 * - Ada case
 * - Camel case
 * - Cobol case
 * - Kebab case
 * - Lower case
 * - Macro case
 * - Pascal case
 * - Sentence case
 * - Snake case
 * - Title case
 * - Train case
 * - Upper case
 *
 * @method self fromAda() Treat input string as _Ada case_
 * @method self fromCamel() Treat input string as _Camel case_
 * @method self fromCobol() Treat input string as _Cobol case_
 * @method self fromDot() Treat input string as _Dot notation_
 * @method self fromKebab() Treat input string as _Kebab case_
 * @method self fromLower() Treat input string as _Lower case_
 * @method self fromMacro() Treat input string as _Macro case_
 * @method self fromPascal() Treat input string as _Pascal case_
 * @method self fromSentence() Treat input string as _Sentence case_
 * @method self fromSnake() Treat input string as _Snake case_
 * @method self fromTitle() Treat input string as _Title case_
 * @method self fromTrain() Treat input string as _Train case_
 * @method self fromUpper() Treat input string as _Upper case_
 *
 * @method string toAda() Return string in _Ada case_ format
 * @method string toCamel() Return string in _Camel case_ format
 * @method string toCobol() Return string in _Cobol case_ format
 * @method string toDot() Return string in _Dot notation_
 * @method string toKebab() Return string in _Kebab case_ format
 * @method string toLower() Return string in _Lower case_ format
 * @method string toMacro() Return string in _Macro case_ format
 * @method string toPascal() Return string in _Pascal case_ format
 * @method string toSentence() Return string in _Sentence case_ format
 * @method string toSnake() Return string in _Snake case_ format
 * @method string toTitle() Return string in _Title case_ format
 * @method string toTrain() Return string in _Train case_ format
 * @method string toUpper() Return string in _Upper case_ format
 *
 * @see     https://softwareengineering.stackexchange.com/questions/322413/bothered-by-an-unknown-letter-case-name
 * @see     http://www.unicode.org/charts/case/
 * @author  Jawira Portugal <dev@tugal.be>
 */
class Convert
{
    /** @var string Input string to convert */
    protected string $source;

    /** @var string[] Words extracted from input string */
    protected array $words;

    protected bool $forceSimpleCaseMapping;

    /**
     * Constructor method
     *
     * @param string $source String to convert
     *
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function __construct(string $source)
    {
        $this->source                 = $source;
        $this->forceSimpleCaseMapping = false;
        $this->fromAuto();
    }

    /**
     * Handle `to*` methods and `from*` methods
     *
     * @param string  $methodName
     * @param mixed[] $arguments
     *
     * @return string|\Jawira\CaseConverter\Convert
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function __call(string $methodName, array $arguments)
    {
        $strStartsWith = static fn(string $haystack, string $needle): bool => 0 === mb_strpos($haystack, $needle);
        if ($strStartsWith($methodName, 'from')) {
            $result = $this->handleSplitterMethod($methodName);
        } elseif ($strStartsWith($methodName, 'to')) {
            $result = $this->handleGluerMethod($methodName);
        } else {
            throw new CaseConverterException("Unknown method: $methodName");
        }

        return $result;
    }

    /**
     * Auto-detect naming convention.
     *
     * This is the default method when you don't call a "from*" method.
     *
     * @param bool $digitsAreLowercase When `true`, digits in input string are considered to be equivalent to a lowercase character. When `false` digits are considered to be uppercase.
     * @return \Jawira\CaseConverter\Convert
     */
    public function fromAuto(bool $digitsAreLowercase = true): self
    {
        $splitter = $this->analyse($this->source, $digitsAreLowercase);
        $this->extractWords($splitter);

        return $this;
    }

    /**
     * Returns original input string
     *
     * @return string Original input string
     */
    public function getSource(): string
    {
        return $this->source;
    }

    /**
     * Detected words extracted from original string.
     *
     * @return string[]
     */
    public function toArray(): array
    {
        return $this->words;
    }

    /**
     * Forces to use Simple Case-Mapping
     *
     * Call this method if you want to maintain the behaviour before PHP 7.3
     *
     * @see https://unicode.org/faq/casemap_charprop.html
     * @return \Jawira\CaseConverter\Convert
     */
    public function forceSimpleCaseMapping(): self
    {
        $this->forceSimpleCaseMapping = true;

        return $this;
    }

    /**
     * Detects word separator of $input string and tells you what strategy you should use.
     *
     * @param string $input              String to be analysed
     * @param bool   $digitsAreLowercase When `true`, digits in input string are considered to be equivalent to a lowercase character. When `false` digits are considered to be uppercase.
     *
     * @return \Jawira\CaseConverter\Split\Splitter
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    protected function analyse(string $input, bool $digitsAreLowercase): Splitter
    {
        $strContains = static fn(string $input, string $needle): bool => is_int(mb_strpos($input, $needle));

        switch (true) {
            case $strContains($input, UnderscoreGluer::DELIMITER):
                $splittingStrategy = new UnderscoreSplitter($input);
                break;
            case $strContains($input, DashGluer::DELIMITER):
                $splittingStrategy = new DashSplitter($input);
                break;
            case $strContains($input, SpaceGluer::DELIMITER):
                $splittingStrategy = new SpaceSplitter($input);
                break;
            case $strContains($input, DotNotation::DELIMITER):
                $splittingStrategy = new DotSplitter($input);
                break;
            case $this->isUppercaseWord($input, $digitsAreLowercase):
                $splittingStrategy = new UnderscoreSplitter($input);
                break;
            default:
                $splittingStrategy = new UppercaseSplitter($input);
                break;
        }

        return $splittingStrategy;
    }

    /**
     * Returns true if $input string is a single word composed only by uppercase characters.
     *
     * ```
     * isUppercaseWord('BRUSSELS'); // true
     * isUppercaseWord('Brussels'); // false
     * ```
     *
     * @see     https://www.regular-expressions.info/unicode.html#category
     *
     * @param string $input String to be tested.
     *
     * @return bool
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    protected function isUppercaseWord(string $input, bool $digitsAreLowercase): bool
    {
        $pattern = $digitsAreLowercase ? '#^\p{Lu}+$#u' : '#^[\p{Lu}\p{Nd}]+$#u';
        $match   = preg_match($pattern, $input);

        if (false === $match) {
            throw new CaseConverterException('Error executing regex'); // @codeCoverageIgnore
        }

        return 1 === $match;
    }

    /**
     * Main function, receives input string and then it stores extracted words into an array.
     *
     * @param \Jawira\CaseConverter\Split\Splitter $splitter
     *
     * @return $this
     */
    protected function extractWords(Splitter $splitter): self
    {
        $this->words = $splitter->split();

        return $this;
    }

    /**
     * Methods to explicitly define naming conventions for input string
     *
     * @param string $methodName
     *
     * @return $this
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    protected function handleSplitterMethod(string $methodName): self
    {
        switch ($methodName) {
            case 'fromCamel':
            case 'fromPascal':
                $splitterName = UppercaseSplitter::class;
                break;
            case 'fromSnake':
            case 'fromAda':
            case 'fromMacro':
                $splitterName = UnderscoreSplitter::class;
                break;
            case 'fromKebab':
            case 'fromTrain':
            case 'fromCobol':
                $splitterName = DashSplitter::class;
                break;
            case 'fromLower':
            case 'fromUpper':
            case 'fromTitle':
            case 'fromSentence':
                $splitterName = SpaceSplitter::class;
                break;
            case 'fromDot':
                $splitterName = DotSplitter::class;
                break;
            default:
                throw new CaseConverterException("Unknown method: $methodName");
        }

        $splitter = $this->createSplitter($splitterName, $this->source);
        $this->extractWords($splitter);

        return $this;
    }

    /**
     * @param string $className Class name in string format
     * @param string $source    Input string to be split
     *
     * @return \Jawira\CaseConverter\Split\Splitter
     */
    protected function createSplitter(string $className, string $source): Splitter
    {
        assert(is_subclass_of($className, Splitter::class));

        return new $className($source);
    }

    /**
     * Handles all methods starting by `to*`
     *
     * @param string $methodName
     *
     * @return string
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    protected function handleGluerMethod(string $methodName): string
    {

        switch ($methodName) {
            case 'toAda':
                $className = AdaCase::class;
                break;
            case 'toCamel':
                $className = CamelCase::class;
                break;
            case 'toCobol':
                $className = CobolCase::class;
                break;
            case 'toKebab':
                $className = KebabCase::class;
                break;
            case 'toLower':
                $className = LowerCase::class;
                break;
            case 'toMacro':
                $className = MacroCase::class;
                break;
            case 'toPascal':
                $className = PascalCase::class;
                break;
            case 'toSentence':
                $className = SentenceCase::class;
                break;
            case 'toSnake':
                $className = SnakeCase::class;
                break;
            case 'toTitle':
                $className = TitleCase::class;
                break;
            case 'toTrain':
                $className = TrainCase::class;
                break;
            case 'toUpper':
                $className = UpperCase::class;
                break;
            case 'toDot':
                $className = DotNotation::class;
                break;
            default:
                throw new CaseConverterException("Unknown method: $methodName");
        }

        $gluer = $this->createGluer($className, $this->words, $this->forceSimpleCaseMapping);

        return $gluer->glue();
    }

    /**
     * @param string   $className              Class name in string format
     * @param string[] $words                  Words to glue
     * @param bool     $forceSimpleCaseMapping Should _Simple Case-Mapping_ be forced?
     *
     * @return \Jawira\CaseConverter\Glue\Gluer
     */
    protected function createGluer(string $className, array $words, bool $forceSimpleCaseMapping): Gluer
    {
        assert(is_subclass_of($className, Gluer::class));

        return new $className($words, $forceSimpleCaseMapping);
    }
}


================================================
FILE: src/Glue/AdaCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

/**
 * Class AdaCase
 *
 * Outputs string in _Ada case_ format: This_Is_Ada_Case
 */
class AdaCase extends UnderscoreGluer
{
    /**
     * Format detected words in _Ada case_
     *
     * @return string
     */
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->titleCase);
    }
}


================================================
FILE: src/Glue/CamelCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

/**
 * Class CamelCase
 *
 * Outputs string in _Camel case_ format: thisIsCamelCase
 */
class CamelCase extends UppercaseGluer
{
    /**
     * Format detected words in _Camel case_
     *
     * @return string
     */
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->titleCase, $this->lowerCase);
    }
}


================================================
FILE: src/Glue/CobolCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

/**
 * Class CobolCase
 *
 * Outputs string in _Cobol case_ format: THIS-IS-COBOL-CASE
 */
class CobolCase extends DashGluer
{
    /**
     * Format detected words in _Cobol case_
     *
     * @return string
     */
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->upperCase);
    }
}


================================================
FILE: src/Glue/DashGluer.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

abstract class DashGluer extends Gluer
{
    /** @internal */
    public const DELIMITER = '-';
}


================================================
FILE: src/Glue/DotNotation.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

/**
 * Class DotNotation
 */
class DotNotation extends Gluer
{
    /** @internal */
    public const DELIMITER = '.';

    /**
     * Format detected words in _dot notation_
     *
     * @return string
     */
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->lowerCase);
    }
}


================================================
FILE: src/Glue/Gluer.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

use function array_map;
use function implode;
use function mb_convert_case;
use const MB_CASE_LOWER;
use const MB_CASE_TITLE;
use const MB_CASE_UPPER;

/**
 * Class Gluer
 *
 * A Gluer subclass allow to export an array of words in a single string
 *
 * @author Jawira Portugal <dev@tugal.be>
 */
abstract class Gluer
{
    /**
     * Encoding to be used by `mb_convert_case()` function.
     *
     * This value should never change.
     */
    protected const ENCODING = 'UTF-8';

    /**
     * @var string[] Words extracted from input string
     */
    protected array $words;

    /**
     * @var int MB_CASE_LOWER or MB_CASE_LOWER_SIMPLE
     */
    protected int $lowerCase;

    /**
     * @var int MB_CASE_UPPER or MB_CASE_UPPER_SIMPLE
     */
    protected int $upperCase;

    /**
     * @var int MB_CASE_TITLE or MB_CASE_TITLE_SIMPLE
     */
    protected int $titleCase;


    /**
     * Gluer constructor.
     *
     * @param string[] $words
     * @param bool     $forceSimpleCaseMapping
     */
    final public function __construct(array $words, bool $forceSimpleCaseMapping)
    {
        $this->words     = $words;
        $this->lowerCase = $forceSimpleCaseMapping ? MB_CASE_LOWER_SIMPLE : MB_CASE_LOWER;
        $this->upperCase = $forceSimpleCaseMapping ? MB_CASE_UPPER_SIMPLE : MB_CASE_UPPER;
        $this->titleCase = $forceSimpleCaseMapping ? MB_CASE_TITLE_SIMPLE : MB_CASE_TITLE;
    }

    /**
     * Creates a string which respects concrete naming convention.
     *
     * @return string
     */
    abstract public function glue(): string;

    /**
     * Implode self::$words array using $glue.
     *
     * @param string   $glue          Character to glue words. Even if is assumed you are using underscore or dash character, this method should be capable to use any character as glue.
     * @param int      $wordsMode     The mode of the conversion. It should be one of `Gluer::$lowerCase`, `Gluer::$upperCase` or  `Gluer::$titleCase`.
     * @param null|int $firstWordMode Sometimes first word requires special treatment. It should be one of `Gluer::$lowerCase`,  `Gluer::$upperCase` or  `Gluer::$titleCase`.
     *
     * @return string Converted words.
     */
    protected function glueUsingRules(string $glue, int $wordsMode, ?int $firstWordMode = null): string
    {
        $convertedWords = $this->changeWordsCase($this->words, $wordsMode);

        if (is_int($firstWordMode)) {
            $convertedWords = $this->changeFirstWordCase($convertedWords, $firstWordMode);
        }

        return implode($glue, $convertedWords);
    }

    /**
     * Changes the case of every $words element
     *
     * @param string[] $words    Words to modify
     * @param int      $caseMode It should be one of `Gluer::$lowerCase`,  `Gluer::$upperCase` or  `Gluer::$titleCase`.
     *
     * @return string[]
     */
    protected function changeWordsCase(array $words, int $caseMode): array
    {
        if (empty($words)) {
            return $words;
        }

        $convertCase = static fn(string $word): string => mb_convert_case($word, $caseMode, self::ENCODING);

        return array_map($convertCase, $words);
    }

    /**
     * Changes the case of first $words element
     *
     * @param string[] $words    Words to modify
     * @param int      $caseMode It should be one of `Gluer::$lowerCase`,  `Gluer::$upperCase` or  `Gluer::$titleCase`.
     *
     * @return string[]
     */
    protected function changeFirstWordCase(array $words, int $caseMode): array
    {
        if (empty($words)) {
            return $words;
        }

        $words[0] = mb_convert_case($words[0], $caseMode, self::ENCODING);

        return $words;
    }

}


================================================
FILE: src/Glue/KebabCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

/**
 * Class KebabCase
 *
 * Outputs string in _Cobol case_ format: this-is-kebab-case
 */
class KebabCase extends DashGluer
{
    /**
     * Format detected words in _Kebab case_
     *
     * @return string
     */
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->lowerCase);
    }
}


================================================
FILE: src/Glue/LowerCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

class LowerCase extends SpaceGluer
{
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->lowerCase);
    }
}


================================================
FILE: src/Glue/MacroCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

class MacroCase extends UnderscoreGluer
{
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->upperCase);
    }
}


================================================
FILE: src/Glue/PascalCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

class PascalCase extends UppercaseGluer
{
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->titleCase);
    }
}


================================================
FILE: src/Glue/SentenceCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

class SentenceCase extends SpaceGluer
{
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->lowerCase, $this->titleCase);
    }
}


================================================
FILE: src/Glue/SnakeCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

class SnakeCase extends UnderscoreGluer
{
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->lowerCase);
    }
}


================================================
FILE: src/Glue/SpaceGluer.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

abstract class SpaceGluer extends Gluer
{
    /** @internal */
    public const DELIMITER = ' ';
}


================================================
FILE: src/Glue/TitleCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

class TitleCase extends SpaceGluer
{
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->titleCase);
    }
}


================================================
FILE: src/Glue/TrainCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

class TrainCase extends DashGluer
{
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->titleCase);
    }
}


================================================
FILE: src/Glue/UnderscoreGluer.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

abstract class UnderscoreGluer extends Gluer
{
    /** @internal */
    public const DELIMITER = '_';
}


================================================
FILE: src/Glue/UpperCase.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

class UpperCase extends SpaceGluer
{
    public function glue(): string
    {
        return $this->glueUsingRules(self::DELIMITER, $this->upperCase);
    }
}


================================================
FILE: src/Glue/UppercaseGluer.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Glue;

abstract class UppercaseGluer extends Gluer
{
    /** @internal */
    public const DELIMITER = '';
}


================================================
FILE: src/Split/DashSplitter.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Split;

use Jawira\CaseConverter\Glue\DashGluer;

class DashSplitter extends Splitter
{
    /** @internal */
    public const PATTERN = '#' . DashGluer::DELIMITER . '+#u';

    /**
     * @return string[]
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function split(): array
    {
        return $this->splitUsingPattern($this->inputString, self::PATTERN);
    }
}


================================================
FILE: src/Split/DotSplitter.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Split;

use Jawira\CaseConverter\Glue\DotNotation;

class DotSplitter extends Splitter
{
    /** @internal */
    public const PATTERN = '#\\' . DotNotation::DELIMITER . '+#u';

    /**
     * @return string[]
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function split(): array
    {
        return $this->splitUsingPattern($this->inputString, self::PATTERN);
    }
}


================================================
FILE: src/Split/SpaceSplitter.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Split;

use Jawira\CaseConverter\Glue\SpaceGluer;

class SpaceSplitter extends Splitter
{
    /** @internal */
    public const PATTERN = '#' . SpaceGluer::DELIMITER . '+#u';

    /**
     * @return string[]
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function split(): array
    {
        return $this->splitUsingPattern($this->inputString, self::PATTERN);
    }
}


================================================
FILE: src/Split/Splitter.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Split;

use Jawira\CaseConverter\CaseConverterException;

/**
 * Class Splitter
 *
 * A Splitter subclass allows to read the words contained in a string
 *
 * @author  Jawira Portugal <dev@tugal.be>
 */
abstract class Splitter
{
    /**
     * @var string Words extracted from input string
     */
    protected string $inputString;

    final public function __construct(string $inputString)
    {
        $this->inputString = $inputString;
    }

    /**
     * Tells how to split a string into valid words.
     *
     * @return string[]
     */
    abstract public function split(): array;

    /**
     * This is a utility method, typically this method is used by to split a string based on pattern.
     *
     * @param string $inputString
     * @param string $pattern
     *
     * @return string[]
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    protected function splitUsingPattern(string $inputString, string $pattern): array
    {
        if (empty($pattern)) {
            throw new CaseConverterException('Pattern must not be empty.'); // @codeCoverageIgnore
        }

        $words = preg_split($pattern, $inputString, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

        if ($words === false) {
            throw new CaseConverterException("Error while processing $this->inputString"); // @codeCoverageIgnore
        }

        return $words;
    }
}


================================================
FILE: src/Split/UnderscoreSplitter.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Split;

use Jawira\CaseConverter\Glue\UnderscoreGluer;

class UnderscoreSplitter extends Splitter
{
    public const PATTERN = '#' . UnderscoreGluer::DELIMITER . '+#u';

    /**
     * @return string[]
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function split(): array
    {
        return $this->splitUsingPattern($this->inputString, self::PATTERN);
    }
}


================================================
FILE: src/Split/UppercaseSplitter.php
================================================
<?php declare(strict_types=1);

namespace Jawira\CaseConverter\Split;

class UppercaseSplitter extends Splitter
{
    // language=PhpRegExp
    public const PATTERN = '#(?=\p{Lu}{1})#u';

    /**
     * Splits $words using Uppercase letters.
     *
     * @see https://www.regular-expressions.info/unicode.html#category
     * @return string[] Words in $input
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function split(): array
    {
        return $this->splitUsingPattern($this->inputString, self::PATTERN);
    }
}


================================================
FILE: tests/behat/bootstrap/FeatureContext.php
================================================
<?php

use Behat\Behat\Context\Context;
use Behat\Behat\Tester\Exception\PendingException;
use Jawira\CaseConverter\Convert;

/**
 * Defines application features from the specific context.
 */
class FeatureContext implements Context
{
    /**
     * @var string|array
     */
    protected $result;

    /**
     * @var \Jawira\CaseConverter\Convert
     */
    protected $instance;

    /**
     * @var int Result of count()
     */
    protected $count;

    /**
     * @Given /^CaseConverter class is instantiated with "([^"]*)"$/
     * @param string $arg1 String to convert
     *
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function caseConverterClassIsInstantiatedWith($arg1)
    {
        $this->instance = new Convert($arg1);
    }

    /**
     * @When I cast object to string
     */
    public function iCastObjectToString()
    {
        $this->result = (string)($this->instance);
    }

    /**
     * @When I call :methodName
     *
     * @param $methodName
     */
    public function iCall($methodName)
    {
        $this->result = ($this->instance)->$methodName();
    }

    /**
     * @Then method should return string :returnString
     *
     * @param string $returnString Expected string
     *
     * @throws \Exception
     */
    public function methodShouldReturnString($returnString)
    {
        if (!is_string($returnString)) {
            throw new Exception('Result is not a string');
        }

        if ($this->result !== $returnString) {
            $message = sprintf('Result "%s" is not equal to expected string "%s"', $this->result, $returnString);
            throw new Exception($message);
        }
    }

    /**
     * @Then method should return array :returnArray
     *
     * @param array $returnArray
     *
     * @throws \Exception
     */
    public function methodShouldReturnArray($returnArray)
    {
        if (!is_array($returnArray)) {
            throw new Exception('Result is not array');
        }

        if ($this->result !== $returnArray) {
            throw new Exception('Result is not the expected array');
        }
    }

    /**
     * Convert string to array.
     *
     * Array format is `[One;Two;Three]`.
     *
     * @Transform /^(\[.*\])$/
     *
     * @see https://behat.readthedocs.io/en/v2.5/guides/2.definitions.html#step-argument-transformations
     *
     * @param string $string The string to convert to array
     *
     * @return array
     */
    public function transformStringToArray($string): array
    {
        $trimmed = trim($string, '[]');
        if ($trimmed === false) {
            $trimmed = '';
        }

        $exploded = explode(';', $trimmed);

        // Filtering since CaseConverter does the same.
        return array_filter($exploded);
    }

    /**
     * @When I use count function
     */
    public function iUseCountFunction()
    {
        $this->count = count($this->instance);
    }

    /**
     * @Then functions should return :expectedCount
     *
     * @param $expectedCount
     *
     * @throws \Exception
     */
    public function functionsShouldReturn($expectedCount)
    {
        if (!is_numeric($expectedCount)) {
            throw new Exception('Count value is not numeric');
        }

        $expectedCount = (int)$expectedCount;

        if ($this->count !== $expectedCount) {
            throw new Exception('Invalid count');
        }
    }
}


================================================
FILE: tests/behat/case-converter.feature
================================================
Feature: Convert Case
  In order to change string case
  Dev should be able to
  change case


  Scenario Outline: Change naming convention from string using explicit methods
    Given CaseConverter class is instantiated with "<input-string>"
    When I call "<method>"
    Then method should return string "<output-string>"

    Examples:
      | method     | input-string         | output-string        |
      | toCamel    |                      |                      |
      | toCamel    | a                    | a                    |
      | toCamel    | NASA                 | nasa                 |
      | toCamel    | Fbi                  | fbi                  |
      | toCamel    | B-C-D                | bCD                  |
      | toCamel    | CamelCase            | camelCase            |
      | toCamel    | dataTransfer         | dataTransfer         |
      | toCamel    | eniac_computer       | eniacComputer        |
      | toCamel    | FIBONACCI_NUMBER     | fibonacciNumber      |
      | toCamel    | v5.3.0               | v530                 |
      | toCamel    | Good_Morning_Vietnam | goodMorningVietnam   |
      | toCamel    | Buenos Días          | buenosDías           |
      | toCamel    | Jag_förstår_inte     | jagFörstårInte       |
      | toCamel    | quicoYÑoño           | quicoYÑoño           |
      | toCamel    | Πολύ-καλό            | πολύΚαλό             |
      | toCamel    | ОЧЕНЬ_ПРИЯТНО        | оченьПриятно         |
      | toCamel    | Ես-հայերեն-չգիտեմ    | եսՀայերենՉգիտեմ      |
      | toPascal   |                      |                      |
      | toPascal   | a                    | A                    |
      | toPascal   | NASA                 | Nasa                 |
      | toPascal   | Fbi                  | Fbi                  |
      | toPascal   | B-C-D                | BCD                  |
      | toPascal   | CamelCase            | CamelCase            |
      | toPascal   | dataTransfer         | DataTransfer         |
      | toPascal   | eniac_computer       | EniacComputer        |
      | toPascal   | FIBONACCI_NUMBER     | FibonacciNumber      |
      | toPascal   | v5.3.0               | V530                 |
      | toPascal   | Good_Morning_Vietnam | GoodMorningVietnam   |
      | toPascal   | Buenos Días          | BuenosDías           |
      | toPascal   | Jag_förstår_inte     | JagFörstårInte       |
      | toPascal   | quicoYÑoño           | QuicoYÑoño           |
      | toPascal   | Πολύ-καλό            | ΠολύΚαλό             |
      | toPascal   | ОЧЕНЬ_ПРИЯТНО        | ОченьПриятно         |
      | toPascal   | Ես-հայերեն-չգիտեմ    | ԵսՀայերենՉգիտեմ      |
      | toSnake    |                      |                      |
      | toSnake    | a                    | a                    |
      | toSnake    | NASA                 | nasa                 |
      | toSnake    | Fbi                  | fbi                  |
      | toSnake    | B-C-D                | b_c_d                |
      | toSnake    | CamelCase            | camel_case           |
      | toSnake    | dataTransfer         | data_transfer        |
      | toSnake    | eniac_computer       | eniac_computer       |
      | toSnake    | FIBONACCI_NUMBER     | fibonacci_number     |
      | toSnake    | v5.3.0               | v5_3_0               |
      | toSnake    | Good_Morning_Vietnam | good_morning_vietnam |
      | toSnake    | Good_Morning_Vietnam | good_morning_vietnam |
      | toSnake    | Buenos Días          | buenos_días          |
      | toSnake    | quicoYÑoño           | quico_y_ñoño         |
      | toSnake    | Πολύ-καλό            | πολύ_καλό            |
      | toSnake    | ОЧЕНЬ_ПРИЯТНО        | очень_приятно        |
      | toSnake    | Ես-հայերեն-չգիտեմ    | ես_հայերեն_չգիտեմ    |
      | toMacro    |                      |                      |
      | toMacro    | a                    | A                    |
      | toMacro    | NASA                 | NASA                 |
      | toMacro    | Fbi                  | FBI                  |
      | toMacro    | B-C-D                | B_C_D                |
      | toMacro    | CamelCase            | CAMEL_CASE           |
      | toMacro    | dataTransfer         | DATA_TRANSFER        |
      | toMacro    | eniac_computer       | ENIAC_COMPUTER       |
      | toMacro    | FIBONACCI_NUMBER     | FIBONACCI_NUMBER     |
      | toMacro    | v5.3.0               | V5_3_0               |
      | toMacro    | Good_Morning_Vietnam | GOOD_MORNING_VIETNAM |
      | toMacro    | Buenos Días          | BUENOS_DÍAS          |
      | toMacro    | Jag_förstår_inte     | JAG_FÖRSTÅR_INTE     |
      | toMacro    | quicoYÑoño           | QUICO_Y_ÑOÑO         |
      | toMacro    | Πολύ-καλό            | ΠΟΛΎ_ΚΑΛΌ            |
      | toMacro    | ОЧЕНЬ_ПРИЯТНО        | ОЧЕНЬ_ПРИЯТНО        |
      | toMacro    | Ես-հայերեն-չգիտեմ    | ԵՍ_ՀԱՅԵՐԵՆ_ՉԳԻՏԵՄ    |
      | toAda      |                      |                      |
      | toAda      | a                    | A                    |
      | toAda      | NASA                 | Nasa                 |
      | toAda      | Fbi                  | Fbi                  |
      | toAda      | B-C-D                | B_C_D                |
      | toAda      | CamelCase            | Camel_Case           |
      | toAda      | dataTransfer         | Data_Transfer        |
      | toAda      | eniac_computer       | Eniac_Computer       |
      | toAda      | FIBONACCI_NUMBER     | Fibonacci_Number     |
      | toAda      | v5.3.0               | V5_3_0               |
      | toAda      | Good_Morning_Vietnam | Good_Morning_Vietnam |
      | toAda      | Buenos Días          | Buenos_Días          |
      | toAda      | Jag_förstår_inte     | Jag_Förstår_Inte     |
      | toAda      | quicoYÑoño           | Quico_Y_Ñoño         |
      | toAda      | Πολύ-καλό            | Πολύ_Καλό            |
      | toAda      | ОЧЕНЬ_ПРИЯТНО        | Очень_Приятно        |
      | toAda      | Ես-հայերեն-չգիտեմ    | Ես_Հայերեն_Չգիտեմ    |
      | toKebab    |                      |                      |
      | toKebab    | a                    | a                    |
      | toKebab    | NASA                 | nasa                 |
      | toKebab    | Fbi                  | fbi                  |
      | toKebab    | B-C-D                | b-c-d                |
      | toKebab    | CamelCase            | camel-case           |
      | toKebab    | dataTransfer         | data-transfer        |
      | toKebab    | eniac_computer       | eniac-computer       |
      | toKebab    | FIBONACCI_NUMBER     | fibonacci-number     |
      | toKebab    | v5.3.0               | v5-3-0               |
      | toKebab    | Good_Morning_Vietnam | good-morning-vietnam |
      | toKebab    | Buenos Días          | buenos-días          |
      | toKebab    | Jag_förstår_inte     | jag-förstår-inte     |
      | toKebab    | quicoYÑoño           | quico-y-ñoño         |
      | toKebab    | Πολύ-καλό            | πολύ-καλό            |
      | toKebab    | ОЧЕНЬ_ПРИЯТНО        | очень-приятно        |
      | toKebab    | Ես-հայերեն-չգիտեմ    | ես-հայերեն-չգիտեմ    |
      | toCobol    |                      |                      |
      | toCobol    | a                    | A                    |
      | toCobol    | NASA                 | NASA                 |
      | toCobol    | Fbi                  | FBI                  |
      | toCobol    | B-C-D                | B-C-D                |
      | toCobol    | CamelCase            | CAMEL-CASE           |
      | toCobol    | dataTransfer         | DATA-TRANSFER        |
      | toCobol    | eniac_computer       | ENIAC-COMPUTER       |
      | toCobol    | FIBONACCI_NUMBER     | FIBONACCI-NUMBER     |
      | toCobol    | v5.3.0               | V5-3-0               |
      | toCobol    | Good_Morning_Vietnam | GOOD-MORNING-VIETNAM |
      | toCobol    | Buenos Días          | BUENOS-DÍAS          |
      | toCobol    | Jag_förstår_inte     | JAG-FÖRSTÅR-INTE     |
      | toCobol    | quicoYÑoño           | QUICO-Y-ÑOÑO         |
      | toCobol    | Πολύ-καλό            | ΠΟΛΎ-ΚΑΛΌ            |
      | toCobol    | ОЧЕНЬ_ПРИЯТНО        | ОЧЕНЬ-ПРИЯТНО        |
      | toCobol    | Ես-հայերեն-չգիտեմ    | ԵՍ-ՀԱՅԵՐԵՆ-ՉԳԻՏԵՄ    |
      | toTrain    |                      |                      |
      | toTrain    | a                    | A                    |
      | toTrain    | NASA                 | Nasa                 |
      | toTrain    | Fbi                  | Fbi                  |
      | toTrain    | B-C-D                | B-C-D                |
      | toTrain    | CamelCase            | Camel-Case           |
      | toTrain    | dataTransfer         | Data-Transfer        |
      | toTrain    | eniac_computer       | Eniac-Computer       |
      | toTrain    | FIBONACCI_NUMBER     | Fibonacci-Number     |
      | toTrain    | v5.3.0               | V5-3-0               |
      | toTrain    | Good_Morning_Vietnam | Good-Morning-Vietnam |
      | toTrain    | Buenos Días          | Buenos-Días          |
      | toTrain    | Jag_förstår_inte     | Jag-Förstår-Inte     |
      | toTrain    | quicoYÑoño           | Quico-Y-Ñoño         |
      | toTrain    | Πολύ-καλό            | Πολύ-Καλό            |
      | toTrain    | ОЧЕНЬ_ПРИЯТНО        | Очень-Приятно        |
      | toTrain    | Ես-հայերեն-չգիտեմ    | Ես-Հայերեն-Չգիտեմ    |
      | toLower    |                      |                      |
      | toLower    | a                    | a                    |
      | toLower    | NASA                 | nasa                 |
      | toLower    | Fbi                  | fbi                  |
      | toLower    | B-C-D                | b c d                |
      | toLower    | CamelCase            | camel case           |
      | toLower    | dataTransfer         | data transfer        |
      | toLower    | eniac_computer       | eniac computer       |
      | toLower    | FIBONACCI_NUMBER     | fibonacci number     |
      | toLower    | v5.3.0               | v5 3 0               |
      | toLower    | Good_Morning_Vietnam | good morning vietnam |
      | toLower    | Buenos Días          | buenos días          |
      | toLower    | Jag_förstår_inte     | jag förstår inte     |
      | toLower    | quicoYÑoño           | quico y ñoño         |
      | toLower    | Πολύ-καλό            | πολύ καλό            |
      | toLower    | ОЧЕНЬ_ПРИЯТНО        | очень приятно        |
      | toLower    | Ես-հայերեն-չգիտեմ    | ես հայերեն չգիտեմ    |
      | toUpper    |                      |                      |
      | toUpper    | a                    | A                    |
      | toUpper    | NASA                 | NASA                 |
      | toUpper    | Fbi                  | FBI                  |
      | toUpper    | B-C-D                | B C D                |
      | toUpper    | CamelCase            | CAMEL CASE           |
      | toUpper    | dataTransfer         | DATA TRANSFER        |
      | toUpper    | eniac_computer       | ENIAC COMPUTER       |
      | toUpper    | v5.3.0               | V5 3 0               |
      | toUpper    | FIBONACCI_NUMBER     | FIBONACCI NUMBER     |
      | toUpper    | Good_Morning_Vietnam | GOOD MORNING VIETNAM |
      | toUpper    | Buenos Días          | BUENOS DÍAS          |
      | toUpper    | Jag_förstår_inte     | JAG FÖRSTÅR INTE     |
      | toUpper    | quicoYÑoño           | QUICO Y ÑOÑO         |
      | toUpper    | Πολύ-καλό            | ΠΟΛΎ ΚΑΛΌ            |
      | toUpper    | ОЧЕНЬ_ПРИЯТНО        | ОЧЕНЬ ПРИЯТНО        |
      | toUpper    | Ես-հայերեն-չգիտեմ    | ԵՍ ՀԱՅԵՐԵՆ ՉԳԻՏԵՄ    |
      | toTitle    |                      |                      |
      | toTitle    | a                    | A                    |
      | toTitle    | NASA                 | Nasa                 |
      | toTitle    | Fbi                  | Fbi                  |
      | toTitle    | B-C-D                | B C D                |
      | toTitle    | CamelCase            | Camel Case           |
      | toTitle    | dataTransfer         | Data Transfer        |
      | toTitle    | eniac_computer       | Eniac Computer       |
      | toTitle    | FIBONACCI_NUMBER     | Fibonacci Number     |
      | toTitle    | v5.3.0               | V5 3 0               |
      | toTitle    | Good_Morning_Vietnam | Good Morning Vietnam |
      | toTitle    | Buenos Días          | Buenos Días          |
      | toTitle    | Jag_förstår_inte     | Jag Förstår Inte     |
      | toTitle    | quicoYÑoño           | Quico Y Ñoño         |
      | toTitle    | Πολύ-καλό            | Πολύ Καλό            |
      | toTitle    | ОЧЕНЬ_ПРИЯТНО        | Очень Приятно        |
      | toTitle    | Ես-հայերեն-չգիտեմ    | Ես Հայերեն Չգիտեմ    |
      | toSentence |                      |                      |
      | toSentence | a                    | A                    |
      | toSentence | NASA                 | Nasa                 |
      | toSentence | Fbi                  | Fbi                  |
      | toSentence | B-C-D                | B c d                |
      | toSentence | CamelCase            | Camel case           |
      | toSentence | dataTransfer         | Data transfer        |
      | toSentence | eniac_computer       | Eniac computer       |
      | toSentence | FIBONACCI_NUMBER     | Fibonacci number     |
      | toSentence | v5.3.0               | V5 3 0               |
      | toSentence | Good_Morning_Vietnam | Good morning vietnam |
      | toSentence | Buenos Días          | Buenos días          |
      | toSentence | Jag_förstår_inte     | Jag förstår inte     |
      | toSentence | quicoYÑoño           | Quico y ñoño         |
      | toSentence | Πολύ-καλό            | Πολύ καλό            |
      | toSentence | ОЧЕНЬ_ПРИЯТНО        | Очень приятно        |
      | toSentence | Ես-հայերեն-չգիտեմ    | Ես հայերեն չգիտեմ    |
      | toDot      |                      |                      |
      | toDot      | a                    | a                    |
      | toDot      | NASA                 | nasa                 |
      | toDot      | Fbi                  | fbi                  |
      | toDot      | B-C-D                | b.c.d                |
      | toDot      | CamelCase            | camel.case           |
      | toDot      | dataTransfer         | data.transfer        |
      | toDot      | eniac_computer       | eniac.computer       |
      | toDot      | FIBONACCI_NUMBER     | fibonacci.number     |
      | toDot      | Good_Morning_Vietnam | good.morning.vietnam |
      | toDot      | Buenos Días          | buenos.días          |
      | toDot      | Jag_förstår_inte     | jag.förstår.inte     |
      | toDot      | quicoYÑoño           | quico.y.ñoño         |
      | toDot      | Πολύ-καλό            | πολύ.καλό            |
      | toDot      | ОЧЕНЬ_ПРИЯТНО        | очень.приятно        |
      | toDot      | Ես-հայերեն-չգիտեմ    | ես.հայերեն.չգիտեմ    |
      | toDot      | XMLHttpRequest       | x.m.l.http.request   |
      | toLower    | IJSJE                 | ijsje                 |
      | toUpper    | ijsje                 | IJSJE                 |


  Scenario Outline: Convert a string to array
    Given CaseConverter class is instantiated with "<input-string>"
    When I call "<method>"
    Then method should return array "<output-string>"

    Examples:
      | method  | input-string    | output-string     |
      | toArray |                 | []                |
      | toArray | a               | [a]               |
      | toArray | HugoPacoLuis    | [Hugo;Paco;Luis]  |
      | toArray | loremIpsum      | [lorem;Ipsum]     |
      | toArray | aBc_DeF_hIj_KlM | [aBc;DeF;hIj;KlM] |
      | toArray | one___two___    | [one;two]         |
      | toArray | Le Népal        | [Le;Népal]        |
      | toArray | red.green.blue  | [red;green;blue]  |


  Scenario Outline: Full case mapping (default behaviour)
    Given CaseConverter class is instantiated with "<input-string>"
    When I call "<method>"
    Then method should return string "<output-string>"

    Examples:
      | method  | input-string | output-string |
      | toUpper | Straße       | STRASSE       |
      | toLower | İstanbul     | i̇stanbul     |
      | toUpper | ʼn            | ʼN            |
      | toUpper | ffl            | FFL           |


  Scenario Outline: Simple case mapping
    Given CaseConverter class is instantiated with "<input-string>"
    When I call "forceSimpleCaseMapping"
    And I call "<method>"
    Then method should return string "<output-string>"

    Examples:
      | method  | input-string | output-string |
      | toUpper | Straße       | STRAßE        |
      | toLower | İstanbul     | istanbul      |
      | toUpper | ʼn            | ʼn             |
      | toUpper | ffl            | ffl             |


  Scenario Outline: Using numbers in input strings
    Given CaseConverter class is instantiated with "<input-string>"
    When I call "<method>"
    Then method should return string "<output-string>"

    Examples:
      | method     | input-string              | output-string          |
      | toCamel    | I-have-99-problems        | iHave99Problems        |
      | toPascal   | The Taking of Pelham 123  | TheTakingOfPelham123   |
      | toSnake    | 3_idiots_2009             | 3_idiots_2009          |
      | toMacro    | fantastic-4               | FANTASTIC_4            |
      | toAda      | the6ThDay                 | The6_Th_Day            |
      | toKebab    | 7samurai                  | 7samurai               |
      | toCobol    | Super8                    | SUPER8                 |
      | toTrain    | 8Mm                       | 8-Mm                   |
      | toLower    | 8MM                       | 8 m m                  |
      | toUpper    | DISTRICT_9                | DISTRICT 9             |
      | toTitle    | session9                  | Session9               |
      | toSentence | 9Songs                    | 9 songs                |
      | toCamel    | STARTER-FOR-10            | starterFor10           |
      | toPascal   | Ocean's 11                | Ocean's11              |
      | toSnake    | 12_angry_men              | 12_angry_men           |
      | toMacro    | Apollo13                  | APOLLO13               |
      | toAda      | Friday-the-13th           | Friday_The_13Th        |
      | toKebab    | 14BLADES                  | 14-b-l-a-d-e-s         |
      | toCobol    | STALAG17-1953             | STALAG17-1953          |
      | toTrain    | 21-JUMP-STREET            | 21-Jump-Street         |
      | toLower    | TheNumber23               | the number23           |
      | toUpper    | The 40-Year-Old Virgin    | THE 40 YEAR OLD VIRGIN |
      | toTitle    | planet_51                 | Planet 51              |
      | toSentence | Passenger 57              | Passenger 57           |
      | toCamel    | 10-10-a-a-10-10           | 1010AA1010             |
      | toPascal   | Hello5My5Name5Is5Bond     | Hello5My5Name5Is5Bond  |
      | toSnake    | 48-HOLA-mundo-6           | 48_hola_mundo_6        |
      | toMacro    | 0-0-0                     | 0_0_0                  |
      | toAda      | Interstate 60             | Interstate_60          |
      | toKebab    | Happy2-see-you            | happy2-see-you         |
      | toCobol    | 123BC456BC789             | 123-B-C456-B-C789      |
      | toTrain    | 21-test-test21-21Test     | 21-Test-Test21-21Test  |
      | toLower    | TheNumber23               | the number23           |
      | toUpper    | 88 Minutes                | 88 MINUTES             |
      | toTitle    | United9                   | United9                |
      | toSentence | 300                       | 300                    |
      | toCamel    | the__0__is_the_best       | the0IsTheBest          |
      | toPascal   | i-do--not--0like--number0 | IDoNot0LikeNumber0     |
      | toSnake    | IDoNot0LikeNumber0        | i_do_not0_like_number0 |
      | toMacro    | you-have-0-money          | YOU_HAVE_0_MONEY       |
      | toDot      | se7en                     | se7en                  |
      | toDot      | Red1Green2Blue3           | red1.green2.blue3      |
      | toDot      | REEL2REAL                 | r.e.e.l2.r.e.a.l       |
      | toDot      | reel2real                 | reel2real              |
      | toDot      | Reel2Real                 | reel2.real             |


  Scenario: Retrieving original string
    Given CaseConverter class is instantiated with "  A commissioned mirror swears.  "
    When I call "getSource"
    Then method should return string "  A commissioned mirror swears.  "


  Scenario Outline: Handling strings with mixed delimiters
    Given CaseConverter class is instantiated with "<input-string>"
    When I call "<from-method>"
    And I call "<to-method>"
    Then method should return string "<output-string>"

    Examples:
      | from-method | to-method | input-string        | output-string         |
      | fromSnake   | toSnake   | C-3PO_and_R2-D2     | c-3po_and_r2-d2       |
      | fromSnake   | toPascal  | C-3PO_and_R2-D2     | C-3PoAndR2-D2         |
      | fromPascal  | toSnake   | C-3PoAndR2-D2       | c-3_po_and_r2-_d2     |
      | fromUpper   | toDot     | non-SI units        | non-si.units          |
      | fromCamel   | toDot     | EstosSon_losActores | estos.son_los.actores |


  Scenario Outline: Manually set input string format (test from* methods)
    Given CaseConverter class is instantiated with "<input-string>"
    When I call "<from-method>"
    And I call "<to-method>"
    Then method should return string "<output-string>"

    Examples:
      | from-method | to-method | input-string | output-string |
      | fromDot     | toSnake   | v5.0.2       | v5_0_2        |


================================================
FILE: tests/phpunit/AdaCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\AdaCase;
use PHPUnit\Framework\TestCase;

/**
 * Class AdaCaseTest
 */
class AdaCaseTest extends TestCase
{
    /**
     * Testing that `glue` method is called and `titleCase` property is used
     *
     * @covers \Jawira\CaseConverter\Glue\AdaCase::glue
     * @throws \ReflectionException
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(AdaCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting proper titleCase property value
        $reflectionObject   = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('titleCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 123);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(AdaCase::DELIMITER, 123)
             ->willReturn('dummy-value-e1bfd');

        /** @var \Jawira\CaseConverter\Glue\AdaCase $mock */
        $returned = $mock->glue();
        $this->assertSame('dummy-value-e1bfd', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/CamelCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\CamelCase;
use PHPUnit\Framework\TestCase;

/**
 * Class CamelCaseTest
 */
class CamelCaseTest extends TestCase
{
    /**
     * Testing that `glue()` method is called and `titleCase` and `lowerCase`
     * properties are being used.
     *
     * @covers \Jawira\CaseConverter\Glue\CamelCase::glue
     * @throws \ReflectionException
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(CamelCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting titleCase and lowerCase properties
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('titleCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 123);
        $lowerCaseProperty = $reflectionObject->getProperty('lowerCase');
        $lowerCaseProperty->setAccessible(true);
        $lowerCaseProperty->setValue($mock, 456);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(CamelCase::DELIMITER, 123, 456)
             ->willReturn('dummy-value-32ea');

        /** @var \Jawira\CaseConverter\Glue\CamelCase $mock */
        $returned = $mock->glue();
        $this->assertSame('dummy-value-32ea', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/CaseConverterTest.php
================================================
<?php

use Jawira\CaseConverter\CaseConverter;
use Jawira\CaseConverter\Convert;
use PHPUnit\Framework\TestCase;

class CaseConverterTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\CaseConverter::convert
     *
     * @covers \Jawira\CaseConverter\Convert::__construct
     * @covers \Jawira\CaseConverter\Convert::analyse
     * @covers \Jawira\CaseConverter\Convert::extractWords
     * @covers \Jawira\CaseConverter\Convert::fromAuto
     * @covers \Jawira\CaseConverter\Convert::getSource
     * @covers \Jawira\CaseConverter\Split\DashSplitter::split
     * @covers \Jawira\CaseConverter\Split\Splitter::__construct
     * @covers \Jawira\CaseConverter\Split\Splitter::splitUsingPattern
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function testConvert()
    {
        $cc = new CaseConverter();

        $convertObject = $cc->convert('hello-world-484');

        $this->assertInstanceOf(Convert::class, $convertObject);
        $this->assertSame('hello-world-484', $convertObject->getSource());
    }
}


================================================
FILE: tests/phpunit/CobolCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\CobolCase;
use PHPUnit\Framework\TestCase;

/**
 * Class CobolCaseTest
 */
class CobolCaseTest extends TestCase
{
    /**
     * Testing that `glue` method is called and `upperCase` property is used.
     *
     * @covers \Jawira\CaseConverter\Glue\CobolCase::glue
     * @throws \ReflectionException
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(CobolCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting `upperCase` property value
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('upperCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 789);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(CobolCase::DELIMITER, 789)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\CobolCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/ConvertTest.php
================================================
<?php

use Jawira\CaseConverter\CaseConverterException;
use Jawira\CaseConverter\Convert;
use Jawira\CaseConverter\Glue\AdaCase;
use Jawira\CaseConverter\Glue\CamelCase;
use Jawira\CaseConverter\Glue\CobolCase;
use Jawira\CaseConverter\Glue\DotNotation;
use Jawira\CaseConverter\Glue\Gluer;
use Jawira\CaseConverter\Glue\KebabCase;
use Jawira\CaseConverter\Glue\LowerCase;
use Jawira\CaseConverter\Glue\MacroCase;
use Jawira\CaseConverter\Glue\PascalCase;
use Jawira\CaseConverter\Glue\SentenceCase;
use Jawira\CaseConverter\Glue\SnakeCase;
use Jawira\CaseConverter\Glue\TitleCase;
use Jawira\CaseConverter\Glue\TrainCase;
use Jawira\CaseConverter\Glue\UpperCase;
use Jawira\CaseConverter\Split\DashSplitter;
use Jawira\CaseConverter\Split\DotSplitter;
use Jawira\CaseConverter\Split\SpaceSplitter;
use Jawira\CaseConverter\Split\Splitter;
use Jawira\CaseConverter\Split\UnderscoreSplitter;
use Jawira\CaseConverter\Split\UppercaseSplitter;
use PHPUnit\Framework\TestCase;

/**
 * Unitary tests for \Jawira\CaseConverter\Convert
 *
 * @see https://jtreminio.com/blog/unit-testing-tutorial-part-i-introduction-to-phpunit/
 */
class ConvertTest extends TestCase
{

    /**
     * @covers       \Jawira\CaseConverter\Convert::isUppercaseWord()
     *
     * @param string $inputString
     * @param bool   $expectedResult
     *
     * @dataProvider isUppercaseWordProvider
     *
     * @throws \ReflectionException
     */
    public function testIsUppercaseWord(string $inputString, bool $digitsAreLowercase, bool $expectedResult)
    {
        // Disabling constructor without stub methods
        $stub = $this->getMockBuilder(Convert::class)
                     ->disableOriginalConstructor()
                     ->setMethods()
                     ->getMock();

        // Removing protected for analyze method
        $reflection = new ReflectionObject($stub);
        $method     = $reflection->getMethod('isUppercaseWord');
        $method->setAccessible(true);

        $output = $method->invoke($stub, $inputString, $digitsAreLowercase);

        $this->assertSame($expectedResult, $output);
    }

    public function isUppercaseWordProvider()
    {
        return [
            ['X', true, true],
            ['YES', true, true],
            ['HELLO', true, true],
            ['', true, false],
            ['x', true, false],
            ['HELLOxWORLD', true, false],
            ['HELLO-WORLD', true, false],
            ['HELLO_WORLD', true, false],
            ['HelloWorld', true, false],
            ['CPU486', true, false],
            ['CPU486', false, true],
            ['IR35', true, false],
            ['IR35', false, true],
            ['ISO8601', true, false],
            ['ISO8601', false, true],
        ];
    }

    /**
     * Testing \Jawira\CaseConverter\Convert::analyse
     *
     * \Jawira\CaseConverter\Convert::analyse should return Convert::SNAKE if $input contains '_'.
     *
     * @covers       \Jawira\CaseConverter\Convert::analyse
     * @covers       \Jawira\CaseConverter\Split\Splitter::__construct
     *
     * @dataProvider analyseProvider
     *
     * @param bool   $isUppercaseWordReturn Return value for `isUppercaseWord()`
     * @param string $expected              Expected result
     * @param string $inputString           Input string
     *
     * @throws \ReflectionException
     */
    public function testAnalyse(bool $isUppercaseWordReturn, string $expected, string $inputString)
    {
        // Disabling constructor with one stub method
        $stub = $this->getMockBuilder(Convert::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['isUppercaseWord'])
                     ->getMock();

        // Configuring expectation
        $stub->expects($this->any())
             ->method('isUppercaseWord')
             ->withAnyParameters()
             ->willReturn($isUppercaseWordReturn);

        // Removing protected for analyze method
        $reflection = new ReflectionObject($stub);
        $method     = $reflection->getMethod('analyse');
        $method->setAccessible(true);

        // Testing
        $output = $method->invoke($stub, $inputString, true);
        $this->assertInstanceOf($expected, $output);
    }

    public function analyseProvider()
    {
        return [
            'Underscore 1' => [false, UnderscoreSplitter::class, 'hola_mundo'],
            'Underscore 2' => [false, UnderscoreSplitter::class, 'HELLO_WORLD'],
            'Underscore 3' => [true, UnderscoreSplitter::class, 'Ñ'],
            'Underscore 4' => [true, UnderscoreSplitter::class, 'HELLO'],
            'Underscore 5' => [false, UnderscoreSplitter::class, '_'],
            'Underscore 6' => [false, UnderscoreSplitter::class, '_____'],
            'Uppercase 1'  => [false, UppercaseSplitter::class, ''],
            'Uppercase 2'  => [false, UppercaseSplitter::class, 'ñ'],
            'Uppercase 3'  => [false, UppercaseSplitter::class, 'one'],
            'Uppercase 4'  => [false, UppercaseSplitter::class, 'helloWorld'],
            'Dash 1'       => [false, DashSplitter::class, 'hello-World'],
            'Dash 2'       => [false, DashSplitter::class, 'my-name-is-bond'],
            'Dash 3'       => [false, DashSplitter::class, '-my-name-is-bond-'],
            'Dash 4'       => [false, DashSplitter::class, '-'],
            'Dash 5'       => [false, DashSplitter::class, '------'],
            'Space 1'      => [false, SpaceSplitter::class, 'Hola mundo'],
            'Space 2'      => [false, SpaceSplitter::class, 'Mi nombre es bond'],
            'Space 3'      => [false, SpaceSplitter::class, 'Formule courte spéciale été'],
            'Space 4'      => [false, SpaceSplitter::class, ' '],
            'Space 5'      => [false, SpaceSplitter::class, '      '],
            'Dot 1'        => [false, DotSplitter::class, 'one.two'],
            'Dot 2'        => [false, DotSplitter::class, '.hello.'],
            'Dot 3'        => [false, DotSplitter::class, '.'],
            'Dot 4'        => [false, DotSplitter::class, '........'],
        ];
    }

    /**
     * Test _converter methods_: _toCamel_, _toSnake_, ...
     *
     * This test do not force the use of _Simple Case-Mapping_ .
     *
     * @dataProvider handleGluerMethodProvider()
     *
     * @covers       \Jawira\CaseConverter\Convert::handleGluerMethod
     *
     * @param string $methodName
     * @param string $className
     *
     * @throws \ReflectionException
     */
    public function testHandleGluerMethod(string $methodName, string $className)
    {
        // Gluer class
        $gluerMock = $this->getMockBuilder($className)
                          ->disableOriginalConstructor()
                          ->setMethods(['glue'])
                          ->getMock();
        $gluerMock->expects($this->once())
                  ->method('glue')
                  ->willReturn('this is a dummy text');

        // Convert class
        $convertMock = $this->getMockBuilder(Convert::class)
                            ->disableOriginalConstructor()
                            ->setMethods(['createGluer'])
                            ->getMock();
        $convertMock->expects($this->once())
                    ->method('createGluer')
                    ->with($className, ['dummy', 'd455b'], false)
                    ->willReturn($gluerMock);

        // Setting detected words
        $reflectionObject = new ReflectionObject($convertMock);
        $wordsProperty    = $reflectionObject->getProperty('words');
        $wordsProperty->setAccessible(true);
        $wordsProperty->setValue($convertMock, ['dummy', 'd455b']);
        // Setting _Simple Case-Mapping_ as false
        $forceProperty = $reflectionObject->getProperty('forceSimpleCaseMapping');
        $forceProperty->setAccessible(true);
        $forceProperty->setValue($convertMock, false);

        // Invoking protected method
        $method = new ReflectionMethod($convertMock, 'handleGluerMethod');
        $method->setAccessible(true);
        $result = $method->invokeArgs($convertMock, [$methodName]);

        $this->assertSame('this is a dummy text', $result);
    }

    /**
     * Test _converter methods_: _toCamel_, _toSnake_, ...
     *
     * This test do not force the use of _Simple Case-Mapping_ .
     *
     * @covers       \Jawira\CaseConverter\Convert::handleGluerMethod
     *
     * @throws \ReflectionException
     */
    public function testHandleGluerMethodWithException()
    {
        // Preparing exception
        $this->expectException(CaseConverterException::class);
        $this->expectExceptionMessage('Unknown method: myDummyMethod');

        // Convert class
        $convertMock = $this->getMockBuilder(Convert::class)
                            ->disableOriginalConstructor()
                            ->setMethods()
                            ->getMock();

        // Invoking protected method
        $method = new ReflectionMethod($convertMock, 'handleGluerMethod');
        $method->setAccessible(true);
        $method->invokeArgs($convertMock, ['myDummyMethod']);
    }

    /**
     * Return and array with the name of all _converter methods_.
     */
    public function handleGluerMethodProvider()
    {
        return [
            'toAda'      => ['toAda', AdaCase::class],
            'toCamel'    => ['toCamel', CamelCase::class],
            'toCobol'    => ['toCobol', CobolCase::class],
            'toKebab'    => ['toKebab', KebabCase::class],
            'toLower'    => ['toLower', LowerCase::class],
            'toMacro'    => ['toMacro', MacroCase::class],
            'toPascal'   => ['toPascal', PascalCase::class],
            'toSentence' => ['toSentence', SentenceCase::class],
            'toSnake'    => ['toSnake', SnakeCase::class],
            'toTitle'    => ['toTitle', TitleCase::class],
            'toTrain'    => ['toTrain', TrainCase::class],
            'toUpper'    => ['toUpper', UpperCase::class],
            'toDot'      => ['toDot', DotNotation::class],
        ];
    }

    /**
     * Returns all valid splitters that can be used by Convert::extractWords()
     *
     * @return array
     */
    public function extractWordsProviders()
    {
        return [
            [SpaceSplitter::class],
            [DashSplitter::class],
            [UnderscoreSplitter::class],
            [UppercaseSplitter::class],
        ];
    }

    /**
     * @covers \Jawira\CaseConverter\Convert::toArray
     *
     * @throws \ReflectionException
     */
    public function testToArray()
    {
        // Preparing Convert mock
        $mock = $this->getMockBuilder(Convert::class)
                     ->disableOriginalConstructor()
                     ->setMethods()
                     ->getMock();

        // Setting value to protected property
        $reflectionObject   = new ReflectionObject($mock);
        $reflectionProperty = $reflectionObject->getProperty('words');
        $reflectionProperty->setAccessible(true);
        $reflectionProperty->setValue($mock, ['dummy', 'array']);

        /** @var \Jawira\CaseConverter\Convert $mock */
        $currentArray = $mock->toArray();

        $this->assertIsArray($currentArray);
        $this->assertEquals(['dummy', 'array'], $currentArray);
    }

    /**
     * @covers       \Jawira\CaseConverter\Convert::createGluer
     * @covers       \Jawira\CaseConverter\Glue\Gluer::__construct
     * @dataProvider createGluerProvider
     *
     * @param string $className
     *
     * @throws \ReflectionException
     */
    public function testCreateGluer(string $className)
    {
        // Preparing Convert mock
        $mock = $this->getMockBuilder(Convert::class)
                     ->disableOriginalConstructor()
                     ->setMethods()
                     ->getMock();

        // Calling protected method
        $reflectionObject = new ReflectionObject($mock);
        $reflectionMethod = $reflectionObject->getMethod('createGluer');
        $reflectionMethod->setAccessible(true);
        $gluerObject = $reflectionMethod->invoke($mock, $className, ['dummy', 'array'], false);

        $this->assertInstanceOf(Gluer::class, $gluerObject);
    }

    public function createGluerProvider()
    {
        return [
            [AdaCase::class],
            [CamelCase::class],
            [CobolCase::class],
            [KebabCase::class],
            [LowerCase::class],
            [MacroCase::class],
            [PascalCase::class],
            [SentenceCase::class],
            [SnakeCase::class],
            [TitleCase::class],
            [TrainCase::class],
            [UpperCase::class],
        ];
    }

    /**
     * @covers \Jawira\CaseConverter\Convert::getSource
     * @throws \ReflectionException
     */
    public function testGetSource()
    {
        // Preparing Convert object
        $convertMock = $this->getMockBuilder(Convert::class)
                            ->disableOriginalConstructor()
                            ->setMethods()
                            ->getMock();

        // Setting detected words
        $reflectionObject = new ReflectionObject($convertMock);
        $sourceProperty   = $reflectionObject->getProperty('source');
        $sourceProperty->setAccessible(true);
        $sourceProperty->setValue($convertMock, 'this is source string');

        /** @var Convert $convertMock */
        $result = $convertMock->getSource();
        $this->assertSame('this is source string', $result);
    }

    /**
     * @throws \ReflectionException
     * @covers \Jawira\CaseConverter\Convert::fromAuto
     */
    public function testFromAuto()
    {
        // Preparing Convert object
        $convertMock = $this->getMockBuilder(Convert::class)
                            ->disableOriginalConstructor()
                            ->setMethods(['analyse', 'extractWords'])
                            ->getMock();

        $strategyMock = $this->getMockBuilder(Splitter::class)
                             ->disableOriginalConstructor()
                             ->getMockForAbstractClass();

        // set 'source' attribute
        $reflectionObject = new ReflectionObject($convertMock);
        $wordsProperty    = $reflectionObject->getProperty('source');
        $wordsProperty->setAccessible(true);
        $wordsProperty->setValue($convertMock, 'dummy-original-string');

        // stub analyse
        $convertMock->expects($this->once())
                    ->method('analyse')
                    ->with('dummy-original-string')
                    ->willReturn($strategyMock);

        // stub extractWords
        $convertMock->expects($this->once())
                    ->method('extractWords')
                    ->with($strategyMock)
                    ->willReturnSelf();

        // Calling protected method
        $reflectionObject = new ReflectionObject($convertMock);
        $reflectionMethod = $reflectionObject->getMethod('fromAuto');
        $reflectionMethod->setAccessible(true);
        $result = $reflectionMethod->invoke($convertMock, 'fromAuto');

        $this->assertInstanceOf(Convert::class, $result);
        $this->assertSame($convertMock, $result);
    }

    /**
     * @covers       \Jawira\CaseConverter\Convert::handleSplitterMethod
     *
     * @param string $methodName
     * @param string $splitterName
     *
     * @dataProvider handleSplitterMethodProvider
     *
     * @throws \ReflectionException
     */
    public function testHandleSplitterMethod(string $methodName = 'fromKebab', string $splitterName = DashSplitter::class, string $sourceString = 'dummy-azer12')
    {
        // Splitter class
        $splitterMock = $this->getMockBuilder($splitterName)
                             ->disableOriginalConstructor()
                             ->getMock();

        // Convert class
        $convertMock = $this->getMockBuilder(Convert::class)
                            ->disableOriginalConstructor()
                            ->setMethods(['createSplitter', 'extractWords'])
                            ->getMock();
        $convertMock->expects($this->once())
                    ->method('createSplitter')
                    ->with($splitterName, $sourceString)
                    ->willReturn($splitterMock);
        $convertMock->expects($this->once())
                    ->method('extractWords')
                    ->with($splitterMock);

        // Add source attribute
        $reflectionObject = new ReflectionObject($convertMock);
        $wordsProperty    = $reflectionObject->getProperty('source');
        $wordsProperty->setAccessible(true);
        $wordsProperty->setValue($convertMock, $sourceString);

        // Invoking protected method
        $method = new ReflectionMethod($convertMock, 'handleSplitterMethod');
        $method->setAccessible(true);
        $result = $method->invoke($convertMock, $methodName);

        $this->assertSame($convertMock, $result);
    }

    public function handleSplitterMethodProvider()
    {
        return [
            ['fromCamel', UppercaseSplitter::class],
            ['fromPascal', UppercaseSplitter::class],
            ['fromSnake', UnderscoreSplitter::class],
            ['fromAda', UnderscoreSplitter::class],
            ['fromMacro', UnderscoreSplitter::class],
            ['fromKebab', DashSplitter::class],
            ['fromTrain', DashSplitter::class],
            ['fromCobol', DashSplitter::class],
            ['fromLower', SpaceSplitter::class],
            ['fromUpper', SpaceSplitter::class],
            ['fromTitle', SpaceSplitter::class],
            ['fromSentence', SpaceSplitter::class],
            ['fromDot', DotSplitter::class],
        ];
    }

    /**
     * @covers \Jawira\CaseConverter\Convert::handleSplitterMethod
     *
     * @throws \ReflectionException
     */
    public function testHandleSplitterMethodWithException()
    {
        // Preparing exception
        $this->expectException(CaseConverterException::class);
        $this->expectExceptionMessage('Unknown method: myDummyMethod');

        // Convert class
        $convertMock = $this->getMockBuilder(Convert::class)
                            ->disableOriginalConstructor()
                            ->setMethods()
                            ->getMock();

        // Invoking protected method
        $method = new ReflectionMethod($convertMock, 'handleSplitterMethod');
        $method->setAccessible(true);
        $method->invokeArgs($convertMock, ['myDummyMethod']);
    }

    /**
     * @covers       \Jawira\CaseConverter\Convert::createSplitter
     * @covers       \Jawira\CaseConverter\Split\Splitter::__construct
     *
     * @dataProvider createSplitterProvider
     *
     * @param string $className
     *
     * @throws \ReflectionException
     */
    public function testCreateSplitter(string $className)
    {
        // Preparing Convert mock
        $mock = $this->getMockBuilder(Convert::class)
                     ->disableOriginalConstructor()
                     ->setMethods()
                     ->getMock();

        // Calling protected method
        $reflectionObject = new ReflectionObject($mock);
        $reflectionMethod = $reflectionObject->getMethod('createSplitter');
        $reflectionMethod->setAccessible(true);
        $splitterObject = $reflectionMethod->invoke($mock, $className, 'dummy-string', false);

        $this->assertInstanceOf($className, $splitterObject);
    }

    public function createSplitterProvider()
    {
        return [
            [DashSplitter::class, 'dummy-string'],
            [SpaceSplitter::class, 'dummy-string'],
            [UnderscoreSplitter::class, 'dummy-string'],
            [UppercaseSplitter::class, 'dummy-string'],
        ];
    }

    /**
     * Testing magic function call
     *
     * @covers       \Jawira\CaseConverter\Convert::__call
     * @dataProvider callProvider
     *
     * @param string $methodName
     * @param array  $arguments
     * @param int    $splitterCount
     * @param int    $gluerCount
     * @param mixed  $handlerResult
     */
    public function testCall(string $methodName, $arguments, int $splitterCount, int $gluerCount, string $handlerResult = '')
    {
        // Preparing Convert mock
        $convertMock = $this->getMockBuilder(Convert::class)
                            ->disableOriginalConstructor()
                            ->setMethods(['handleSplitterMethod', 'handleGluerMethod'])
                            ->getMock();

        $convertMock->expects($this->exactly($splitterCount))
                    ->method('handleSplitterMethod')
                    ->with($methodName)
                    ->willReturnSelf();

        $convertMock->expects($this->exactly($gluerCount))
                    ->method('handleGluerMethod')
                    ->with($methodName)
                    ->willReturn($handlerResult);

        /** @var string|\Jawira\CaseConverter\Split\Splitter $result */
        $result = $convertMock->__call($methodName, $arguments);

        if ($splitterCount) {
            $this->assertInstanceOf(Convert::class, $result);
        }
        if ($gluerCount) {
            $this->assertSame($handlerResult, $result);
        }
    }

    public function callProvider()
    {
        return [
            ['toDummy', [], 0, 1, '46d54fd5'],
            ['toAda', [], 0, 1, 'ed65f'],
            ['toCamel', [], 0, 1, '65hg4jk45'],
            ['toCobol', [], 0, 1, 'a1g94a1'],
            ['toKebab', [], 0, 1, 'd4g2q1df'],
            ['toLower', [], 0, 1, 'ff4f1f'],
            ['toMacro', [], 0, 1, 'fe64df'],
            ['toPascal', [], 0, 1, 'ff1f1f1f'],
            ['toSentence', [], 0, 1, 'de9e1d'],
            ['toSnake', [], 0, 1, 'fdq1nh1jl'],
            ['toTitle', [], 0, 1, 'hjy94'],
            ['toTrain', [], 0, 1, 'g4i4ol'],
            ['toUpper', [], 0, 1, 'gu1ioo1'],
            ['fromDummy', [], 1, 0],
            ['fromAda', [], 1, 0],
            ['fromCamel', [], 1, 0],
            ['fromCobol', [], 1, 0],
            ['fromKebab', [], 1, 0],
            ['fromLower', [], 1, 0],
            ['fromMacro', [], 1, 0],
            ['fromPascal', [], 1, 0],
            ['fromSentence', [], 1, 0],
            ['fromSnake', [], 1, 0],
            ['fromTitle', [], 1, 0],
            ['fromTrain', [], 1, 0],
            ['fromUpper', [], 1, 0],
        ];
    }

    /**
     * @covers       \Jawira\CaseConverter\Convert::__call
     */
    public function testCallException()
    {
        $this->expectException(Jawira\CaseConverter\CaseConverterException::class);
        $this->expectExceptionMessage('Unknown method: invalidMethod');

        // Preparing Convert mock
        $convertMock = $this->getMockBuilder(Convert::class)
                            ->disableOriginalConstructor()
                            ->setMethods()
                            ->getMock();

        /** @var string|\Jawira\CaseConverter\Split\Splitter $result */
        $convertMock->__call('invalidMethod', []);
    }
}


================================================
FILE: tests/phpunit/DashSplitterTest.php
================================================
<?php

use Jawira\CaseConverter\Split\DashSplitter;
use PHPUnit\Framework\TestCase;

class DashSplitterTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Split\DashSplitter::split
     * @throws \ReflectionException
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function testSplit()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(DashSplitter::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['splitUsingPattern'])
                     ->getMock();

        // Setting value to protected property
        $reflectionObject   = new ReflectionObject($mock);
        $reflectionProperty = $reflectionObject->getProperty('inputString');
        $reflectionProperty->setAccessible(true);
        $reflectionProperty->setValue($mock, 'dummyString');

        // Configuring stub
        $mock->expects($this->once())
             ->method('splitUsingPattern')
             ->with('dummyString', '#-+#u')
             ->willReturn(['dummy', 'array']);

        /** @var \Jawira\CaseConverter\Split\DashSplitter $mock */
        $returned = $mock->split();
        $this->assertSame(['dummy', 'array'], $returned);
    }
}


================================================
FILE: tests/phpunit/DotNotationTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\DotNotation;
use PHPUnit\Framework\TestCase;

class DotNotationTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Glue\DotNotation::glue
     * @throws \ReflectionException
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(DotNotation::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting `upperCase` property value
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('lowerCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 789);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(DotNotation::DELIMITER, 789)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\Glue\MacroCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/DotSplitterTest.php
================================================
<?php

use Jawira\CaseConverter\Split\DotSplitter;
use PHPUnit\Framework\TestCase;

class DotSplitterTest extends TestCase
{
    /**
     * @covers       \Jawira\CaseConverter\Split\DotSplitter::split
     *
     * @throws \Jawira\CaseConverter\CaseConverterException
     * @throws \ReflectionException
     */
    public function testSplit()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(DotSplitter::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['splitUsingPattern'])
                     ->getMock();

        // Setting value to protected property
        $reflectionObject   = new ReflectionObject($mock);
        $reflectionProperty = $reflectionObject->getProperty('inputString');
        $reflectionProperty->setAccessible(true);
        $reflectionProperty->setValue($mock, 'dummyString');

        // Configuring stub
        $mock->expects($this->once())
             ->method('splitUsingPattern')
             ->with('dummyString', '#\\.+#u')
             ->willReturn(['dummy', 'array']);

        /** @var \Jawira\CaseConverter\Split\UnderscoreSplitter $mock */
        $returned = $mock->split();
        $this->assertSame(['dummy', 'array'], $returned);
    }
}


================================================
FILE: tests/phpunit/GluerTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\Gluer;
use PHPUnit\Framework\TestCase;

class GluerTest extends TestCase
{
    /**
     * @covers       \Jawira\CaseConverter\Glue\Gluer::glueUsingRules
     * @dataProvider glueUsingRulesProvider
     *
     * @param array  $words
     * @param string $glue
     * @param int    $wordsMode
     * @param        $firstWordMode
     * @param string $expected
     *
     * @throws \ReflectionException
     */
    public function testGlueUsingRules(array $words, string $glue, int $wordsMode, $firstWordMode, string $expected)
    {
        // Disabling constructor without stub methods
        $mock = $this->getMockBuilder(Gluer::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['changeWordsCase', 'changeFirstWordCase'])
                     ->getMockForAbstractClass();

        // Making "words" property accessible and setting a value
        $reflection = new ReflectionObject($mock);
        $property   = $reflection->getProperty('words');
        $property->setAccessible(true);
        $property->setValue($mock, $words);

        // Making public a protected method
        $reflection = new ReflectionObject($mock);
        $method     = $reflection->getMethod('glueUsingRules');
        $method->setAccessible(true);

        // Expectations for changeWordsCase
        $mock->expects($this->once())
             ->method('changeWordsCase')
             ->with($this->equalTo($words, $wordsMode))
             ->will($this->returnValue($words));

        // Only checking that method is called
        $expectation = ($firstWordMode) ? $this->once() : $this->never();
        $mock->expects($expectation)
             ->method('changeFirstWordCase')
             ->with($words, $firstWordMode)
             ->will($this->returnValue($words));

        // Testing
        $output = $method->invoke($mock, $glue, $wordsMode, $firstWordMode);
        $this->assertSame($expected, $output);
    }

    /**
     * @return array
     */
    public function glueUsingRulesProvider()
    {
        return [
            [['fOo', 'bAr'], '§', MB_CASE_LOWER, null, 'fOo§bAr'],
            [['fOo', 'bAr'], '§', MB_CASE_LOWER, MB_CASE_LOWER, 'fOo§bAr'],
            [['fOo', 'bAr'], 'X', MB_CASE_LOWER, null, 'fOoXbAr'],
            [['fOo', 'bAr'], 'X', MB_CASE_LOWER, MB_CASE_LOWER, 'fOoXbAr'],
        ];
    }

    /**
     * @covers       \Jawira\CaseConverter\Glue\Gluer::changeWordsCase
     * @dataProvider changeWordsCaseProvider
     *
     * @param array $words
     * @param int   $caseMode
     * @param array $expected
     *
     * @throws \ReflectionException
     */
    public function testChangeWordsCase($words, $caseMode, $expected)
    {
        // Disabling constructor without stub methods
        $mock = $this->getMockBuilder(Gluer::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMockForAbstractClass();

        // Making public a protected method
        $reflection = new ReflectionObject($mock);
        $method     = $reflection->getMethod('changeWordsCase');
        $method->setAccessible(true);
        $result = $method->invoke($mock, $words, $caseMode);

        $this->assertSame($expected, $result);
    }

    public function changeWordsCaseProvider()
    {
        return [
            [[], MB_CASE_LOWER, []],
            [['hola', 'mundo'], MB_CASE_LOWER, ['hola', 'mundo']],
            [['hola', 'mundo'], MB_CASE_UPPER, ['HOLA', 'MUNDO']],
            [['hola', 'mundo'], MB_CASE_TITLE, ['Hola', 'Mundo']],
            [['HoLa', 'MuNdO'], MB_CASE_LOWER, ['hola', 'mundo']],
            [['HoLa', 'MuNdO'], MB_CASE_UPPER, ['HOLA', 'MUNDO']],
            [['HoLa', 'MuNdO'], MB_CASE_TITLE, ['Hola', 'Mundo']],
        ];
    }

    /**
     * @covers       \Jawira\CaseConverter\Glue\Gluer::changeFirstWordCase
     * @dataProvider changeFirstWordCaseProvider
     *
     * @param array $words
     * @param int   $caseMode
     * @param array $expected
     *
     * @throws \ReflectionException
     */
    public function testChangeFirstWordsCase($words, $caseMode, $expected)
    {
        // Disabling constructor without stub methods
        $mock = $this->getMockBuilder(Gluer::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMockForAbstractClass();

        // Making public a protected method
        $reflection = new ReflectionObject($mock);
        $method     = $reflection->getMethod('changeFirstWordCase');
        $method->setAccessible(true);
        $result = $method->invoke($mock, $words, $caseMode);

        $this->assertSame($expected, $result);
    }

    public function changeFirstWordCaseProvider()
    {
        return [
            [[], MB_CASE_LOWER, []],
            [['hola', 'mundo'], MB_CASE_LOWER, ['hola', 'mundo']],
            [['hola', 'mundo'], MB_CASE_UPPER, ['HOLA', 'mundo']],
            [['hola', 'mundo'], MB_CASE_TITLE, ['Hola', 'mundo']],
            [['HoLa', 'MuNdO'], MB_CASE_LOWER, ['hola', 'MuNdO']],
            [['HoLa', 'MuNdO'], MB_CASE_UPPER, ['HOLA', 'MuNdO']],
            [['HoLa', 'MuNdO'], MB_CASE_TITLE, ['Hola', 'MuNdO']],
        ];
    }

    public function constructorProvider()
    {
        return [
            [['dummy', 'f4s2Q'], false, 0],
            [['dummy', '7e7e7'], true, 1],
        ];
    }
}


================================================
FILE: tests/phpunit/KebabCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\KebabCase;
use PHPUnit\Framework\TestCase;

class KebabCaseTest extends TestCase
{
    /**
     * Testing that `glue` method is called and `lowerCase` property is used.
     *
     * @covers \Jawira\CaseConverter\Glue\KebabCase::glue
     * @throws \ReflectionException
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(KebabCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting lowerCase properties
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('lowerCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 456);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(KebabCase::DELIMITER, 456)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\Glue\KebabCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/LowerCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\LowerCase;
use PHPUnit\Framework\TestCase;

class LowerCaseTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Glue\LowerCase::glue
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(LowerCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting lowerCase properties
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('lowerCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 456);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(LowerCase::DELIMITER, 456)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\Glue\LowerCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/MacroCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\MacroCase;
use PHPUnit\Framework\TestCase;

class MacroCaseTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Glue\MacroCase::glue
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(MacroCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting `upperCase` property value
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('upperCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 789);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(MacroCase::DELIMITER, 789)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\Glue\MacroCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/PascalCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\PascalCase;
use PHPUnit\Framework\TestCase;

class PascalCaseTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Glue\PascalCase::glue
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(PascalCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting titleCase and lowerCase properties
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('titleCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 789);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(PascalCase::DELIMITER, 789)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\Glue\PascalCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/SentenceCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\SentenceCase;
use PHPUnit\Framework\TestCase;

class SentenceCaseTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Glue\SentenceCase::glue
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(SentenceCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting titleCase and lowerCase properties
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('titleCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 123);
        $lowerCaseProperty = $reflectionObject->getProperty('lowerCase');
        $lowerCaseProperty->setAccessible(true);
        $lowerCaseProperty->setValue($mock, 456);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(SentenceCase::DELIMITER, 456, 123)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\Glue\SentenceCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/SnakeCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\SnakeCase;
use PHPUnit\Framework\TestCase;

class SnakeCaseTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Glue\SnakeCase::glue
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(SnakeCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting titleCase and lowerCase properties
        $reflectionObject  = new ReflectionObject($mock);
        $lowerCaseProperty = $reflectionObject->getProperty('lowerCase');
        $lowerCaseProperty->setAccessible(true);
        $lowerCaseProperty->setValue($mock, 456);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(SnakeCase::DELIMITER, 456)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\Glue\SnakeCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/SpaceSplitterTest.php
================================================
<?php

use Jawira\CaseConverter\Split\SpaceSplitter;
use PHPUnit\Framework\TestCase;

class SpaceSplitterTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Split\SpaceSplitter::split
     * @throws \ReflectionException
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function testSplit()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(SpaceSplitter::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['splitUsingPattern'])
                     ->getMock();

        // Setting value to protected property
        $reflectionObject   = new ReflectionObject($mock);
        $reflectionProperty = $reflectionObject->getProperty('inputString');
        $reflectionProperty->setAccessible(true);
        $reflectionProperty->setValue($mock, 'dummyString');

        // Configuring stub
        $mock->expects($this->once())
             ->method('splitUsingPattern')
             ->with('dummyString', '# +#u')
             ->willReturn(['dummy', 'array']);

        /** @var \Jawira\CaseConverter\Split\SpaceSplitter $mock */
        $returned = $mock->split();
        $this->assertSame(['dummy', 'array'], $returned);
    }
}


================================================
FILE: tests/phpunit/SplitterTest.php
================================================
<?php

use Jawira\CaseConverter\Split\SpaceSplitter;
use PHPUnit\Framework\TestCase;

class SplitterTest extends TestCase
{
    /**
     * @covers       \Jawira\CaseConverter\Split\SpaceSplitter::splitUsingPattern
     * @dataProvider splitUsingPatternProvider
     *
     * @param $inputString
     * @param $pattern
     * @param $expected
     *
     * @throws \ReflectionException
     */
    public function testSplitUsingPattern($inputString, $pattern, $expected)
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(SpaceSplitter::class)
                     ->disableOriginalConstructor()
                     ->setMethods([])
                     ->getMock();

        // Invoking protected method
        $method = new ReflectionMethod($mock, 'splitUsingPattern');
        $method->setAccessible(true);
        $result = $method->invokeArgs($mock, [$inputString, $pattern]);

        $this->assertSame($expected, $result);
    }

    public function splitUsingPatternProvider()
    {
        return [
            ['', '#-+#u', []],
            ['hola-mundo', '#-+#u', ['hola', 'mundo']],
            ['-hola-mundo-', '#-+#u', ['hola', 'mundo']],
            ['---hola-----mundo---', '#-+#u', ['hola', 'mundo']],
            ['0', '#-+#u', ['0']],
            ['---0---0---', '#-+#u', ['0', '0']],
            ['---000---000---', '#-+#u', ['000', '000']],
        ];
    }
}


================================================
FILE: tests/phpunit/TitleCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\TitleCase;
use PHPUnit\Framework\TestCase;

class TitleCaseTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Glue\TitleCase::glue
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(TitleCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting titleCase and lowerCase properties
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('titleCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 123);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(TitleCase::DELIMITER, 123)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\TitleCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/TrainCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\TrainCase;
use PHPUnit\Framework\TestCase;

class TrainCaseTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Glue\TrainCase::glue
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(TrainCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting titleCase and lowerCase properties
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('titleCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 123);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(TrainCase::DELIMITER, 123)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\Glue\TrainCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/UnderscoreSplitterTest.php
================================================
<?php

use Jawira\CaseConverter\Split\UnderscoreSplitter;
use PHPUnit\Framework\TestCase;

class UnderscoreSplitterTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Split\UnderscoreSplitter::split
     * @throws \ReflectionException
     * @throws \Jawira\CaseConverter\CaseConverterException
     */
    public function testSplit()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(UnderscoreSplitter::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['splitUsingPattern'])
                     ->getMock();

        // Setting value to protected property
        $reflectionObject   = new ReflectionObject($mock);
        $reflectionProperty = $reflectionObject->getProperty('inputString');
        $reflectionProperty->setAccessible(true);
        $reflectionProperty->setValue($mock, 'dummyString');

        // Configuring stub
        $mock->expects($this->once())
             ->method('splitUsingPattern')
             ->with('dummyString', '#_+#u')
             ->willReturn(['dummy', 'array']);

        /** @var \Jawira\CaseConverter\Split\UnderscoreSplitter $mock */
        $returned = $mock->split();
        $this->assertSame(['dummy', 'array'], $returned);
    }
}


================================================
FILE: tests/phpunit/UpperCaseTest.php
================================================
<?php

use Jawira\CaseConverter\Glue\UpperCase;
use PHPUnit\Framework\TestCase;

class UpperCaseTest extends TestCase
{
    /**
     * @covers \Jawira\CaseConverter\Glue\UpperCase::glue
     */
    public function testGlue()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(UpperCase::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['glueUsingRules'])
                     ->getMock();

        // Setting titleCase and lowerCase properties
        $reflectionObject  = new ReflectionObject($mock);
        $titleCaseProperty = $reflectionObject->getProperty('upperCase');
        $titleCaseProperty->setAccessible(true);
        $titleCaseProperty->setValue($mock, 789);

        // Configuring stub
        $mock->expects($this->once())
             ->method('glueUsingRules')
             ->with(UpperCase::DELIMITER, 789)
             ->willReturn('e1bfd762321e409cee4ac0b6e841963c');

        /** @var \Jawira\CaseConverter\Glue\UpperCase $mock */
        $returned = $mock->glue();
        $this->assertSame('e1bfd762321e409cee4ac0b6e841963c', $returned, 'Returned value is not the expected');
    }
}


================================================
FILE: tests/phpunit/UppercaseSplitterTest.php
================================================
<?php

use Jawira\CaseConverter\Split\UppercaseSplitter;
use PHPUnit\Framework\TestCase;

class UppercaseSplitterTest extends TestCase
{
    /**
     * @covers       \Jawira\CaseConverter\Split\UppercaseSplitter::split
     *
     * @throws \Jawira\CaseConverter\CaseConverterException
     * @throws \ReflectionException
     */
    public function testSplit()
    {
        // Disabling constructor with one stub method
        $mock = $this->getMockBuilder(UppercaseSplitter::class)
                     ->disableOriginalConstructor()
                     ->setMethods(['splitUsingPattern'])
                     ->getMock();

        // Setting value to protected property
        $reflectionObject   = new ReflectionObject($mock);
        $reflectionProperty = $reflectionObject->getProperty('inputString');
        $reflectionProperty->setAccessible(true);
        $reflectionProperty->setValue($mock, 'dummyString');

        // Configuring stub
        $mock->expects($this->once())
             ->method('splitUsingPattern')
             ->with('dummyString', '#(?=\p{Lu}{1})#u')
             ->willReturn(['dummy', 'array']);

        /** @var \Jawira\CaseConverter\Split\UnderscoreSplitter $mock */
        $returned = $mock->split();
        $this->assertSame(['dummy', 'array'], $returned);
    }
}
Download .txt
gitextract_86zso1k9/

├── .codeclimate.yml
├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       ├── docs.yaml
│       └── qa.yaml
├── .gitignore
├── LICENSE.md
├── README.md
├── build.xml
├── composer.json
├── config/
│   ├── behat.yml
│   └── phpunit.xml
├── docs/
│   ├── api.md
│   ├── case-mapping.md
│   ├── detection-algorithm.md
│   ├── dev.md
│   ├── images/
│   │   ├── build.puml
│   │   ├── detection-algorithm.puml
│   │   ├── number-problem.puml
│   │   ├── railroad.js
│   │   ├── uml-case-converter.puml
│   │   ├── uml-glue.puml
│   │   └── uml-split.puml
│   ├── index.md
│   ├── known-issues.md
│   ├── naming-conventions.md
│   └── using-the-factory.md
├── mkdocs.yml
├── src/
│   ├── CaseConverter.php
│   ├── CaseConverterException.php
│   ├── CaseConverterInterface.php
│   ├── Convert.php
│   ├── Glue/
│   │   ├── AdaCase.php
│   │   ├── CamelCase.php
│   │   ├── CobolCase.php
│   │   ├── DashGluer.php
│   │   ├── DotNotation.php
│   │   ├── Gluer.php
│   │   ├── KebabCase.php
│   │   ├── LowerCase.php
│   │   ├── MacroCase.php
│   │   ├── PascalCase.php
│   │   ├── SentenceCase.php
│   │   ├── SnakeCase.php
│   │   ├── SpaceGluer.php
│   │   ├── TitleCase.php
│   │   ├── TrainCase.php
│   │   ├── UnderscoreGluer.php
│   │   ├── UpperCase.php
│   │   └── UppercaseGluer.php
│   └── Split/
│       ├── DashSplitter.php
│       ├── DotSplitter.php
│       ├── SpaceSplitter.php
│       ├── Splitter.php
│       ├── UnderscoreSplitter.php
│       └── UppercaseSplitter.php
└── tests/
    ├── behat/
    │   ├── bootstrap/
    │   │   └── FeatureContext.php
    │   └── case-converter.feature
    └── phpunit/
        ├── AdaCaseTest.php
        ├── CamelCaseTest.php
        ├── CaseConverterTest.php
        ├── CobolCaseTest.php
        ├── ConvertTest.php
        ├── DashSplitterTest.php
        ├── DotNotationTest.php
        ├── DotSplitterTest.php
        ├── GluerTest.php
        ├── KebabCaseTest.php
        ├── LowerCaseTest.php
        ├── MacroCaseTest.php
        ├── PascalCaseTest.php
        ├── SentenceCaseTest.php
        ├── SnakeCaseTest.php
        ├── SpaceSplitterTest.php
        ├── SplitterTest.php
        ├── TitleCaseTest.php
        ├── TrainCaseTest.php
        ├── UnderscoreSplitterTest.php
        ├── UpperCaseTest.php
        └── UppercaseSplitterTest.php
Download .txt
SYMBOL INDEX (149 symbols across 51 files)

FILE: src/CaseConverter.php
  class CaseConverter (line 12) | class CaseConverter implements CaseConverterInterface
    method convert (line 22) | public function convert(string $source): Convert

FILE: src/CaseConverterException.php
  class CaseConverterException (line 7) | class CaseConverterException extends RuntimeException

FILE: src/CaseConverterInterface.php
  type CaseConverterInterface (line 10) | interface CaseConverterInterface
    method convert (line 12) | public function convert(string $source): Convert;

FILE: src/Convert.php
  class Convert (line 81) | class Convert
    method __construct (line 98) | public function __construct(string $source)
    method __call (line 114) | public function __call(string $methodName, array $arguments)
    method fromAuto (line 136) | public function fromAuto(bool $digitsAreLowercase = true): self
    method getSource (line 149) | public function getSource(): string
    method toArray (line 159) | public function toArray(): array
    method forceSimpleCaseMapping (line 172) | public function forceSimpleCaseMapping(): self
    method analyse (line 188) | protected function analyse(string $input, bool $digitsAreLowercase): S...
    method isUppercaseWord (line 231) | protected function isUppercaseWord(string $input, bool $digitsAreLower...
    method extractWords (line 250) | protected function extractWords(Splitter $splitter): self
    method handleSplitterMethod (line 265) | protected function handleSplitterMethod(string $methodName): self
    method createSplitter (line 307) | protected function createSplitter(string $className, string $source): ...
    method handleGluerMethod (line 322) | protected function handleGluerMethod(string $methodName): string
    method createGluer (line 381) | protected function createGluer(string $className, array $words, bool $...

FILE: src/Glue/AdaCase.php
  class AdaCase (line 10) | class AdaCase extends UnderscoreGluer
    method glue (line 17) | public function glue(): string

FILE: src/Glue/CamelCase.php
  class CamelCase (line 10) | class CamelCase extends UppercaseGluer
    method glue (line 17) | public function glue(): string

FILE: src/Glue/CobolCase.php
  class CobolCase (line 10) | class CobolCase extends DashGluer
    method glue (line 17) | public function glue(): string

FILE: src/Glue/DashGluer.php
  class DashGluer (line 5) | abstract class DashGluer extends Gluer

FILE: src/Glue/DotNotation.php
  class DotNotation (line 8) | class DotNotation extends Gluer
    method glue (line 18) | public function glue(): string

FILE: src/Glue/Gluer.php
  class Gluer (line 19) | abstract class Gluer
    method __construct (line 55) | final public function __construct(array $words, bool $forceSimpleCaseM...
    method glue (line 68) | abstract public function glue(): string;
    method glueUsingRules (line 79) | protected function glueUsingRules(string $glue, int $wordsMode, ?int $...
    method changeWordsCase (line 98) | protected function changeWordsCase(array $words, int $caseMode): array
    method changeFirstWordCase (line 117) | protected function changeFirstWordCase(array $words, int $caseMode): a...

FILE: src/Glue/KebabCase.php
  class KebabCase (line 10) | class KebabCase extends DashGluer
    method glue (line 17) | public function glue(): string

FILE: src/Glue/LowerCase.php
  class LowerCase (line 5) | class LowerCase extends SpaceGluer
    method glue (line 7) | public function glue(): string

FILE: src/Glue/MacroCase.php
  class MacroCase (line 5) | class MacroCase extends UnderscoreGluer
    method glue (line 7) | public function glue(): string

FILE: src/Glue/PascalCase.php
  class PascalCase (line 5) | class PascalCase extends UppercaseGluer
    method glue (line 7) | public function glue(): string

FILE: src/Glue/SentenceCase.php
  class SentenceCase (line 5) | class SentenceCase extends SpaceGluer
    method glue (line 7) | public function glue(): string

FILE: src/Glue/SnakeCase.php
  class SnakeCase (line 5) | class SnakeCase extends UnderscoreGluer
    method glue (line 7) | public function glue(): string

FILE: src/Glue/SpaceGluer.php
  class SpaceGluer (line 5) | abstract class SpaceGluer extends Gluer

FILE: src/Glue/TitleCase.php
  class TitleCase (line 5) | class TitleCase extends SpaceGluer
    method glue (line 7) | public function glue(): string

FILE: src/Glue/TrainCase.php
  class TrainCase (line 5) | class TrainCase extends DashGluer
    method glue (line 7) | public function glue(): string

FILE: src/Glue/UnderscoreGluer.php
  class UnderscoreGluer (line 5) | abstract class UnderscoreGluer extends Gluer

FILE: src/Glue/UpperCase.php
  class UpperCase (line 5) | class UpperCase extends SpaceGluer
    method glue (line 7) | public function glue(): string

FILE: src/Glue/UppercaseGluer.php
  class UppercaseGluer (line 5) | abstract class UppercaseGluer extends Gluer

FILE: src/Split/DashSplitter.php
  class DashSplitter (line 7) | class DashSplitter extends Splitter
    method split (line 16) | public function split(): array

FILE: src/Split/DotSplitter.php
  class DotSplitter (line 7) | class DotSplitter extends Splitter
    method split (line 16) | public function split(): array

FILE: src/Split/SpaceSplitter.php
  class SpaceSplitter (line 7) | class SpaceSplitter extends Splitter
    method split (line 16) | public function split(): array

FILE: src/Split/Splitter.php
  class Splitter (line 14) | abstract class Splitter
    method __construct (line 21) | final public function __construct(string $inputString)
    method split (line 31) | abstract public function split(): array;
    method splitUsingPattern (line 42) | protected function splitUsingPattern(string $inputString, string $patt...

FILE: src/Split/UnderscoreSplitter.php
  class UnderscoreSplitter (line 7) | class UnderscoreSplitter extends Splitter
    method split (line 15) | public function split(): array

FILE: src/Split/UppercaseSplitter.php
  class UppercaseSplitter (line 5) | class UppercaseSplitter extends Splitter
    method split (line 17) | public function split(): array

FILE: tests/behat/bootstrap/FeatureContext.php
  class FeatureContext (line 10) | class FeatureContext implements Context
    method caseConverterClassIsInstantiatedWith (line 33) | public function caseConverterClassIsInstantiatedWith($arg1)
    method iCastObjectToString (line 41) | public function iCastObjectToString()
    method iCall (line 51) | public function iCall($methodName)
    method methodShouldReturnString (line 63) | public function methodShouldReturnString($returnString)
    method methodShouldReturnArray (line 82) | public function methodShouldReturnArray($returnArray)
    method transformStringToArray (line 106) | public function transformStringToArray($string): array
    method iUseCountFunction (line 122) | public function iUseCountFunction()
    method functionsShouldReturn (line 134) | public function functionsShouldReturn($expectedCount)

FILE: tests/phpunit/AdaCaseTest.php
  class AdaCaseTest (line 9) | class AdaCaseTest extends TestCase
    method testGlue (line 17) | public function testGlue()

FILE: tests/phpunit/CamelCaseTest.php
  class CamelCaseTest (line 9) | class CamelCaseTest extends TestCase
    method testGlue (line 18) | public function testGlue()

FILE: tests/phpunit/CaseConverterTest.php
  class CaseConverterTest (line 7) | class CaseConverterTest extends TestCase
    method testConvert (line 22) | public function testConvert()

FILE: tests/phpunit/CobolCaseTest.php
  class CobolCaseTest (line 9) | class CobolCaseTest extends TestCase
    method testGlue (line 17) | public function testGlue()

FILE: tests/phpunit/ConvertTest.php
  class ConvertTest (line 32) | class ConvertTest extends TestCase
    method testIsUppercaseWord (line 45) | public function testIsUppercaseWord(string $inputString, bool $digitsA...
    method isUppercaseWordProvider (line 63) | public function isUppercaseWordProvider()
    method testAnalyse (line 100) | public function testAnalyse(bool $isUppercaseWordReturn, string $expec...
    method analyseProvider (line 124) | public function analyseProvider()
    method testHandleGluerMethod (line 168) | public function testHandleGluerMethod(string $methodName, string $clas...
    method testHandleGluerMethodWithException (line 216) | public function testHandleGluerMethodWithException()
    method handleGluerMethodProvider (line 237) | public function handleGluerMethodProvider()
    method extractWordsProviders (line 261) | public function extractWordsProviders()
    method testToArray (line 276) | public function testToArray()
    method testCreateGluer (line 306) | public function testCreateGluer(string $className)
    method createGluerProvider (line 323) | public function createGluerProvider()
    method testGetSource (line 345) | public function testGetSource()
    method testFromAuto (line 368) | public function testFromAuto()
    method testHandleSplitterMethod (line 418) | public function testHandleSplitterMethod(string $methodName = 'fromKeb...
    method handleSplitterMethodProvider (line 452) | public function handleSplitterMethodProvider()
    method testHandleSplitterMethodWithException (line 476) | public function testHandleSplitterMethodWithException()
    method testCreateSplitter (line 504) | public function testCreateSplitter(string $className)
    method createSplitterProvider (line 521) | public function createSplitterProvider()
    method testCall (line 543) | public function testCall(string $methodName, $arguments, int $splitter...
    method callProvider (line 572) | public function callProvider()
    method testCallException (line 607) | public function testCallException()

FILE: tests/phpunit/DashSplitterTest.php
  class DashSplitterTest (line 6) | class DashSplitterTest extends TestCase
    method testSplit (line 13) | public function testSplit()

FILE: tests/phpunit/DotNotationTest.php
  class DotNotationTest (line 6) | class DotNotationTest extends TestCase
    method testGlue (line 12) | public function testGlue()

FILE: tests/phpunit/DotSplitterTest.php
  class DotSplitterTest (line 6) | class DotSplitterTest extends TestCase
    method testSplit (line 14) | public function testSplit()

FILE: tests/phpunit/GluerTest.php
  class GluerTest (line 6) | class GluerTest extends TestCase
    method testGlueUsingRules (line 20) | public function testGlueUsingRules(array $words, string $glue, int $wo...
    method glueUsingRulesProvider (line 60) | public function glueUsingRulesProvider()
    method testChangeWordsCase (line 80) | public function testChangeWordsCase($words, $caseMode, $expected)
    method changeWordsCaseProvider (line 97) | public function changeWordsCaseProvider()
    method testChangeFirstWordsCase (line 120) | public function testChangeFirstWordsCase($words, $caseMode, $expected)
    method changeFirstWordCaseProvider (line 137) | public function changeFirstWordCaseProvider()
    method constructorProvider (line 150) | public function constructorProvider()

FILE: tests/phpunit/KebabCaseTest.php
  class KebabCaseTest (line 6) | class KebabCaseTest extends TestCase
    method testGlue (line 14) | public function testGlue()

FILE: tests/phpunit/LowerCaseTest.php
  class LowerCaseTest (line 6) | class LowerCaseTest extends TestCase
    method testGlue (line 11) | public function testGlue()

FILE: tests/phpunit/MacroCaseTest.php
  class MacroCaseTest (line 6) | class MacroCaseTest extends TestCase
    method testGlue (line 11) | public function testGlue()

FILE: tests/phpunit/PascalCaseTest.php
  class PascalCaseTest (line 6) | class PascalCaseTest extends TestCase
    method testGlue (line 11) | public function testGlue()

FILE: tests/phpunit/SentenceCaseTest.php
  class SentenceCaseTest (line 6) | class SentenceCaseTest extends TestCase
    method testGlue (line 11) | public function testGlue()

FILE: tests/phpunit/SnakeCaseTest.php
  class SnakeCaseTest (line 6) | class SnakeCaseTest extends TestCase
    method testGlue (line 11) | public function testGlue()

FILE: tests/phpunit/SpaceSplitterTest.php
  class SpaceSplitterTest (line 6) | class SpaceSplitterTest extends TestCase
    method testSplit (line 13) | public function testSplit()

FILE: tests/phpunit/SplitterTest.php
  class SplitterTest (line 6) | class SplitterTest extends TestCase
    method testSplitUsingPattern (line 18) | public function testSplitUsingPattern($inputString, $pattern, $expected)
    method splitUsingPatternProvider (line 34) | public function splitUsingPatternProvider()

FILE: tests/phpunit/TitleCaseTest.php
  class TitleCaseTest (line 6) | class TitleCaseTest extends TestCase
    method testGlue (line 11) | public function testGlue()

FILE: tests/phpunit/TrainCaseTest.php
  class TrainCaseTest (line 6) | class TrainCaseTest extends TestCase
    method testGlue (line 11) | public function testGlue()

FILE: tests/phpunit/UnderscoreSplitterTest.php
  class UnderscoreSplitterTest (line 6) | class UnderscoreSplitterTest extends TestCase
    method testSplit (line 13) | public function testSplit()

FILE: tests/phpunit/UpperCaseTest.php
  class UpperCaseTest (line 6) | class UpperCaseTest extends TestCase
    method testGlue (line 11) | public function testGlue()

FILE: tests/phpunit/UppercaseSplitterTest.php
  class UppercaseSplitterTest (line 6) | class UppercaseSplitterTest extends TestCase
    method testSplit (line 14) | public function testSplit()
Condensed preview — 80 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (162K chars).
[
  {
    "path": ".codeclimate.yml",
    "chars": 120,
    "preview": "plugins:\n  sonar-php:\n    enabled: true\n    config:\n      tests_patterns:\n        - tests/**\n  fixme:\n    enabled: true\n"
  },
  {
    "path": ".editorconfig",
    "chars": 706,
    "preview": "root = true\n\n[*]\ncharset = utf-8\ntrim_trailing_whitespace = true\nend_of_line = lf\ninsert_final_newline = true\nindent_sty"
  },
  {
    "path": ".gitattributes",
    "chars": 442,
    "preview": "/.github            export-ignore\n/.idea              export-ignore\n/config             export-ignore\n/docs             "
  },
  {
    "path": ".github/workflows/docs.yaml",
    "chars": 430,
    "preview": "name: Publish documentation\n\non:\n  release:\n    types: [ published ]\n\njobs:\n  build:\n    name: Deploy docs\n    runs-on: "
  },
  {
    "path": ".github/workflows/qa.yaml",
    "chars": 1085,
    "preview": "name: Quality assurance\n\non:\n  pull_request:\n  push:\n    branches:\n      - master\n\njobs:\n  tests:\n    strategy:\n      ma"
  },
  {
    "path": ".gitignore",
    "chars": 363,
    "preview": "/.idea/\n!/.idea/dictionaries/\n/resources/coverage/\n/resources/phpdoc/\n/vendor/\n/bin/\n/composer-setup.php\n/composer.lock\n"
  },
  {
    "path": "LICENSE.md",
    "chars": 1107,
    "preview": "The MIT License (MIT)\n=====================\n\nCopyright © 2015-2022 Jawira Portugal\n\nPermission is hereby granted, free o"
  },
  {
    "path": "README.md",
    "chars": 5360,
    "preview": "Case converter\n==============\n\nUse this library to convert string between:\n\n| Name              | Method         | Outpu"
  },
  {
    "path": "build.xml",
    "chars": 6002,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project name=\"Case Converter\" description=\"Case Converter class\" default=\"help\" "
  },
  {
    "path": "composer.json",
    "chars": 1168,
    "preview": "{\n  \"name\": \"jawira/case-converter\",\n  \"type\": \"library\",\n  \"description\": \"Convert strings between 13 naming convention"
  },
  {
    "path": "config/behat.yml",
    "chars": 215,
    "preview": "default:\n  autoload:\n    '': '%paths.base%/../tests/behat/bootstrap/'\n  suites:\n    default:\n      paths:\n      - '%path"
  },
  {
    "path": "config/phpunit.xml",
    "chars": 1087,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNam"
  },
  {
    "path": "docs/api.md",
    "chars": 3463,
    "preview": "API\n===\n\nList of public methods.\n\n`\\Jawira\\CaseConverter\\Convert`\n-------------------------------\n\n### String conversion"
  },
  {
    "path": "docs/case-mapping.md",
    "chars": 3915,
    "preview": "Case-Mapping\n============\n\nIntroduction\n------------\n\n_Case-mapping_ or _case conversion_ is performed everytime a chara"
  },
  {
    "path": "docs/detection-algorithm.md",
    "chars": 830,
    "preview": "Detection algorithm\n===================\n\nWhen `\\Jawira\\CaseConverter\\Convert` class is instantiated, the input string is"
  },
  {
    "path": "docs/dev.md",
    "chars": 1921,
    "preview": "Development notes\n=================\n\nPhing targets\n-------------\n\n[![Phing targets](./images/build.png \"Phing targets\")]"
  },
  {
    "path": "docs/images/build.puml",
    "chars": 1287,
    "preview": "@startuml\n\ntitle\nCase Converter\nend title\n\ntop to bottom direction\n\nskinparam Shadowing false\nskinparam ArrowFontColor B"
  },
  {
    "path": "docs/images/detection-algorithm.puml",
    "chars": 422,
    "preview": "@startuml\nstart\nif ($input  contains \"**_**\") then (yes)\n  :Split using \"**_**\";\nelseif ($input contains \"**-**\") then ("
  },
  {
    "path": "docs/images/number-problem.puml",
    "chars": 334,
    "preview": "@startuml\nleft to right direction\nhide empty description\n\nstate \"hello-8-world\" as state1\nstate \"hello8World\" as state2\n"
  },
  {
    "path": "docs/images/railroad.js",
    "chars": 921,
    "preview": "// https://tabatkins.github.io/railroad-diagrams/generator.html\nDiagram(\n  Choice(0,\n    Sequence(\n      Optional('->for"
  },
  {
    "path": "docs/images/uml-case-converter.puml",
    "chars": 715,
    "preview": "@startuml\nnamespace Jawira.CaseConverter  {\n\texception CaseConverterException {\n\t}\n\tinterface CaseConverterInterface << "
  },
  {
    "path": "docs/images/uml-glue.puml",
    "chars": 2456,
    "preview": "@startuml\nnamespace Jawira.CaseConverter.Glue  {\n\tclass TitleCase << class >> {\n\t\t+glue()\n\t}\n\tabstract SpaceGluer << abs"
  },
  {
    "path": "docs/images/uml-split.puml",
    "chars": 925,
    "preview": "@startuml\nnamespace Jawira.CaseConverter.Split  {\n\tabstract Splitter << abstract >> {\n\t\t#inputString\n\t\t--\n\t\t+__construct"
  },
  {
    "path": "docs/index.md",
    "chars": 2718,
    "preview": "Case Converter\n==============\n\nTo use **Case Converter** you have to instantiate `Convert` class, to do so you\ncan use t"
  },
  {
    "path": "docs/known-issues.md",
    "chars": 1422,
    "preview": "Known issues\n============\n\nNumber is not a word\n--------------------\n\nWhen using `case-converter` you cannot use a numbe"
  },
  {
    "path": "docs/naming-conventions.md",
    "chars": 3370,
    "preview": "Naming conventions\n==================\n\nNaming conventions are also referred as:\n\n- Naming style\n- Case convention\n\nRefer"
  },
  {
    "path": "docs/using-the-factory.md",
    "chars": 1740,
    "preview": "Using the factory\n=================\n\nBesides `\\Jawira\\CaseConverter\\Convert` you also have at your disposal:\n\n- `\\Jawira"
  },
  {
    "path": "mkdocs.yml",
    "chars": 471,
    "preview": "site_name: !ENV [SITE_NAME, 'Case Converter']\nsite_author: 'Jawira Portugal'\nsite_url: 'https://jawira.github.io/case-co"
  },
  {
    "path": "src/CaseConverter.php",
    "chars": 579,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter;\n\n/**\n * Class CaseConverter\n *\n * Factory class which re"
  },
  {
    "path": "src/CaseConverterException.php",
    "chars": 121,
    "preview": "<?php\n\nnamespace Jawira\\CaseConverter;\n\nuse RuntimeException;\n\nclass CaseConverterException extends RuntimeException\n{\n}"
  },
  {
    "path": "src/CaseConverterInterface.php",
    "chars": 246,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter;\n\n/**\n * Interface CaseConverterInterface\n *\n * @author  "
  },
  {
    "path": "src/Convert.php",
    "chars": 12924,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter;\n\nuse Jawira\\CaseConverter\\Glue\\AdaCase;\nuse Jawira\\CaseC"
  },
  {
    "path": "src/Glue/AdaCase.php",
    "chars": 405,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\n/**\n * Class AdaCase\n *\n * Outputs string in _Ada "
  },
  {
    "path": "src/Glue/CamelCase.php",
    "chars": 429,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\n/**\n * Class CamelCase\n *\n * Outputs string in _Ca"
  },
  {
    "path": "src/Glue/CobolCase.php",
    "chars": 409,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\n/**\n * Class CobolCase\n *\n * Outputs string in _Co"
  },
  {
    "path": "src/Glue/DashGluer.php",
    "chars": 168,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nabstract class DashGluer extends Gluer\n{\n    /** @"
  },
  {
    "path": "src/Glue/DotNotation.php",
    "chars": 403,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\n/**\n * Class DotNotation\n */\nclass DotNotation ext"
  },
  {
    "path": "src/Glue/Gluer.php",
    "chars": 3768,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nuse function array_map;\nuse function implode;\nuse "
  },
  {
    "path": "src/Glue/KebabCase.php",
    "chars": 409,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\n/**\n * Class KebabCase\n *\n * Outputs string in _Co"
  },
  {
    "path": "src/Glue/LowerCase.php",
    "chars": 229,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nclass LowerCase extends SpaceGluer\n{\n    public fu"
  },
  {
    "path": "src/Glue/MacroCase.php",
    "chars": 234,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nclass MacroCase extends UnderscoreGluer\n{\n    publ"
  },
  {
    "path": "src/Glue/PascalCase.php",
    "chars": 234,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nclass PascalCase extends UppercaseGluer\n{\n    publ"
  },
  {
    "path": "src/Glue/SentenceCase.php",
    "chars": 250,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nclass SentenceCase extends SpaceGluer\n{\n    public"
  },
  {
    "path": "src/Glue/SnakeCase.php",
    "chars": 234,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nclass SnakeCase extends UnderscoreGluer\n{\n    publ"
  },
  {
    "path": "src/Glue/SpaceGluer.php",
    "chars": 169,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nabstract class SpaceGluer extends Gluer\n{\n    /** "
  },
  {
    "path": "src/Glue/TitleCase.php",
    "chars": 229,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nclass TitleCase extends SpaceGluer\n{\n    public fu"
  },
  {
    "path": "src/Glue/TrainCase.php",
    "chars": 228,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nclass TrainCase extends DashGluer\n{\n    public fun"
  },
  {
    "path": "src/Glue/UnderscoreGluer.php",
    "chars": 174,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nabstract class UnderscoreGluer extends Gluer\n{\n   "
  },
  {
    "path": "src/Glue/UpperCase.php",
    "chars": 229,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nclass UpperCase extends SpaceGluer\n{\n    public fu"
  },
  {
    "path": "src/Glue/UppercaseGluer.php",
    "chars": 172,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Glue;\n\nabstract class UppercaseGluer extends Gluer\n{\n    "
  },
  {
    "path": "src/Split/DashSplitter.php",
    "chars": 461,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Split;\n\nuse Jawira\\CaseConverter\\Glue\\DashGluer;\n\nclass D"
  },
  {
    "path": "src/Split/DotSplitter.php",
    "chars": 466,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Split;\n\nuse Jawira\\CaseConverter\\Glue\\DotNotation;\n\nclass"
  },
  {
    "path": "src/Split/SpaceSplitter.php",
    "chars": 464,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Split;\n\nuse Jawira\\CaseConverter\\Glue\\SpaceGluer;\n\nclass "
  },
  {
    "path": "src/Split/Splitter.php",
    "chars": 1464,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Split;\n\nuse Jawira\\CaseConverter\\CaseConverterException;\n"
  },
  {
    "path": "src/Split/UnderscoreSplitter.php",
    "chars": 458,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Split;\n\nuse Jawira\\CaseConverter\\Glue\\UnderscoreGluer;\n\nc"
  },
  {
    "path": "src/Split/UppercaseSplitter.php",
    "chars": 553,
    "preview": "<?php declare(strict_types=1);\n\nnamespace Jawira\\CaseConverter\\Split;\n\nclass UppercaseSplitter extends Splitter\n{\n    //"
  },
  {
    "path": "tests/behat/bootstrap/FeatureContext.php",
    "chars": 3428,
    "preview": "<?php\n\nuse Behat\\Behat\\Context\\Context;\nuse Behat\\Behat\\Tester\\Exception\\PendingException;\nuse Jawira\\CaseConverter\\Conv"
  },
  {
    "path": "tests/behat/case-converter.feature",
    "chars": 22022,
    "preview": "Feature: Convert Case\n  In order to change string case\n  Dev should be able to\n  change case\n\n\n  Scenario Outline: Chang"
  },
  {
    "path": "tests/phpunit/AdaCaseTest.php",
    "chars": 1308,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\AdaCase;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Class AdaCaseTest\n */\nclass AdaCas"
  },
  {
    "path": "tests/phpunit/CamelCaseTest.php",
    "chars": 1535,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\CamelCase;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Class CamelCaseTest\n */\nclass Ca"
  },
  {
    "path": "tests/phpunit/CaseConverterTest.php",
    "chars": 1064,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\CaseConverter;\nuse Jawira\\CaseConverter\\Convert;\nuse PHPUnit\\Framework\\TestCase;\n\nclass "
  },
  {
    "path": "tests/phpunit/CobolCaseTest.php",
    "chars": 1342,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\CobolCase;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Class CobolCaseTest\n */\nclass Co"
  },
  {
    "path": "tests/phpunit/ConvertTest.php",
    "chars": 23085,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\CaseConverterException;\nuse Jawira\\CaseConverter\\Convert;\nuse Jawira\\CaseConverter\\Glue\\"
  },
  {
    "path": "tests/phpunit/DashSplitterTest.php",
    "chars": 1262,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Split\\DashSplitter;\nuse PHPUnit\\Framework\\TestCase;\n\nclass DashSplitterTest extends Test"
  },
  {
    "path": "tests/phpunit/DotNotationTest.php",
    "chars": 1241,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\DotNotation;\nuse PHPUnit\\Framework\\TestCase;\n\nclass DotNotationTest extends TestCas"
  },
  {
    "path": "tests/phpunit/DotSplitterTest.php",
    "chars": 1279,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Split\\DotSplitter;\nuse PHPUnit\\Framework\\TestCase;\n\nclass DotSplitterTest extends TestCa"
  },
  {
    "path": "tests/phpunit/GluerTest.php",
    "chars": 5486,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\Gluer;\nuse PHPUnit\\Framework\\TestCase;\n\nclass GluerTest extends TestCase\n{\n    /**\n"
  },
  {
    "path": "tests/phpunit/KebabCaseTest.php",
    "chars": 1310,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\KebabCase;\nuse PHPUnit\\Framework\\TestCase;\n\nclass KebabCaseTest extends TestCase\n{\n"
  },
  {
    "path": "tests/phpunit/LowerCaseTest.php",
    "chars": 1189,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\LowerCase;\nuse PHPUnit\\Framework\\TestCase;\n\nclass LowerCaseTest extends TestCase\n{\n"
  },
  {
    "path": "tests/phpunit/MacroCaseTest.php",
    "chars": 1195,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\MacroCase;\nuse PHPUnit\\Framework\\TestCase;\n\nclass MacroCaseTest extends TestCase\n{\n"
  },
  {
    "path": "tests/phpunit/PascalCaseTest.php",
    "chars": 1209,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\PascalCase;\nuse PHPUnit\\Framework\\TestCase;\n\nclass PascalCaseTest extends TestCase\n"
  },
  {
    "path": "tests/phpunit/SentenceCaseTest.php",
    "chars": 1399,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\SentenceCase;\nuse PHPUnit\\Framework\\TestCase;\n\nclass SentenceCaseTest extends TestC"
  },
  {
    "path": "tests/phpunit/SnakeCaseTest.php",
    "chars": 1203,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\SnakeCase;\nuse PHPUnit\\Framework\\TestCase;\n\nclass SnakeCaseTest extends TestCase\n{\n"
  },
  {
    "path": "tests/phpunit/SpaceSplitterTest.php",
    "chars": 1267,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Split\\SpaceSplitter;\nuse PHPUnit\\Framework\\TestCase;\n\nclass SpaceSplitterTest extends Te"
  },
  {
    "path": "tests/phpunit/SplitterTest.php",
    "chars": 1429,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Split\\SpaceSplitter;\nuse PHPUnit\\Framework\\TestCase;\n\nclass SplitterTest extends TestCas"
  },
  {
    "path": "tests/phpunit/TitleCaseTest.php",
    "chars": 1198,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\TitleCase;\nuse PHPUnit\\Framework\\TestCase;\n\nclass TitleCaseTest extends TestCase\n{\n"
  },
  {
    "path": "tests/phpunit/TrainCaseTest.php",
    "chars": 1203,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\TrainCase;\nuse PHPUnit\\Framework\\TestCase;\n\nclass TrainCaseTest extends TestCase\n{\n"
  },
  {
    "path": "tests/phpunit/UnderscoreSplitterTest.php",
    "chars": 1292,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Split\\UnderscoreSplitter;\nuse PHPUnit\\Framework\\TestCase;\n\nclass UnderscoreSplitterTest "
  },
  {
    "path": "tests/phpunit/UpperCaseTest.php",
    "chars": 1203,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Glue\\UpperCase;\nuse PHPUnit\\Framework\\TestCase;\n\nclass UpperCaseTest extends TestCase\n{\n"
  },
  {
    "path": "tests/phpunit/UppercaseSplitterTest.php",
    "chars": 1312,
    "preview": "<?php\n\nuse Jawira\\CaseConverter\\Split\\UppercaseSplitter;\nuse PHPUnit\\Framework\\TestCase;\n\nclass UppercaseSplitterTest ex"
  }
]

About this extraction

This page contains the full source code of the jawira/case-converter GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 80 files (147.0 KB), approximately 39.6k tokens, and a symbol index with 149 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!