├── .gitignore ├── .php_cs ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── VERSIONING.md ├── bin └── test.sh ├── composer.json ├── couscous.yml ├── fixtures ├── Repository.php ├── Types │ ├── DeepImplementation.php │ ├── DeepInterface.php │ ├── NoParents.php │ ├── OtherInterface.php │ ├── SomeAndOtherImplementation.php │ ├── SomeImplementation.php │ ├── SomeInterface.php │ └── WithParents.php ├── actual │ ├── GenerateConstructorTest │ │ └── .gitkeep │ └── GenerateMethodTest │ │ └── .gitkeep ├── expected │ ├── GenerateConstructorTest │ │ ├── it_inserts_constructor_at_the_begining_of_the_class.txt │ │ ├── it_inserts_properties_with_initialization_for_each_constructor_arguments.txt │ │ └── it_prevents_constructor_to_use_a_special_class_name.txt │ └── GenerateMethodTest │ │ ├── it_inserts_method_at_the_end_of_the_class.txt │ │ ├── it_names_object_argument_after_their_type.txt │ │ ├── it_prevents_methods_to_be_longer_than_120_characters.txt │ │ ├── it_prevents_methods_to_use_a_special_class_name.txt │ │ └── it_type_hints_arguments.txt └── skeleton │ ├── GenerateConstructorTest │ ├── it_inserts_constructor_at_the_begining_of_the_class.txt │ ├── it_inserts_properties_with_initialization_for_each_constructor_arguments.txt │ └── it_prevents_constructor_to_use_a_special_class_name.txt │ └── GenerateMethodTest │ ├── it_inserts_method_at_the_end_of_the_class.txt │ ├── it_names_object_argument_after_their_type.txt │ ├── it_prevents_methods_to_be_longer_than_120_characters.txt │ ├── it_prevents_methods_to_use_a_special_class_name.txt │ └── it_type_hints_arguments.txt ├── phpspec.yml.dist ├── phpunit.xml.dist ├── spec └── Memio │ └── SpecGen │ ├── CodeEditor │ ├── CodeEditorSpec.php │ ├── InsertConstructorHandlerSpec.php │ ├── InsertMethodHandlerSpec.php │ ├── InsertPropertiesHandlerSpec.php │ ├── InsertPropertyHandlerSpec.php │ ├── InsertUseStatementHandlerSpec.php │ └── InsertUseStatementsHandlerSpec.php │ ├── CommandBus │ └── CommandBusSpec.php │ ├── ConstructorGeneratorSpec.php │ ├── GenerateConstructor │ ├── GenerateConstructorHandlerSpec.php │ ├── InsertGeneratedConstructorListenerSpec.php │ └── LogGeneratedConstructorListenerSpec.php │ ├── GenerateMethod │ ├── GenerateMethodHandlerSpec.php │ ├── InsertGeneratedMethodListenerSpec.php │ └── LogGeneratedMethodListenerSpec.php │ ├── Marshaller │ ├── Model │ │ └── ArgumentCollectionSpec.php │ ├── Service │ │ ├── NameGuesserSpec.php │ │ └── TypeGuesserSpec.php │ └── VariableArgumentMarshallerSpec.php │ └── MethodGeneratorSpec.php ├── src └── Memio │ └── SpecGen │ ├── CodeEditor │ ├── CodeEditor.php │ ├── InsertConstructor.php │ ├── InsertConstructorHandler.php │ ├── InsertMethod.php │ ├── InsertMethodHandler.php │ ├── InsertProperties.php │ ├── InsertPropertiesHandler.php │ ├── InsertProperty.php │ ├── InsertPropertyHandler.php │ ├── InsertUseStatement.php │ ├── InsertUseStatementHandler.php │ ├── InsertUseStatements.php │ └── InsertUseStatementsHandler.php │ ├── CommandBus │ ├── Command.php │ ├── CommandBus.php │ └── CommandHandler.php │ ├── ConstructorGenerator.php │ ├── GenerateConstructor │ ├── GenerateConstructor.php │ ├── GenerateConstructorHandler.php │ ├── GeneratedConstructor.php │ ├── InsertGeneratedConstructorListener.php │ └── LogGeneratedConstructorListener.php │ ├── GenerateMethod │ ├── GenerateMethod.php │ ├── GenerateMethodHandler.php │ ├── GeneratedMethod.php │ ├── InsertGeneratedMethodListener.php │ └── LogGeneratedMethodListener.php │ ├── Marshaller │ ├── Model │ │ └── ArgumentCollection.php │ ├── Service │ │ ├── NameGuesser.php │ │ └── TypeGuesser.php │ └── VariableArgumentMarshaller.php │ ├── MemioSpecGenExtension.php │ └── MethodGenerator.php └── tests └── Memio └── SpecGen ├── Build.php ├── Generator ├── GenerateConstructorTest.php └── GenerateMethodTest.php ├── GeneratorTestCase.php └── NullIO.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Third party 2 | /composer.lock 3 | /vendor 4 | /phpunit.xml 5 | /.couscous 6 | /.php_cs.cache 7 | /.phpunit.result.cache 8 | 9 | # Temporary files 10 | /.php_cs.cache 11 | /fixtures/actual 12 | !/fixtures/actual/Generated*Test/.gitkeep 13 | -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | exclude('bin') 5 | ->exclude('vendor') 6 | ->in(__DIR__) 7 | ; 8 | 9 | return PhpCsFixer\Config::create() 10 | ->setRules([ 11 | '@Symfony' => true, 12 | 'visibility_required' => false, 13 | 'array_syntax' => [ 14 | 'syntax' => 'short', 15 | ], 16 | ]) 17 | ->setUsingCache(true) 18 | ->setFinder($finder) 19 | ; 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | cache: 6 | directories: 7 | - $HOME/.composer/cache 8 | 9 | php: 10 | - 7.2 11 | - 7.3 12 | 13 | before_script: 14 | - composer selfupdate 15 | 16 | script: 17 | - bin/test.sh 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 0.10.0: Symfony 5, phpspec 6, PHP 7.2 4 | 5 | Upgraded requirements: 6 | 7 | * Symfony 5 8 | * phpspec 6.1 9 | * PHP 7.2 10 | 11 | ## 0.9.0: phpspec 5 12 | 13 | Upgraded phpspec to v5.0@rc, meaning: 14 | 15 | * phpspec v4 support was dropped 16 | * PHP 7.0 support was dropped 17 | * Symfony 2.7, 3.0, 3.1, 3.2 and 3.3 was dropped 18 | * added usage of void return type 19 | * added usage of constant visibility 20 | 21 | ## 0.8.5: Normalized float to double 22 | 23 | Normalization from float to double, thanks to @ItsKelsBoys 24 | 25 | ## 0.8.4: PHP 7.2 support 26 | 27 | Thanks to @roukmoute for adding PHP 7.2 support 28 | 29 | ## 0.8.3: Fixed float arguments 30 | 31 | Marked float as being a non object type, thanks to @arn0d 32 | 33 | ## 0.8.2: phpspec 4 34 | 35 | Using phpspec 4.0 stable, thanks to @arn0d 36 | 37 | ## 0.8.1: Memio 2.0 38 | 39 | Using Memio 2.0, thanks to @arn0d 40 | 41 | ## 0.8.0: phpspec 4 42 | 43 | Upgraded phpspec to v4.0@rc, meaning: 44 | 45 | * phpspec v2 and v3 support was dropped 46 | 47 | ## 0.7.0: Scalar Type Hints 48 | 49 | Upgraded Memio to v2.0@alpha, meaning: 50 | 51 | * PHP 5 support was dropped 52 | * scalar arguments now get type hinted 53 | * maximum method argument line length changed from 120 to 80 54 | * opening curly brace changed to be on the same line as the method 55 | closing parenthesis, when arguments are on many lines 56 | * properties changed to not have empty lines between them, 57 | except if they have PHPdoc 58 | 59 | ## 0.6.2: Re-enabled constructor generator 60 | 61 | Constructor generator wasn't registered as a generator in phpspec 3, 62 | du to a missing DI tag. 63 | 64 | ## 0.6.0, 0.6.1: Upgraded tp phpspec 3.0@beta2 65 | 66 | > **BC Break**: since phpspec 3.0@beta2, registering extensions in 67 | > `phpspec.yml` is done as follow: 68 | > 69 | > ``` 70 | > extensions: 71 | > Memio\SpecGen\MemioSpecGenExtension: ~ 72 | > ``` 73 | 74 | > **Note**: `0.6.0` is actually the same as `0.5.0`, due to a git tagging 75 | > typo. 76 | 77 | ## 0.5.0: Upgraded to phpspec 3.0@beta1 78 | 79 | Due to phpspec sharing some common dependencies with SpecGen: 80 | 81 | * dropped support for PHP < 5.6 82 | * dropped support for Symfony Event Dispatcher < 2.7 83 | 84 | ## 0.4.1: Updated dependencies 85 | 86 | * added support for PHP 7 87 | * added support for Symfony 3 88 | 89 | ## 0.4.0: Interface Typehints 90 | 91 | * object arguments will now be typehinted against their interface 92 | * object arguments will now be named after their interface (without `Interface` suffix) 93 | 94 | ## 0.3.0: Constructor generation 95 | 96 | * constructor generation, same as method except: 97 | * it inserts constructor at the begining of the class 98 | * it inserts properties with initialization for each constructor arguments 99 | 100 | ## 0.2.0: Use statements 101 | 102 | * use statement insertion (for each object argument) 103 | 104 | ## 0.1.1: Fixed object type hints 105 | 106 | * fixed Prophecy test doubles type guessing 107 | 108 | ## 0.1.0: Method Generation 109 | 110 | * method generation: 111 | * it inserts method at the end of the class 112 | * it typehints object, array and callable arguments 113 | * it names object arguments after their type 114 | * it names scalar arguments after a generic name (`argument`) 115 | * it adds number on names that could collide (e.g. `$argument1, $argument2`) 116 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | Everybody should be able to help. Here's how you can make this project more 4 | awesome: 5 | 6 | 1. [Fork it](https://github.com/memio/spec-gen/fork_select) 7 | 2. improve it 8 | 3. submit a [pull request](https://help.github.com/articles/creating-a-pull-request) 9 | 10 | Your work will then be reviewed as soon as possible (suggestions about some 11 | changes, improvements or alternatives may be given). 12 | 13 | Here's some tips to make you the best contributor ever: 14 | 15 | * [Standard code](#standard-code) 16 | * [Specifications](#specifications) 17 | * [Keeping your fork up-to-date](#keeping-your-fork-up-to-date) 18 | 19 | ## Standard code 20 | 21 | Use [PHP CS fixer](http://cs.sensiolabs.org/) to make your code compliant with 22 | Memio's coding standards: 23 | 24 | ```console 25 | $ ./vendor/bin/php-cs-fixer fix . 26 | ``` 27 | 28 | ## Specifications 29 | 30 | Memio drives its development using [phpspec](http://www.phpspec.net/). 31 | 32 | First bootstrap the code for the Specification: 33 | 34 | ```console 35 | $ phpspec describe 'Memio\Memio\MyNewUseCase' 36 | ``` 37 | 38 | Next, write the actual code of the Specification: 39 | 40 | ```console 41 | $ $EDITOR spec/Memio/SpecGen/MyNewUseCase.php 42 | ``` 43 | 44 | Then bootstrap the code for the corresponding Use Case: 45 | 46 | ```console 47 | $ phpspec run 48 | ``` 49 | 50 | Follow that by writing the actual code of the Use Case: 51 | 52 | ```console 53 | $ $EDITOR src/Memio/SpecGen/MyNewUseCase.php 54 | ``` 55 | 56 | Finally run the specification: 57 | 58 | ```console 59 | $ phpspec run 60 | ``` 61 | 62 | Results should be green! 63 | 64 | ## Keeping your fork up-to-date 65 | 66 | To keep your fork up-to-date, you should track the upstream (original) one 67 | using the following command: 68 | 69 | ```console 70 | $ git remote add upstream https://github.com/memio/spec-gen.git 71 | ``` 72 | 73 | Then get the upstream changes: 74 | 75 | ```console 76 | git checkout main 77 | git pull --rebase origin main 78 | git pull --rebase upstream main 79 | git checkout 80 | git rebase main 81 | ``` 82 | 83 | Finally, publish your changes: 84 | 85 | ```console 86 | $ git push -f origin 87 | ``` 88 | 89 | Your pull request will be automatically updated. 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2024 Loïc Faugeron 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Memio's SpecGen [![Travis CI](https://travis-ci.org/memio/spec-gen.png)](https://travis-ci.org/memio/spec-gen) 2 | 3 | This extension for [phpspec](http://phpspec.net/) provides a powerful code generator: 4 | 5 | * method generation: 6 | * it inserts method at the end of the class 7 | * it typehints arguments (uses interface when possible) 8 | * it names object arguments after their type (strips `Interface` suffix from names) 9 | * it names scalar arguments after a generic name (`argument`) 10 | * it adds number on names that could collide (e.g. `$argument1, $argument2`) 11 | * constructor generation, same as method except: 12 | * it inserts constructor at the begining of the class 13 | * it inserts properties with initialization for each constructor arguments 14 | 15 | > **Note**: Currently it is not possible to provide custom templates to SpecGen 16 | > (it is not compatible with phpspec templates). 17 | 18 | ## Installation 19 | 20 | First install it using [Composer](https://getcomposer.org/download): 21 | 22 | ```console 23 | $ composer require --dev memio/spec-gen:^0.10 24 | ``` 25 | 26 | Then enable it in `phpspec.yml`: 27 | 28 | ```yaml 29 | extensions: 30 | Memio\SpecGen\MemioSpecGenExtension: ~ 31 | ``` 32 | 33 | > **Version guide**: 34 | > 35 | > * using phpspec 5? Then use spec-gen v0.9 36 | > * using phpspec 4? Then use spec-gen v0.8 37 | > * using phpspec 3 and PHP 7? Then use spec-gen v0.7 38 | > * using phpspec 3 and PHP 5.6? Then use spec-gen v0.6 39 | > * using phpspec 2? Then use spec-gen v0.4 40 | 41 | ## Full example 42 | 43 | Let's write the following specification: 44 | 45 | ```php 46 | beConstructedWith($filesystem); 62 | } 63 | 64 | function it_creates_new_files(File $file, Filesystem $filesystem) 65 | { 66 | $filesystem->exists(self::FILENAME)->willReturn(false); 67 | $filesystem->create(self::FILENAME)->willReturn($file); 68 | 69 | $this->open(self::FILENAME, self::FORCE_FILE_CREATION)->shouldBe($file); 70 | } 71 | } 72 | ``` 73 | 74 | Executing the specifications (`phpspec run`) will generate the following class: 75 | 76 | ```php 77 | filesystem = $filesystem; 90 | } 91 | 92 | public function open(string $argument1, bool $argument2) 93 | { 94 | } 95 | } 96 | ``` 97 | 98 | Now we can start naming those generic arguments and write the code. 99 | 100 | ## Want to know more? 101 | 102 | You can see the current and past versions using one of the following: 103 | 104 | * the `git tag` command 105 | * the [releases page on Github](https://github.com/memio/spec-gen/releases) 106 | * the file listing the [changes between versions](CHANGELOG.md) 107 | 108 | And finally some meta documentation: 109 | 110 | * [copyright and MIT license](LICENSE) 111 | * [versioning and branching models](VERSIONING.md) 112 | * [contribution instructions](CONTRIBUTING.md) 113 | 114 | ## Roadmap 115 | 116 | * constructor property promotion 117 | * return type hints 118 | * method body (mirror of test method body) 119 | * better scalar argument naming (based on names used in test) 120 | -------------------------------------------------------------------------------- /VERSIONING.md: -------------------------------------------------------------------------------- 1 | # Versioning and branching models 2 | 3 | This file explains the versioning and branching models of this project. 4 | 5 | ## Versioning 6 | 7 | The versioning is inspired by [Semantic Versioning](http://semver.org/): 8 | 9 | > Given a version number MAJOR.MINOR.PATCH, increment the: 10 | > 11 | > 1. MAJOR version when you make incompatible API changes 12 | > 2. MINOR version when you add functionality in a backwards-compatible manner 13 | > 3. PATCH version when you make backwards-compatible bug fixes 14 | 15 | ### Public API 16 | 17 | Classes and methods marked with the `@api` tag are considered to be the public 18 | API of this project. 19 | 20 | ## Branching Model 21 | 22 | The branching is inspired by [@jbenet](https://github.com/jbenet) 23 | [simple git branching model](https://gist.github.com/jbenet/ee6c9ac48068889b0912): 24 | 25 | > 1. `main` must always be deployable. 26 | > 2. **all changes** are made through feature branches (pull-request + merge) 27 | > 3. rebase to avoid/resolve conflicts; merge in to `main` 28 | -------------------------------------------------------------------------------- /bin/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | composer --quiet install --optimize-autoloader 4 | 5 | vendor/bin/phpspec --no-interaction run --format=dot 6 | vendor/bin/phpunit 7 | vendor/bin/php-cs-fixer fix --dry-run 8 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "memio/spec-gen", 3 | "license": "MIT", 4 | "type": "library", 5 | "description": "phpspec extension for better code generation", 6 | "keywords": ["phpspec", "extension", "generator", "PHP", "code"], 7 | "homepage": "http://memio.github.io/spec-gen", 8 | "authors": [ 9 | { 10 | "name": "Loïc Faugeron", 11 | "email": "faugeron.loic@gmail.com", 12 | "homepage": "http://gnugat.github.io", 13 | "role": "Developer" 14 | } 15 | ], 16 | "autoload": { 17 | "psr-4": { 18 | "Memio\\SpecGen\\": "src/Memio/SpecGen" 19 | } 20 | }, 21 | "autoload-dev": { 22 | "psr-4": { 23 | "Memio\\SpecGen\\Fixtures\\": "fixtures", 24 | "tests\\Memio\\SpecGen\\": "tests" 25 | } 26 | }, 27 | "require": { 28 | "gnugat/redaktilo": "^2.0", 29 | "memio/memio": "^2.0", 30 | "memio/linter": "^2.0", 31 | "memio/validator": "^2.0", 32 | "memio/model": "^2.0.1", 33 | "memio/pretty-printer": "^2.0", 34 | "memio/twig-template-engine": "^2.0.1", 35 | "php": "^7.2", 36 | "phpspec/phpspec": "^6.1", 37 | "symfony/event-dispatcher": "^5.0" 38 | }, 39 | "require-dev": { 40 | "friendsofphp/php-cs-fixer": "^2.16", 41 | "phpunit/phpunit": "^8.4" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /couscous.yml: -------------------------------------------------------------------------------- 1 | template: 2 | url: https://github.com/CouscousPHP/Template-Light.git 3 | 4 | baseUrl: http://memio.github.io/spec-gen 5 | 6 | title: Memio SpecGen 7 | subTitle: phpspec extension for better code generation 8 | 9 | github: 10 | user: memio 11 | repo: spec-gen 12 | 13 | menu: 14 | items: 15 | home: 16 | text: Home 17 | relativeUrl: 18 | -------------------------------------------------------------------------------- /fixtures/Repository.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Fixtures; 13 | 14 | class Repository 15 | { 16 | /** 17 | * @param string $name 18 | * 19 | * @return string 20 | */ 21 | public static function find($name) 22 | { 23 | return file_get_contents(__DIR__.'/'.$name.'.txt'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /fixtures/Types/DeepImplementation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Fixtures\Types; 13 | 14 | class DeepImplementation implements DeepInterface 15 | { 16 | public function doSomething() 17 | { 18 | } 19 | 20 | public function doStuff() 21 | { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fixtures/Types/DeepInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Fixtures\Types; 13 | 14 | interface DeepInterface extends SomeInterface 15 | { 16 | public function doStuff(); 17 | } 18 | -------------------------------------------------------------------------------- /fixtures/Types/NoParents.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Fixtures\Types; 13 | 14 | class NoParents 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /fixtures/Types/OtherInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Fixtures\Types; 13 | 14 | interface OtherInterface 15 | { 16 | public function doSomethingElse(); 17 | } 18 | -------------------------------------------------------------------------------- /fixtures/Types/SomeAndOtherImplementation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Fixtures\Types; 13 | 14 | class SomeAndOtherImplementation implements SomeInterface, OtherInterface 15 | { 16 | public function doSomething() 17 | { 18 | } 19 | 20 | public function doSomethingElse() 21 | { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fixtures/Types/SomeImplementation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Fixtures\Types; 13 | 14 | class SomeImplementation implements SomeInterface 15 | { 16 | public function doSomething() 17 | { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /fixtures/Types/SomeInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Fixtures\Types; 13 | 14 | interface SomeInterface 15 | { 16 | public function doSomething(); 17 | } 18 | -------------------------------------------------------------------------------- /fixtures/Types/WithParents.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Fixtures\Types; 13 | 14 | class WithParents extends NoParents 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /fixtures/actual/GenerateConstructorTest/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/memio/spec-gen/16d2686eff16bbf08193fb463de02ccc8b05cfc4/fixtures/actual/GenerateConstructorTest/.gitkeep -------------------------------------------------------------------------------- /fixtures/actual/GenerateMethodTest/.gitkeep: -------------------------------------------------------------------------------- 1 | .gitkeep 2 | -------------------------------------------------------------------------------- /fixtures/expected/GenerateConstructorTest/it_inserts_constructor_at_the_begining_of_the_class.txt: -------------------------------------------------------------------------------- 1 | dateTime = $dateTime; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /fixtures/expected/GenerateConstructorTest/it_prevents_constructor_to_use_a_special_class_name.txt: -------------------------------------------------------------------------------- 1 | argument1 = $argument1; 22 | $this->argument2 = $argument2; 23 | $this->argument3 = $argument3; 24 | $this->argument4 = $argument4; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /fixtures/expected/GenerateMethodTest/it_inserts_method_at_the_end_of_the_class.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | tests 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/CodeEditor/CodeEditorSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Gnugat\Redaktilo\File; 16 | use Memio\SpecGen\CommandBus\Command; 17 | use Memio\SpecGen\CommandBus\CommandBus; 18 | use PhpSpec\ObjectBehavior; 19 | 20 | class CodeEditorSpec extends ObjectBehavior 21 | { 22 | const FILENAME = 'src/Vendor/Project/MyClass.php'; 23 | 24 | function let(CommandBus $commandBus, Editor $editor) 25 | { 26 | $this->beConstructedWith($commandBus, $editor); 27 | } 28 | 29 | function it_can_open_existing_files(File $file, Editor $editor) 30 | { 31 | $editor->open(self::FILENAME)->willReturn($file); 32 | 33 | $this->open(self::FILENAME)->shouldBe($file); 34 | } 35 | 36 | function it_can_save_files(File $file, Editor $editor) 37 | { 38 | $editor->save($file)->shouldBeCalled(); 39 | 40 | $this->save($file); 41 | } 42 | 43 | function it_handles_commands(Command $command, CommandBus $commandBus) 44 | { 45 | $commandBus->handle($command)->shouldBeCalled(); 46 | 47 | $this->handle($command); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/CodeEditor/InsertConstructorHandlerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Gnugat\Redaktilo\File; 16 | use Memio\Model\Method; 17 | use Memio\PrettyPrinter\PrettyPrinter; 18 | use Memio\SpecGen\CodeEditor\InsertConstructor; 19 | use Memio\SpecGen\CodeEditor\InsertConstructorHandler; 20 | use Memio\SpecGen\CommandBus\CommandHandler; 21 | use PhpSpec\ObjectBehavior; 22 | 23 | class InsertConstructorHandlerSpec extends ObjectBehavior 24 | { 25 | const GENERATED_CODE = ' abstract public function __construct();'; 26 | 27 | function let(Editor $editor, PrettyPrinter $prettyPrinter) 28 | { 29 | $this->beConstructedWith($editor, $prettyPrinter); 30 | } 31 | 32 | function it_is_a_command_handler() 33 | { 34 | $this->shouldImplement(CommandHandler::class); 35 | } 36 | 37 | function it_supports_insert_constructor_command(InsertConstructor $insertConstructor) 38 | { 39 | $this->supports($insertConstructor)->shouldBe(true); 40 | } 41 | 42 | function it_does_not_insert_a_constructor_twice( 43 | Editor $editor, 44 | File $file, 45 | Method $method, 46 | PrettyPrinter $prettyPrinter 47 | ) { 48 | $insertConstructor = new InsertConstructor($file->getWrappedObject(), $method->getWrappedObject()); 49 | 50 | $editor->hasBelow($file, InsertConstructorHandler::CONSTRUCTOR, 0)->willReturn(true); 51 | $prettyPrinter->generateCode($method)->shouldNotBeCalled(); 52 | 53 | $this->handle($insertConstructor); 54 | } 55 | 56 | function it_inserts_constructor_in_empty_class( 57 | Editor $editor, 58 | File $file, 59 | Method $method, 60 | PrettyPrinter $prettyPrinter 61 | ) { 62 | $insertConstructor = new InsertConstructor($file->getWrappedObject(), $method->getWrappedObject()); 63 | 64 | $editor->hasBelow($file, InsertConstructorHandler::CONSTRUCTOR, 0)->willReturn(false); 65 | $editor->hasBelow($file, InsertConstructorHandler::METHOD, 0)->willReturn(false); 66 | $editor->jumpBelow($file, InsertConstructorHandler::CLASS_ENDING, 0)->shouldBeCalled(); 67 | $prettyPrinter->generateCode($method)->willReturn(self::GENERATED_CODE); 68 | $editor->insertAbove($file, self::GENERATED_CODE)->shouldBeCalled(); 69 | $file->decrementCurrentLineNumber(1)->shouldBeCalled(); 70 | $file->getLine()->willReturn('{'); 71 | 72 | $this->handle($insertConstructor); 73 | } 74 | 75 | function it_inserts_constructor_in_class_without_methods( 76 | Editor $editor, 77 | File $file, 78 | Method $method, 79 | PrettyPrinter $prettyPrinter 80 | ) { 81 | $insertConstructor = new InsertConstructor($file->getWrappedObject(), $method->getWrappedObject()); 82 | 83 | $editor->hasBelow($file, InsertConstructorHandler::CONSTRUCTOR, 0)->willReturn(false); 84 | $editor->hasBelow($file, InsertConstructorHandler::METHOD, 0)->willReturn(false); 85 | $editor->jumpBelow($file, InsertConstructorHandler::CLASS_ENDING, 0)->shouldBeCalled(); 86 | $prettyPrinter->generateCode($method)->willReturn(self::GENERATED_CODE); 87 | $editor->insertAbove($file, self::GENERATED_CODE)->shouldBeCalled(); 88 | $file->decrementCurrentLineNumber(1)->shouldBeCalled(); 89 | $file->getLine()->willReturn(' private $property;'); 90 | $editor->insertBelow($file, '')->shouldBeCalled(); 91 | 92 | $this->handle($insertConstructor); 93 | } 94 | 95 | function it_inserts_constructor_in_class_with_only_methods( 96 | Editor $editor, 97 | File $file, 98 | Method $method, 99 | PrettyPrinter $prettyPrinter 100 | ) { 101 | $insertConstructor = new InsertConstructor($file->getWrappedObject(), $method->getWrappedObject()); 102 | 103 | $editor->hasBelow($file, InsertConstructorHandler::CONSTRUCTOR, 0)->willReturn(false); 104 | $editor->hasBelow($file, InsertConstructorHandler::METHOD, 0)->willReturn(true); 105 | $editor->jumpBelow($file, InsertConstructorHandler::METHOD, 0)->shouldBeCalled(); 106 | $editor->insertAbove($file, '')->shouldBeCalled(); 107 | $prettyPrinter->generateCode($method)->willReturn(self::GENERATED_CODE); 108 | $editor->insertAbove($file, self::GENERATED_CODE)->shouldBeCalled(); 109 | $file->decrementCurrentLineNumber(1)->shouldBeCalled(); 110 | $file->getLine()->willReturn('{'); 111 | 112 | $this->handle($insertConstructor); 113 | } 114 | 115 | function it_inserts_constructor_in_class_with_methods_and_other_stuff( 116 | Editor $editor, 117 | File $file, 118 | Method $method, 119 | PrettyPrinter $prettyPrinter 120 | ) { 121 | $insertConstructor = new InsertConstructor($file->getWrappedObject(), $method->getWrappedObject()); 122 | 123 | $editor->hasBelow($file, InsertConstructorHandler::CONSTRUCTOR, 0)->willReturn(false); 124 | $editor->hasBelow($file, InsertConstructorHandler::METHOD, 0)->willReturn(true); 125 | $editor->jumpBelow($file, InsertConstructorHandler::METHOD, 0)->shouldBeCalled(); 126 | $editor->insertAbove($file, '')->shouldBeCalled(); 127 | $prettyPrinter->generateCode($method)->willReturn(self::GENERATED_CODE); 128 | $editor->insertAbove($file, self::GENERATED_CODE)->shouldBeCalled(); 129 | $file->decrementCurrentLineNumber(1)->shouldBeCalled(); 130 | $file->getLine()->willReturn(' const CONSTANT = 42;'); 131 | $editor->insertBelow($file, '')->shouldBeCalled(); 132 | 133 | $this->handle($insertConstructor); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/CodeEditor/InsertMethodHandlerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Gnugat\Redaktilo\File; 16 | use Memio\Model\Method; 17 | use Memio\PrettyPrinter\PrettyPrinter; 18 | use Memio\SpecGen\CodeEditor\InsertMethod; 19 | use Memio\SpecGen\CodeEditor\InsertMethodHandler; 20 | use Memio\SpecGen\CommandBus\CommandHandler; 21 | use PhpSpec\ObjectBehavior; 22 | 23 | class InsertMethodHandlerSpec extends ObjectBehavior 24 | { 25 | const METHOD_NAME = 'method'; 26 | const METHOD_PATTERN = '/^ public function method\(/'; 27 | const GENERATED_CODE = ' public function method() { }'; 28 | 29 | function let(Editor $editor, PrettyPrinter $prettyPrinter) 30 | { 31 | $this->beConstructedWith($editor, $prettyPrinter); 32 | } 33 | 34 | function it_is_a_command_handler() 35 | { 36 | $this->shouldImplement(CommandHandler::class); 37 | } 38 | 39 | function it_supports_insert_method_command(InsertMethod $insertMethod) 40 | { 41 | $this->supports($insertMethod)->shouldBe(true); 42 | } 43 | 44 | function it_does_not_insert_a_method_twice( 45 | Editor $editor, 46 | File $file, 47 | Method $method, 48 | PrettyPrinter $prettyPrinter 49 | ) { 50 | $insertMethod = new InsertMethod($file->getWrappedObject(), $method->getWrappedObject()); 51 | $method->getName()->willReturn(self::METHOD_NAME); 52 | 53 | $editor->hasBelow($file, self::METHOD_PATTERN, 0)->willReturn(true); 54 | $prettyPrinter->generateCode($method)->shouldNotBeCalled(); 55 | 56 | $this->handle($insertMethod); 57 | } 58 | 59 | function it_inserts_method_in_empty_class( 60 | Editor $editor, 61 | File $file, 62 | Method $method, 63 | PrettyPrinter $prettyPrinter 64 | ) { 65 | $insertMethod = new InsertMethod($file->getWrappedObject(), $method->getWrappedObject()); 66 | $method->getName()->willReturn(self::METHOD_NAME); 67 | 68 | $editor->hasBelow($file, self::METHOD_PATTERN, 0)->willReturn(false); 69 | $editor->jumpBelow($file, InsertMethodHandler::CLASS_ENDING, 0)->shouldBeCalled(); 70 | $file->decrementCurrentLineNumber(1)->shouldBeCalled(); 71 | $file->getLine()->willReturn('{'); 72 | $prettyPrinter->generateCode($method)->willReturn(self::GENERATED_CODE); 73 | $editor->insertBelow($file, self::GENERATED_CODE)->shouldBeCalled(); 74 | 75 | $this->handle($insertMethod); 76 | } 77 | 78 | function it_inserts_method_in_class_with_stuff( 79 | Editor $editor, 80 | File $file, 81 | Method $method, 82 | PrettyPrinter $prettyPrinter 83 | ) { 84 | $insertMethod = new InsertMethod($file->getWrappedObject(), $method->getWrappedObject()); 85 | $method->getName()->willReturn(self::METHOD_NAME); 86 | 87 | $editor->hasBelow($file, self::METHOD_PATTERN, 0)->willReturn(false); 88 | $editor->jumpBelow($file, InsertMethodHandler::CLASS_ENDING, 0)->shouldBeCalled(); 89 | $file->decrementCurrentLineNumber(1)->shouldBeCalled(); 90 | $file->getLine()->willReturn(' }'); 91 | $editor->insertBelow($file, '')->shouldBeCalled(); 92 | $prettyPrinter->generateCode($method)->willReturn(self::GENERATED_CODE); 93 | $editor->insertBelow($file, self::GENERATED_CODE)->shouldBeCalled(); 94 | 95 | $this->handle($insertMethod); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/CodeEditor/InsertPropertiesHandlerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\File; 15 | use Memio\Model\Property; 16 | use Memio\SpecGen\CodeEditor\InsertProperties; 17 | use Memio\SpecGen\CodeEditor\InsertProperty; 18 | use Memio\SpecGen\CodeEditor\InsertPropertyHandler; 19 | use Memio\SpecGen\CommandBus\CommandHandler; 20 | use PhpSpec\ObjectBehavior; 21 | use Prophecy\Argument; 22 | 23 | class InsertPropertiesHandlerSpec extends ObjectBehavior 24 | { 25 | function let(InsertPropertyHandler $insertPropertyHandler) 26 | { 27 | $this->beConstructedWith($insertPropertyHandler); 28 | } 29 | 30 | function it_is_a_command_handler() 31 | { 32 | $this->shouldImplement(CommandHandler::class); 33 | } 34 | 35 | function it_supports_insert_properties_command(InsertProperties $insertProperties) 36 | { 37 | $this->supports($insertProperties)->shouldBe(true); 38 | } 39 | 40 | function it_inserts_properties(File $file, Property $property, InsertPropertyHandler $insertPropertyHandler) 41 | { 42 | $properties = [$property->getWrappedObject()]; 43 | $insertProperties = new InsertProperties($file->getWrappedObject(), $properties); 44 | 45 | $insertProperty = Argument::Type(InsertProperty::class); 46 | $insertPropertyHandler->handle($insertProperty)->shouldBeCalled(); 47 | 48 | $this->handle($insertProperties); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/CodeEditor/InsertPropertyHandlerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Gnugat\Redaktilo\File; 16 | use Memio\Model\Property; 17 | use Memio\PrettyPrinter\PrettyPrinter; 18 | use Memio\SpecGen\CodeEditor\InsertProperty; 19 | use Memio\SpecGen\CodeEditor\InsertPropertyHandler; 20 | use Memio\SpecGen\CommandBus\CommandHandler; 21 | use PhpSpec\ObjectBehavior; 22 | 23 | class InsertPropertyHandlerSpec extends ObjectBehavior 24 | { 25 | function let(Editor $editor, PrettyPrinter $prettyPrinter) 26 | { 27 | $this->beConstructedWith($editor, $prettyPrinter); 28 | } 29 | 30 | function it_is_a_command_handler() 31 | { 32 | $this->shouldImplement(CommandHandler::class); 33 | } 34 | 35 | function it_supports_insert_property_command(InsertProperty $insertProperty) 36 | { 37 | $this->supports($insertProperty)->shouldBe(true); 38 | } 39 | 40 | function it_does_not_insert_a_property_twice( 41 | Editor $editor, 42 | File $file, 43 | PrettyPrinter $prettyPrinter, 44 | Property $property 45 | ) { 46 | $insertProperty = new InsertProperty($file->getWrappedObject(), $property->getWrappedObject()); 47 | $property->getName()->willReturn('property'); 48 | 49 | $editor->hasBelow($file, '/^ private \$property;$/', 0)->willReturn(true); 50 | $prettyPrinter->generateCode($property)->shouldNotBeCalled(); 51 | 52 | $this->handle($insertProperty); 53 | } 54 | 55 | function it_inserts_property_in_empty_class( 56 | Editor $editor, 57 | File $file, 58 | PrettyPrinter $prettyPrinter, 59 | Property $property 60 | ) { 61 | $insertProperty = new InsertProperty($file->getWrappedObject(), $property->getWrappedObject()); 62 | $property->getName()->willReturn('property'); 63 | 64 | $editor->hasBelow($file, '/^ private \$property;$/', 0)->willReturn(false); 65 | $editor->hasBelow($file, InsertPropertyHandler::PROPERTY, 0)->willReturn(false); 66 | $editor->hasBelow($file, InsertPropertyHandler::CONSTANT, 0)->willReturn(false); 67 | $editor->jumpBelow($file, InsertPropertyHandler::CLASS_OPENING, 0)->shouldBeCalled(); 68 | $prettyPrinter->generateCode($property)->willReturn(' private $property;'); 69 | $editor->insertBelow($file, ' private $property;')->shouldBeCalled(); 70 | $file->incrementCurrentLineNumber(1)->shouldBeCalled(); 71 | $file->getLine()->willReturn('}'); 72 | 73 | $this->handle($insertProperty); 74 | } 75 | 76 | function it_inserts_property_in_class_with_properties( 77 | Editor $editor, 78 | File $file, 79 | PrettyPrinter $prettyPrinter, 80 | Property $property 81 | ) { 82 | $insertProperty = new InsertProperty($file->getWrappedObject(), $property->getWrappedObject()); 83 | $property->getName()->willReturn('property'); 84 | 85 | $editor->hasBelow($file, '/^ private \$property;$/', 0)->willReturn(false); 86 | $editor->hasBelow($file, InsertPropertyHandler::PROPERTY, 0)->willReturn(true); 87 | $editor->hasBelow($file, InsertPropertyHandler::CONSTANT, 0)->willReturn(false); 88 | $editor->jumpBelow($file, InsertPropertyHandler::CLASS_ENDING, 0)->shouldBeCalled(); 89 | $editor->jumpAbove($file, InsertPropertyHandler::PROPERTY)->shouldBeCalled(); 90 | $editor->insertBelow($file, '')->shouldBeCalled(); 91 | $prettyPrinter->generateCode($property)->willReturn(' private $property;'); 92 | $editor->insertBelow($file, ' private $property;')->shouldBeCalled(); 93 | $file->incrementCurrentLineNumber(1)->shouldBeCalled(); 94 | $file->getLine()->willReturn('}'); 95 | 96 | $this->handle($insertProperty); 97 | } 98 | 99 | function it_inserts_property_in_class_with_constants( 100 | Editor $editor, 101 | File $file, 102 | PrettyPrinter $prettyPrinter, 103 | Property $property 104 | ) { 105 | $insertProperty = new InsertProperty($file->getWrappedObject(), $property->getWrappedObject()); 106 | $property->getName()->willReturn('property'); 107 | 108 | $editor->hasBelow($file, '/^ private \$property;$/', 0)->willReturn(false); 109 | $editor->hasBelow($file, InsertPropertyHandler::PROPERTY, 0)->willReturn(false); 110 | $editor->hasBelow($file, InsertPropertyHandler::CONSTANT, 0)->willReturn(true); 111 | $editor->jumpBelow($file, InsertPropertyHandler::CLASS_ENDING, 0)->shouldBeCalled(); 112 | $editor->jumpAbove($file, InsertPropertyHandler::CONSTANT)->shouldBeCalled(); 113 | $editor->insertBelow($file, '')->shouldBeCalled(); 114 | $prettyPrinter->generateCode($property)->willReturn(' private $property;'); 115 | $editor->insertBelow($file, ' private $property;')->shouldBeCalled(); 116 | $file->incrementCurrentLineNumber(1)->shouldBeCalled(); 117 | $file->getLine()->willReturn('}'); 118 | 119 | $this->handle($insertProperty); 120 | } 121 | 122 | function it_inserts_property_in_class_with_methods( 123 | Editor $editor, 124 | File $file, 125 | PrettyPrinter $prettyPrinter, 126 | Property $property 127 | ) { 128 | $insertProperty = new InsertProperty($file->getWrappedObject(), $property->getWrappedObject()); 129 | $property->getName()->willReturn('property'); 130 | 131 | $editor->hasBelow($file, '/^ private \$property;$/', 0)->willReturn(false); 132 | $editor->hasBelow($file, InsertPropertyHandler::PROPERTY, 0)->willReturn(false); 133 | $editor->hasBelow($file, InsertPropertyHandler::CONSTANT, 0)->willReturn(false); 134 | $editor->jumpBelow($file, InsertPropertyHandler::CLASS_OPENING, 0)->shouldBeCalled(); 135 | $prettyPrinter->generateCode($property)->willReturn(' private $property;'); 136 | $editor->insertBelow($file, ' private $property;')->shouldBeCalled(); 137 | $file->incrementCurrentLineNumber(1)->shouldBeCalled(); 138 | $file->getLine()->willReturn(' public function __construct($property)'); 139 | $editor->insertAbove($file, '')->shouldBeCalled(); 140 | 141 | $this->handle($insertProperty); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/CodeEditor/InsertUseStatementHandlerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Gnugat\Redaktilo\File; 16 | use Memio\Model\FullyQualifiedName; 17 | use Memio\SpecGen\CodeEditor\InsertUseStatement; 18 | use Memio\SpecGen\CodeEditor\InsertUseStatementHandler; 19 | use Memio\SpecGen\CommandBus\CommandHandler; 20 | use PhpSpec\ObjectBehavior; 21 | 22 | class InsertUseStatementHandlerSpec extends ObjectBehavior 23 | { 24 | const FULLY_QUALIFIED_NAME = 'Vendor\Project\MyClass'; 25 | const NAME_SPACE = 'Vendor\Project'; 26 | const NAME_SPACE_PATTERN = '/^namespace Vendor\\\\Project;$/'; 27 | const USE_STATEMENT = 'use Vendor\Project\MyClass;'; 28 | const USE_STATEMENT_PATTERN = '/^use Vendor\\\\Project\\\\MyClass;$/'; 29 | 30 | function let(Editor $editor) 31 | { 32 | $this->beConstructedWith($editor); 33 | } 34 | 35 | function it_is_a_command_handler() 36 | { 37 | $this->shouldImplement(CommandHandler::class); 38 | } 39 | 40 | function it_supports_insert_use_statement_command(InsertUseStatement $insertUseStatement) 41 | { 42 | $this->supports($insertUseStatement)->shouldBe(true); 43 | } 44 | 45 | function it_does_not_insert_use_statement_in_same_namespace( 46 | Editor $editor, 47 | File $file, 48 | FullyQualifiedName $fullyQualifiedName 49 | ) { 50 | $insertUseStatement = new InsertUseStatement($file->getWrappedObject(), $fullyQualifiedName->getWrappedObject()); 51 | $fullyQualifiedName->getNamespace()->willReturn(self::NAME_SPACE); 52 | $fullyQualifiedName->getFullyQualifiedName()->willReturn(self::FULLY_QUALIFIED_NAME); 53 | 54 | $editor->hasBelow($file, self::NAME_SPACE_PATTERN, 0)->willReturn(true); 55 | $editor->insertBelow($file, self::USE_STATEMENT)->shouldNotBeCalled(); 56 | 57 | $this->handle($insertUseStatement); 58 | } 59 | 60 | function it_does_not_insert_use_statement_twice( 61 | Editor $editor, 62 | File $file, 63 | FullyQualifiedName $fullyQualifiedName 64 | ) { 65 | $insertUseStatement = new InsertUseStatement($file->getWrappedObject(), $fullyQualifiedName->getWrappedObject()); 66 | $fullyQualifiedName->getNamespace()->willReturn(self::NAME_SPACE); 67 | $fullyQualifiedName->getFullyQualifiedName()->willReturn(self::FULLY_QUALIFIED_NAME); 68 | 69 | $editor->hasBelow($file, self::NAME_SPACE_PATTERN, 0)->willReturn(false); 70 | $editor->hasBelow($file, self::USE_STATEMENT_PATTERN, 0)->willReturn(true); 71 | $editor->insertBelow($file, self::USE_STATEMENT)->shouldNotBeCalled(); 72 | 73 | $this->handle($insertUseStatement); 74 | } 75 | 76 | function it_inserts_first_use_statement( 77 | Editor $editor, 78 | File $file, 79 | FullyQualifiedName $fullyQualifiedName 80 | ) { 81 | $insertUseStatement = new InsertUseStatement($file->getWrappedObject(), $fullyQualifiedName->getWrappedObject()); 82 | $fullyQualifiedName->getNamespace()->willReturn(self::NAME_SPACE); 83 | $fullyQualifiedName->getFullyQualifiedName()->willReturn(self::FULLY_QUALIFIED_NAME); 84 | 85 | $editor->hasBelow($file, self::NAME_SPACE_PATTERN, 0)->willReturn(false); 86 | $editor->hasBelow($file, self::USE_STATEMENT_PATTERN, 0)->willReturn(false); 87 | $editor->jumpBelow($file, InsertUseStatementHandler::CLASS_ENDING, 0)->shouldBeCalled(); 88 | $editor->hasAbove($file, InsertUseStatementHandler::USE_STATEMENT)->willReturn(false); 89 | $editor->jumpAbove($file, InsertUseStatementHandler::NAME_SPACE)->shouldBeCalled(); 90 | $editor->insertBelow($file, '')->shouldBeCalled(); 91 | $editor->insertBelow($file, self::USE_STATEMENT)->shouldBeCalled(); 92 | 93 | $this->handle($insertUseStatement); 94 | } 95 | 96 | function it_inserts_use_statement_at_the_end_of_use_statement_block( 97 | Editor $editor, 98 | File $file, 99 | FullyQualifiedName $fullyQualifiedName 100 | ) { 101 | $insertUseStatement = new InsertUseStatement($file->getWrappedObject(), $fullyQualifiedName->getWrappedObject()); 102 | $fullyQualifiedName->getNamespace()->willReturn(self::NAME_SPACE); 103 | $fullyQualifiedName->getFullyQualifiedName()->willReturn(self::FULLY_QUALIFIED_NAME); 104 | 105 | $editor->hasBelow($file, self::NAME_SPACE_PATTERN, 0)->willReturn(false); 106 | $editor->hasBelow($file, self::USE_STATEMENT_PATTERN, 0)->willReturn(false); 107 | $editor->jumpBelow($file, InsertUseStatementHandler::CLASS_ENDING, 0)->shouldBeCalled(); 108 | $editor->hasAbove($file, InsertUseStatementHandler::USE_STATEMENT)->willReturn(true); 109 | $editor->jumpAbove($file, InsertUseStatementHandler::USE_STATEMENT)->shouldBeCalled(); 110 | $editor->insertBelow($file, self::USE_STATEMENT)->shouldBeCalled(); 111 | 112 | $this->handle($insertUseStatement); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/CodeEditor/InsertUseStatementsHandlerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Gnugat\Redaktilo\File; 16 | use Memio\Model\FullyQualifiedName; 17 | use Memio\SpecGen\CodeEditor\InsertUseStatement; 18 | use Memio\SpecGen\CodeEditor\InsertUseStatementHandler; 19 | use Memio\SpecGen\CodeEditor\InsertUseStatements; 20 | use Memio\SpecGen\CommandBus\CommandHandler; 21 | use PhpSpec\ObjectBehavior; 22 | use Prophecy\Argument; 23 | 24 | class InsertUseStatementsHandlerSpec extends ObjectBehavior 25 | { 26 | function let(Editor $editor, InsertUseStatementHandler $insertUseStatementHandler) 27 | { 28 | $this->beConstructedWith($editor, $insertUseStatementHandler); 29 | } 30 | 31 | function it_is_a_command_handler() 32 | { 33 | $this->shouldImplement(CommandHandler::class); 34 | } 35 | 36 | function it_supports_insert_use_statements_command(InsertUseStatements $insertUseStatements) 37 | { 38 | $this->supports($insertUseStatements)->shouldBe(true); 39 | } 40 | 41 | function it_inserts_the_same_use_statement_once( 42 | Editor $editor, 43 | File $file, 44 | FullyQualifiedName $fullyQualifiedName, 45 | InsertUseStatementHandler $insertUseStatementHandler 46 | ) { 47 | $fullyQualifiedNames = [$fullyQualifiedName->getWrappedObject()]; 48 | $insertUseStatements = new InsertUseStatements($file->getWrappedObject(), $fullyQualifiedNames); 49 | 50 | $fullyQualifiedName->getFullyQualifiedName()->willReturn('Vendor\Project\MyDependency'); 51 | $editor->hasBelow($file, '/^use Vendor\\\\Project\\\\MyDependency;$/', 0)->willReturn(false); 52 | $insertUseStatement = Argument::Type(InsertUseStatement::class); 53 | $insertUseStatementHandler->handle($insertUseStatement)->shouldBeCalled(); 54 | 55 | $this->handle($insertUseStatements); 56 | } 57 | 58 | function it_does_not_insert_the_same_use_statement_twice( 59 | Editor $editor, 60 | File $file, 61 | FullyQualifiedName $fullyQualifiedName, 62 | InsertUseStatementHandler $insertUseStatementHandler 63 | ) { 64 | $fullyQualifiedNames = [$fullyQualifiedName->getWrappedObject()]; 65 | $insertUseStatements = new InsertUseStatements($file->getWrappedObject(), $fullyQualifiedNames); 66 | 67 | $fullyQualifiedName->getFullyQualifiedName()->willReturn('Vendor\Project\MyDependency'); 68 | $editor->hasBelow($file, '/^use Vendor\\\\Project\\\\MyDependency;$/', 0)->willReturn(true); 69 | $insertUseStatement = Argument::Type(InsertUseStatement::class); 70 | $insertUseStatementHandler->handle($insertUseStatement)->shouldNotBeCalled(); 71 | 72 | $this->handle($insertUseStatements); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/CommandBus/CommandBusSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\CommandBus; 13 | 14 | use Memio\SpecGen\CommandBus\Command; 15 | use Memio\SpecGen\CommandBus\CommandHandler; 16 | use PhpSpec\ObjectBehavior; 17 | 18 | class CommandBusSpec extends ObjectBehavior 19 | { 20 | function it_calls_appropriate_command_handler(Command $command, CommandHandler $commandHandler) 21 | { 22 | $commandHandler->supports($command)->willReturn(true); 23 | $commandHandler->handle($command)->shouldBeCalled(); 24 | $this->addCommandHandler($commandHandler); 25 | 26 | $this->handle($command); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/ConstructorGeneratorSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen; 13 | 14 | use Memio\SpecGen\CommandBus\CommandBus; 15 | use Memio\SpecGen\GenerateConstructor\GenerateConstructor; 16 | use PhpSpec\CodeGenerator\Generator\Generator; 17 | use PhpSpec\Locator\Resource; 18 | use PhpSpec\ObjectBehavior; 19 | use Prophecy\Argument; 20 | 21 | class ConstructorGeneratorSpec extends ObjectBehavior 22 | { 23 | const FILE_NAME = 'src/Vendor/Project/MyClass.php'; 24 | const NAME_SPACE = 'Vendor\Project'; 25 | const CLASS_NAME = 'MyClass'; 26 | const METHOD_NAME = '__construct'; 27 | 28 | function let(CommandBus $commandBus) 29 | { 30 | $this->beConstructedWith($commandBus); 31 | } 32 | 33 | function it_is_a_generator() 34 | { 35 | $this->shouldImplement(Generator::class); 36 | } 37 | 38 | function it_supports_constructor_generation(Resource $resource) 39 | { 40 | $data = ['name' => self::METHOD_NAME]; 41 | $this->supports($resource, 'method', $data)->shouldBe(true); 42 | } 43 | 44 | function it_calls_the_command_bus(CommandBus $commandBus, Resource $resource) 45 | { 46 | $resource->getSrcFilename()->willReturn(self::FILE_NAME); 47 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 48 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 49 | $data = [ 50 | 'name' => self::METHOD_NAME, 51 | 'arguments' => [], 52 | ]; 53 | 54 | $command = Argument::type(GenerateConstructor::class); 55 | $commandBus->handle($command)->shouldbeCalled(); 56 | 57 | $this->generate($resource, $data); 58 | } 59 | 60 | function it_has_a_higher_priority_than_method_generator() 61 | { 62 | $this->getPriority()->shouldBe(1); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/GenerateConstructor/GenerateConstructorHandlerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\GenerateConstructor; 13 | 14 | use Memio\SpecGen\CommandBus\CommandHandler; 15 | use Memio\SpecGen\GenerateConstructor\GenerateConstructor; 16 | use Memio\SpecGen\GenerateConstructor\GeneratedConstructor; 17 | use Memio\SpecGen\Marshaller\VariableArgumentMarshaller; 18 | use PhpSpec\ObjectBehavior; 19 | use Prophecy\Argument; 20 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; 21 | 22 | class GenerateConstructorHandlerSpec extends ObjectBehavior 23 | { 24 | const FILE_NAME = 'src/Vendor/Project/MyClass.php'; 25 | const CLASS_NAME = 'MyClass'; 26 | const METHOD_NAME = 'myMethod'; 27 | 28 | function let(EventDispatcherInterface $eventDispatcher, VariableArgumentMarshaller $variableArgumentMarshaller) 29 | { 30 | $this->beConstructedWith($eventDispatcher, $variableArgumentMarshaller); 31 | } 32 | 33 | function it_is_a_command_handler() 34 | { 35 | $this->shouldImplement(CommandHandler::class); 36 | } 37 | 38 | function it_supports_generate_method_commands(GenerateConstructor $command) 39 | { 40 | $this->supports($command)->shouldBe(true); 41 | } 42 | 43 | function it_builds_a_memio_method_model( 44 | EventDispatcherInterface $eventDispatcher, 45 | VariableArgumentMarshaller $variableArgumentMarshaller 46 | ) { 47 | $variableArguments = []; 48 | $command = new GenerateConstructor(self::FILE_NAME, self::CLASS_NAME, self::METHOD_NAME, $variableArguments); 49 | 50 | $variableArgumentMarshaller->marshal($variableArguments)->willReturn([]); 51 | $generatedConstructor = Argument::type(GeneratedConstructor::class); 52 | $eventDispatcher->dispatch( 53 | $generatedConstructor, 54 | GeneratedConstructor::EVENT_NAME 55 | )->shouldBeCalled(); 56 | 57 | $this->handle($command); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/GenerateConstructor/InsertGeneratedConstructorListenerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\GenerateConstructor; 13 | 14 | use Gnugat\Redaktilo\File; 15 | use Memio\Model\File as FileModel; 16 | use Memio\Model\FullyQualifiedName as FullyQualifiedNameModel; 17 | use Memio\Model\Method as MethodModel; 18 | use Memio\Model\Objekt as ObjectModel; 19 | use Memio\Model\Property as PropertyModel; 20 | use Memio\SpecGen\CodeEditor\CodeEditor; 21 | use Memio\SpecGen\CodeEditor\InsertConstructor; 22 | use Memio\SpecGen\CodeEditor\InsertProperties; 23 | use Memio\SpecGen\CodeEditor\InsertUseStatements; 24 | use Memio\SpecGen\GenerateConstructor\GeneratedConstructor; 25 | use PhpSpec\ObjectBehavior; 26 | use Prophecy\Argument; 27 | 28 | class InsertGeneratedConstructorListenerSpec extends ObjectBehavior 29 | { 30 | const FILE_NAME = 'src/Vendor/Project/MyClass.php'; 31 | const CLASS_NAME = 'MyClass'; 32 | const METHOD_NAME = 'myMethod'; 33 | 34 | function let(CodeEditor $codeEditor) 35 | { 36 | $this->beConstructedWith($codeEditor); 37 | } 38 | 39 | function it_inserts_the_generated_method( 40 | CodeEditor $codeEditor, 41 | File $file, 42 | FileModel $fileModel, 43 | FullyQualifiedNameModel $fullyQualifiedNameModel, 44 | MethodModel $methodModel, 45 | ObjectModel $objectModel, 46 | PropertyModel $propertyModel 47 | ) { 48 | $insertUseStatements = Argument::type(InsertUseStatements::class); 49 | $insertProperties = Argument::type(InsertProperties::class); 50 | $insertConstructor = Argument::type(InsertConstructor::class); 51 | 52 | $generatedConstructor = new GeneratedConstructor($fileModel->getWrappedObject()); 53 | $fileModel->allFullyQualifiedNames()->willReturn([$fullyQualifiedNameModel]); 54 | $fileModel->getFilename()->willReturn(self::FILE_NAME); 55 | $fileModel->getStructure()->willReturn($objectModel); 56 | $objectModel->allProperties()->willReturn([$propertyModel]); 57 | $objectModel->allMethods()->willReturn([$methodModel]); 58 | 59 | $codeEditor->open(self::FILE_NAME)->willReturn($file); 60 | $codeEditor->handle($insertUseStatements)->shouldBeCalled(); 61 | $codeEditor->handle($insertProperties)->shouldBeCalled(); 62 | $codeEditor->handle($insertConstructor)->shouldBeCalled(); 63 | $codeEditor->save($file)->shouldBeCalled(); 64 | 65 | $this->onGeneratedConstructor($generatedConstructor); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/GenerateConstructor/LogGeneratedConstructorListenerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\GenerateConstructor; 13 | 14 | use Memio\Model\File; 15 | use Memio\Model\Method; 16 | use Memio\Model\Objekt; 17 | use Memio\Model\Property; 18 | use Memio\SpecGen\GenerateConstructor\GeneratedConstructor; 19 | use PhpSpec\Console\ConsoleIO; 20 | use PhpSpec\ObjectBehavior; 21 | 22 | class LogGeneratedConstructorListenerSpec extends ObjectBehavior 23 | { 24 | const CLASS_NAME = 'MyClass'; 25 | const METHOD_NAME = '__construct'; 26 | const PROPERTIES_COUNT = 1; 27 | 28 | function let(ConsoleIO $io) 29 | { 30 | $this->beConstructedWith($io); 31 | } 32 | 33 | function it_logs_the_generated_constructor(File $file, ConsoleIO $io, Method $method, Objekt $object, Property $property) 34 | { 35 | $generatedConstructor = new GeneratedConstructor($file->getWrappedObject()); 36 | $file->getStructure()->willReturn($object); 37 | $object->getName()->willReturn(self::CLASS_NAME); 38 | $object->allProperties()->willReturn([$property]); 39 | $object->allMethods()->willReturn([$method]); 40 | $method->getName()->willReturn(self::METHOD_NAME); 41 | 42 | $className = self::CLASS_NAME; 43 | $methodName = self::METHOD_NAME; 44 | $propertiesCount = self::PROPERTIES_COUNT; 45 | $io->write(<<Generated $propertiesCount property for $className, with its constructor 48 | 49 | OUTPUT 50 | )->shouldBeCalled(); 51 | 52 | $this->onGeneratedConstructor($generatedConstructor); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/GenerateMethod/GenerateMethodHandlerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\GenerateMethod; 13 | 14 | use Memio\SpecGen\CommandBus\CommandHandler; 15 | use Memio\SpecGen\GenerateMethod\GeneratedMethod; 16 | use Memio\SpecGen\GenerateMethod\GenerateMethod; 17 | use Memio\SpecGen\Marshaller\VariableArgumentMarshaller; 18 | use PhpSpec\ObjectBehavior; 19 | use Prophecy\Argument; 20 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; 21 | 22 | class GenerateMethodHandlerSpec extends ObjectBehavior 23 | { 24 | const FILE_NAME = 'src/Vendor/Project/MyClass.php'; 25 | const CLASS_NAME = 'MyClass'; 26 | const METHOD_NAME = 'myMethod'; 27 | 28 | function let(EventDispatcherInterface $eventDispatcher, VariableArgumentMarshaller $variableArgumentMarshaller) 29 | { 30 | $this->beConstructedWith($eventDispatcher, $variableArgumentMarshaller); 31 | } 32 | 33 | function it_is_a_command_handler() 34 | { 35 | $this->shouldImplement(CommandHandler::class); 36 | } 37 | 38 | function it_supports_generate_method_commands(GenerateMethod $command) 39 | { 40 | $this->supports($command)->shouldBe(true); 41 | } 42 | 43 | function it_builds_a_memio_method_model( 44 | EventDispatcherInterface $eventDispatcher, 45 | VariableArgumentMarshaller $variableArgumentMarshaller 46 | ) { 47 | $variableArguments = []; 48 | $command = new GenerateMethod(self::FILE_NAME, self::CLASS_NAME, self::METHOD_NAME, $variableArguments); 49 | 50 | $variableArgumentMarshaller->marshal($variableArguments)->willReturn([]); 51 | $generatedMethod = Argument::type(GeneratedMethod::class); 52 | $eventDispatcher->dispatch( 53 | $generatedMethod, 54 | GeneratedMethod::EVENT_NAME 55 | )->shouldBeCalled(); 56 | 57 | $this->handle($command); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/GenerateMethod/InsertGeneratedMethodListenerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\GenerateMethod; 13 | 14 | use Gnugat\Redaktilo\File; 15 | use Memio\Model\File as FileModel; 16 | use Memio\Model\FullyQualifiedName as FullyQualifiedNameModel; 17 | use Memio\Model\Method as MethodModel; 18 | use Memio\Model\Objekt as ObjectModel; 19 | use Memio\SpecGen\CodeEditor\CodeEditor; 20 | use Memio\SpecGen\CodeEditor\InsertMethod; 21 | use Memio\SpecGen\CodeEditor\InsertUseStatements; 22 | use Memio\SpecGen\GenerateMethod\GeneratedMethod; 23 | use PhpSpec\ObjectBehavior; 24 | use Prophecy\Argument; 25 | 26 | class InsertGeneratedMethodListenerSpec extends ObjectBehavior 27 | { 28 | const FILE_NAME = 'src/Vendor/Project/MyClass.php'; 29 | const CLASS_NAME = 'MyClass'; 30 | const METHOD_NAME = 'myMethod'; 31 | 32 | function let(CodeEditor $codeEditor) 33 | { 34 | $this->beConstructedWith($codeEditor); 35 | } 36 | 37 | function it_inserts_the_generated_method( 38 | CodeEditor $codeEditor, 39 | File $file, 40 | FileModel $fileModel, 41 | FullyQualifiedNameModel $fullyQualifiedNameModel, 42 | MethodModel $methodModel, 43 | ObjectModel $objectModel 44 | ) { 45 | $insertUseStatements = Argument::type(InsertUseStatements::class); 46 | $insertMethod = Argument::type(InsertMethod::class); 47 | 48 | $generatedMethod = new GeneratedMethod($fileModel->getWrappedObject()); 49 | $fileModel->allFullyQualifiedNames()->willReturn([$fullyQualifiedNameModel]); 50 | $fileModel->getFilename()->willReturn(self::FILE_NAME); 51 | $fileModel->getStructure()->willReturn($objectModel); 52 | $objectModel->allMethods()->willReturn([$methodModel]); 53 | 54 | $codeEditor->open(self::FILE_NAME)->willReturn($file); 55 | $codeEditor->handle($insertUseStatements)->shouldBeCalled(); 56 | $codeEditor->handle($insertMethod)->shouldBeCalled(); 57 | $codeEditor->save($file)->shouldBeCalled(); 58 | 59 | $this->onGeneratedMethod($generatedMethod); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/GenerateMethod/LogGeneratedMethodListenerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\GenerateMethod; 13 | 14 | use Memio\Model\File; 15 | use Memio\Model\Method; 16 | use Memio\Model\Objekt; 17 | use Memio\SpecGen\GenerateMethod\GeneratedMethod; 18 | use PhpSpec\Console\ConsoleIO; 19 | use PhpSpec\ObjectBehavior; 20 | 21 | class LogGeneratedMethodListenerSpec extends ObjectBehavior 22 | { 23 | const CLASS_NAME = 'MyClass'; 24 | const METHOD_NAME = 'myMethod'; 25 | 26 | function let(ConsoleIO $io) 27 | { 28 | $this->beConstructedWith($io); 29 | } 30 | 31 | function it_logs_the_generated_method(File $file, ConsoleIO $io, Method $method, Objekt $object) 32 | { 33 | $generatedMethod = new GeneratedMethod($file->getWrappedObject()); 34 | $file->getStructure()->willReturn($object); 35 | $object->getName()->willReturn(self::CLASS_NAME); 36 | $object->allMethods()->willReturn([$method]); 37 | $method->getName()->willReturn(self::METHOD_NAME); 38 | 39 | $className = self::CLASS_NAME; 40 | $methodName = self::METHOD_NAME; 41 | $io->write(<<Generated $className#$methodName 44 | 45 | OUTPUT 46 | )->shouldBeCalled(); 47 | 48 | $this->onGeneratedMethod($generatedMethod); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/Marshaller/Model/ArgumentCollectionSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\Marshaller\Model; 13 | 14 | use Memio\Model\Argument; 15 | use PhpSpec\ObjectBehavior; 16 | 17 | class ArgumentCollectionSpec extends ObjectBehavior 18 | { 19 | function it_can_have_arguments() 20 | { 21 | $this->add('string', 'argument'); 22 | 23 | $arguments = $this->all(); 24 | $stringArgument = $arguments[0]; 25 | $stringArgument->shouldHaveType(Argument::class); 26 | $stringArgument->getType()->shouldBe('string'); 27 | $stringArgument->getName()->shouldBe('argument'); 28 | } 29 | 30 | function it_prevents_name_duplication() 31 | { 32 | $this->add('array', 'argument'); 33 | $this->add('string', 'argument'); 34 | 35 | $arguments = $this->all(); 36 | $stringArgument = $arguments[0]; 37 | $stringArgument->getName()->shouldBe('argument1'); 38 | $arrayArgument = $arguments[1]; 39 | $arrayArgument->getName()->shouldBe('argument2'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/Marshaller/Service/NameGuesserSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\Marshaller\Service; 13 | 14 | use Memio\SpecGen\Fixtures\Types\SomeInterface; 15 | use PhpSpec\ObjectBehavior; 16 | 17 | class NameGuesserSpec extends ObjectBehavior 18 | { 19 | function it_uses_a_generic_name_for_non_object_arguments() 20 | { 21 | $this->guess('string')->shouldBe('argument'); 22 | } 23 | 24 | function it_names_object_arguments_after_their_type() 25 | { 26 | $this->guess('DateTime')->shouldBe('dateTime'); 27 | } 28 | 29 | function it_removes_interface_suffix_from_object_argument_names() 30 | { 31 | $this->guess(SomeInterface::class)->shouldBe('some'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/Marshaller/Service/TypeGuesserSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\Marshaller\Service; 13 | 14 | use Memio\SpecGen\Fixtures\Types\DeepImplementation; 15 | use Memio\SpecGen\Fixtures\Types\DeepInterface; 16 | use Memio\SpecGen\Fixtures\Types\NoParents; 17 | use Memio\SpecGen\Fixtures\Types\OtherInterface; 18 | use Memio\SpecGen\Fixtures\Types\SomeAndOtherImplementation; 19 | use Memio\SpecGen\Fixtures\Types\SomeImplementation; 20 | use Memio\SpecGen\Fixtures\Types\SomeInterface; 21 | use Memio\SpecGen\Fixtures\Types\WithParents; 22 | use PhpSpec\ObjectBehavior; 23 | 24 | class TypeGuesserSpec extends ObjectBehavior 25 | { 26 | function it_guesses_scalar_types() 27 | { 28 | $this->guess(42)->shouldBe('int'); 29 | } 30 | 31 | function it_guesses_objects_without_parents() 32 | { 33 | $this->guess(new NoParents())->shouldBe(NoParents::class); 34 | } 35 | 36 | function it_guesses_objects_with_parents() 37 | { 38 | $this->guess(new WithParents())->shouldBe(WithParents::class); 39 | } 40 | 41 | function it_guesses_implementations_of_an_interface() 42 | { 43 | $this->guess(new SomeImplementation())->shouldBe(SomeInterface::class); 44 | } 45 | 46 | function it_guesses_implementations_of_many_interfaces() 47 | { 48 | $this->guess(new SomeAndOtherImplementation())->shouldBe(SomeInterface::class); 49 | } 50 | 51 | function it_guesses_implementations_of_deep_interfaces() 52 | { 53 | $this->guess(new DeepImplementation())->shouldBe(DeepInterface::class); 54 | } 55 | 56 | function it_guesses_phpspec_doubles_of_objects_without_parents(NoParents $noParents) 57 | { 58 | $this->guess($noParents)->shouldBe(NoParents::class); 59 | } 60 | 61 | function it_guesses_phpspec_doubles_of_objects_with_parents(WithParents $withParents) 62 | { 63 | $this->guess($withParents)->shouldBe(WithParents::class); 64 | } 65 | 66 | function it_guesses_phpspec_doubles_of_implementations_of_an_interface(SomeImplementation $someImplementation) 67 | { 68 | $this->guess($someImplementation)->shouldBe(SomeInterface::class); 69 | } 70 | 71 | function it_guesses_phpspec_doubles_of_implementations_of_many_interfaces(SomeAndOtherImplementation $someAndOtherImplementation) 72 | { 73 | $this->guess($someAndOtherImplementation)->shouldBe(OtherInterface::class); 74 | } 75 | 76 | function it_guesses_phpspec_doubles_of_implementations_of_deep_interfaces(DeepImplementation $deepImplementation) 77 | { 78 | $this->guess($deepImplementation)->shouldBe(SomeInterface::class); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/Marshaller/VariableArgumentMarshallerSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen\Marshaller; 13 | 14 | use Memio\SpecGen\Marshaller\Service\NameGuesser; 15 | use Memio\SpecGen\Marshaller\Service\TypeGuesser; 16 | use PhpSpec\ObjectBehavior; 17 | 18 | class VariableArgumentMarshallerSpec extends ObjectBehavior 19 | { 20 | const ARGUMENT_TYPE = 'DateTimeInterface'; 21 | const ARGUMENT_NAME = 'dateTime'; 22 | 23 | function let(NameGuesser $nameGuesser, TypeGuesser $typeGuesser) 24 | { 25 | $this->beConstructedWith($nameGuesser, $typeGuesser); 26 | } 27 | 28 | function it_converts_array_of_variables_into_array_of_arguments(NameGuesser $nameGuesser, TypeGuesser $typeGuesser) 29 | { 30 | $variable = new \DateTime(); 31 | $variables = [$variable]; 32 | 33 | $typeGuesser->guess($variable)->willReturn(self::ARGUMENT_TYPE); 34 | $nameGuesser->guess(self::ARGUMENT_TYPE)->willReturn(self::ARGUMENT_NAME); 35 | 36 | $arguments = $this->marshal($variables); 37 | $argument = $arguments[0]; 38 | $argument->getType()->shouldBe(self::ARGUMENT_TYPE); 39 | $argument->getName()->shouldBe(self::ARGUMENT_NAME); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /spec/Memio/SpecGen/MethodGeneratorSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace spec\Memio\SpecGen; 13 | 14 | use Memio\SpecGen\CommandBus\CommandBus; 15 | use Memio\SpecGen\GenerateMethod\GenerateMethod; 16 | use PhpSpec\CodeGenerator\Generator\Generator; 17 | use PhpSpec\Locator\Resource; 18 | use PhpSpec\ObjectBehavior; 19 | use Prophecy\Argument; 20 | 21 | class MethodGeneratorSpec extends ObjectBehavior 22 | { 23 | const FILE_NAME = 'src/Vendor/Project/MyClass.php'; 24 | const NAME_SPACE = 'Vendor\Project'; 25 | const CLASS_NAME = 'MyClass'; 26 | const METHOD_NAME = 'myMethod'; 27 | 28 | function let(CommandBus $commandBus) 29 | { 30 | $this->beConstructedWith($commandBus); 31 | } 32 | 33 | function it_is_a_generator() 34 | { 35 | $this->shouldImplement(Generator::class); 36 | } 37 | 38 | function it_supports_method_generation(Resource $resource) 39 | { 40 | $this->supports($resource, 'method', [])->shouldBe(true); 41 | } 42 | 43 | function it_calls_the_command_bus(CommandBus $commandBus, Resource $resource) 44 | { 45 | $resource->getSrcFilename()->willReturn(self::FILE_NAME); 46 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 47 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 48 | $data = [ 49 | 'name' => self::METHOD_NAME, 50 | 'arguments' => [], 51 | ]; 52 | 53 | $command = Argument::type(GenerateMethod::class); 54 | $commandBus->handle($command)->shouldbeCalled(); 55 | 56 | $this->generate($resource, $data); 57 | } 58 | 59 | function it_has_regular_priority() 60 | { 61 | $this->getPriority()->shouldBe(0); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/CodeEditor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Gnugat\Redaktilo\File; 16 | use Memio\SpecGen\CommandBus\Command; 17 | use Memio\SpecGen\CommandBus\CommandBus; 18 | 19 | /** 20 | * Facade to enable the "Code Editor" metaphor. 21 | */ 22 | class CodeEditor 23 | { 24 | private $commandBus; 25 | private $editor; 26 | 27 | public function __construct(CommandBus $commandBus, Editor $editor) 28 | { 29 | $this->commandBus = $commandBus; 30 | $this->editor = $editor; 31 | } 32 | 33 | public function open(string $filename): File 34 | { 35 | return $this->editor->open($filename); 36 | } 37 | 38 | public function save(File $file): void 39 | { 40 | $this->editor->save($file); 41 | } 42 | 43 | public function handle(Command $command): void 44 | { 45 | $this->commandBus->handle($command); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertConstructor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\File; 15 | use Memio\Model\Method; 16 | use Memio\SpecGen\CommandBus\Command; 17 | 18 | class InsertConstructor implements Command 19 | { 20 | public $file; 21 | public $method; 22 | 23 | public function __construct(File $file, Method $method) 24 | { 25 | $this->file = $file; 26 | $this->method = $method; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertConstructorHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Memio\PrettyPrinter\PrettyPrinter; 16 | use Memio\SpecGen\CommandBus\Command; 17 | use Memio\SpecGen\CommandBus\CommandHandler; 18 | 19 | class InsertConstructorHandler implements CommandHandler 20 | { 21 | public const CONSTRUCTOR = '/function __construct\(/'; 22 | public const METHOD = '/^ public function /'; 23 | public const CLASS_ENDING = '/^}$/'; 24 | 25 | private $editor; 26 | private $prettyPrinter; 27 | 28 | public function __construct(Editor $editor, PrettyPrinter $prettyPrinter) 29 | { 30 | $this->editor = $editor; 31 | $this->prettyPrinter = $prettyPrinter; 32 | } 33 | 34 | public function supports(Command $command): bool 35 | { 36 | return $command instanceof InsertConstructor; 37 | } 38 | 39 | public function handle(Command $command): void 40 | { 41 | if ($this->editor->hasBelow($command->file, self::CONSTRUCTOR, 0)) { 42 | return; 43 | } 44 | if ($this->editor->hasBelow($command->file, self::METHOD, 0)) { 45 | $this->editor->jumpBelow($command->file, self::METHOD, 0); 46 | $this->editor->insertAbove($command->file, ''); 47 | } else { 48 | $this->editor->jumpBelow($command->file, self::CLASS_ENDING, 0); 49 | } 50 | $generatedCode = $this->prettyPrinter->generateCode($command->method); 51 | $this->editor->insertAbove($command->file, $generatedCode); 52 | $command->file->decrementCurrentLineNumber(1); 53 | $line = $command->file->getLine(); 54 | if ('{' !== $line && '' !== $line) { 55 | $this->editor->insertBelow($command->file, ''); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertMethod.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\File; 15 | use Memio\Model\Method; 16 | use Memio\SpecGen\CommandBus\Command; 17 | 18 | class InsertMethod implements Command 19 | { 20 | public $file; 21 | public $method; 22 | 23 | public function __construct(File $file, Method $method) 24 | { 25 | $this->file = $file; 26 | $this->method = $method; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertMethodHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Memio\PrettyPrinter\PrettyPrinter; 16 | use Memio\SpecGen\CommandBus\Command; 17 | use Memio\SpecGen\CommandBus\CommandHandler; 18 | 19 | class InsertMethodHandler implements CommandHandler 20 | { 21 | public const CLASS_ENDING = '/^}$/'; 22 | 23 | private $editor; 24 | private $prettyPrinter; 25 | 26 | public function __construct(Editor $editor, PrettyPrinter $prettyPrinter) 27 | { 28 | $this->editor = $editor; 29 | $this->prettyPrinter = $prettyPrinter; 30 | } 31 | 32 | public function supports(Command $command): bool 33 | { 34 | return $command instanceof InsertMethod; 35 | } 36 | 37 | public function handle(Command $command): void 38 | { 39 | $methodPattern = '/^ public function '.$command->method->getName().'\(/'; 40 | if ($this->editor->hasBelow($command->file, $methodPattern, 0)) { 41 | return; 42 | } 43 | $this->editor->jumpBelow($command->file, self::CLASS_ENDING, 0); 44 | $command->file->decrementCurrentLineNumber(1); 45 | $line = trim($command->file->getLine()); 46 | if ('{' !== $line && '' !== $line) { 47 | $this->editor->insertBelow($command->file, ''); 48 | } 49 | $generatedCode = $this->prettyPrinter->generateCode($command->method); 50 | $this->editor->insertBelow($command->file, $generatedCode); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertProperties.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\File; 15 | use Memio\SpecGen\CommandBus\Command; 16 | 17 | class InsertProperties implements Command 18 | { 19 | public $file; 20 | public $properties; 21 | 22 | public function __construct(File $file, array $properties) 23 | { 24 | $this->file = $file; 25 | $this->properties = $properties; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertPropertiesHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Memio\SpecGen\CommandBus\Command; 15 | use Memio\SpecGen\CommandBus\CommandHandler; 16 | 17 | class InsertPropertiesHandler implements CommandHandler 18 | { 19 | private $insertPropertyHandler; 20 | 21 | public function __construct(InsertPropertyHandler $insertPropertyHandler) 22 | { 23 | $this->insertPropertyHandler = $insertPropertyHandler; 24 | } 25 | 26 | public function supports(Command $command): bool 27 | { 28 | return $command instanceof InsertProperties; 29 | } 30 | 31 | public function handle(Command $command): void 32 | { 33 | foreach ($command->properties as $property) { 34 | $this->insertPropertyHandler->handle(new InsertProperty($command->file, $property)); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertProperty.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\File; 15 | use Memio\Model\Property; 16 | use Memio\SpecGen\CommandBus\Command; 17 | 18 | class InsertProperty implements Command 19 | { 20 | public $file; 21 | public $property; 22 | 23 | public function __construct(File $file, Property $property) 24 | { 25 | $this->file = $file; 26 | $this->property = $property; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertPropertyHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Memio\PrettyPrinter\PrettyPrinter; 16 | use Memio\SpecGen\CommandBus\Command; 17 | use Memio\SpecGen\CommandBus\CommandHandler; 18 | 19 | class InsertPropertyHandler implements CommandHandler 20 | { 21 | public const CLASS_OPENING = '/^{$/'; 22 | public const CLASS_ENDING = '/^}$/'; 23 | public const CONSTANT = '/^ const /'; 24 | public const PROPERTY = '/^ private \$/'; 25 | 26 | private $editor; 27 | private $prettyPrinter; 28 | 29 | public function __construct(Editor $editor, PrettyPrinter $prettyPrinter) 30 | { 31 | $this->editor = $editor; 32 | $this->prettyPrinter = $prettyPrinter; 33 | } 34 | 35 | public function supports(Command $command): bool 36 | { 37 | return $command instanceof InsertProperty; 38 | } 39 | 40 | public function handle(Command $command): void 41 | { 42 | $propertyStatement = '/^ private \$'.$command->property->getName().';$/'; 43 | if ($this->editor->hasBelow($command->file, $propertyStatement, 0)) { 44 | return; 45 | } 46 | $hasAnyConstants = $this->editor->hasBelow($command->file, self::CONSTANT, 0); 47 | $hasAnyProperties = $this->editor->hasBelow($command->file, self::PROPERTY, 0); 48 | if ($hasAnyProperties) { 49 | $this->editor->jumpBelow($command->file, self::CLASS_ENDING, 0); 50 | $this->editor->jumpAbove($command->file, self::PROPERTY); 51 | $this->editor->insertBelow($command->file, ''); 52 | } elseif ($hasAnyConstants) { 53 | $this->editor->jumpBelow($command->file, self::CLASS_ENDING, 0); 54 | $this->editor->jumpAbove($command->file, self::CONSTANT); 55 | $this->editor->insertBelow($command->file, ''); 56 | } else { 57 | $this->editor->jumpBelow($command->file, self::CLASS_OPENING, 0); 58 | } 59 | $generatedProperty = $this->prettyPrinter->generateCode($command->property); 60 | $this->editor->insertBelow($command->file, $generatedProperty); 61 | $command->file->incrementCurrentLineNumber(1); 62 | $line = trim($command->file->getLine()); 63 | $hasAnyMethods = ('}' !== $line && '' !== $line); 64 | if ($hasAnyMethods) { 65 | $this->editor->insertAbove($command->file, ''); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertUseStatement.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\File; 15 | use Memio\Model\FullyQualifiedName; 16 | use Memio\SpecGen\CommandBus\Command; 17 | 18 | class InsertUseStatement implements Command 19 | { 20 | public $file; 21 | public $fullyQualifiedName; 22 | 23 | public function __construct(File $file, FullyQualifiedName $fullyQualifiedName) 24 | { 25 | $this->file = $file; 26 | $this->fullyQualifiedName = $fullyQualifiedName; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertUseStatementHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Memio\SpecGen\CommandBus\Command; 16 | use Memio\SpecGen\CommandBus\CommandHandler; 17 | 18 | class InsertUseStatementHandler implements CommandHandler 19 | { 20 | public const CLASS_ENDING = '}'; 21 | public const NAME_SPACE = '/^namespace /'; 22 | public const USE_STATEMENT = '/^use /'; 23 | 24 | private $editor; 25 | 26 | public function __construct(Editor $editor) 27 | { 28 | $this->editor = $editor; 29 | } 30 | 31 | public function supports(Command $command): bool 32 | { 33 | return $command instanceof InsertUseStatement; 34 | } 35 | 36 | public function handle(Command $command): void 37 | { 38 | $namespace = $command->fullyQualifiedName->getNamespace(); 39 | $fullyQualifiedName = $command->fullyQualifiedName->getFullyQualifiedName(); 40 | $namespacePattern = '/^namespace '.addslashes($namespace).';$/'; 41 | $useStatementPattern = '/^use '.addslashes($fullyQualifiedName).';$/'; 42 | if ($this->editor->hasBelow($command->file, $namespacePattern, 0) || $this->editor->hasBelow($command->file, $useStatementPattern, 0)) { 43 | return; 44 | } 45 | $this->editor->jumpBelow($command->file, self::CLASS_ENDING, 0); 46 | if ($this->editor->hasAbove($command->file, self::USE_STATEMENT)) { 47 | $this->editor->jumpAbove($command->file, self::USE_STATEMENT); 48 | } else { 49 | $this->editor->jumpAbove($command->file, self::NAME_SPACE); 50 | $this->editor->insertBelow($command->file, ''); 51 | } 52 | $generatedCode = 'use '.$fullyQualifiedName.';'; 53 | $this->editor->insertBelow($command->file, $generatedCode); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertUseStatements.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\File; 15 | use Memio\SpecGen\CommandBus\Command; 16 | 17 | class InsertUseStatements implements Command 18 | { 19 | public $file; 20 | public $fullyQualifiedNames; 21 | 22 | public function __construct(File $file, array $fullyQualifiedNames) 23 | { 24 | $this->file = $file; 25 | $this->fullyQualifiedNames = $fullyQualifiedNames; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CodeEditor/InsertUseStatementsHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CodeEditor; 13 | 14 | use Gnugat\Redaktilo\Editor; 15 | use Memio\SpecGen\CommandBus\Command; 16 | use Memio\SpecGen\CommandBus\CommandHandler; 17 | 18 | class InsertUseStatementsHandler implements CommandHandler 19 | { 20 | private $editor; 21 | private $insertUseStatementHandler; 22 | 23 | public function __construct( 24 | Editor $editor, 25 | InsertUseStatementHandler $insertUseStatementHandler 26 | ) { 27 | $this->editor = $editor; 28 | $this->insertUseStatementHandler = $insertUseStatementHandler; 29 | } 30 | 31 | public function supports(Command $command): bool 32 | { 33 | return $command instanceof InsertUseStatements; 34 | } 35 | 36 | public function handle(Command $command): void 37 | { 38 | foreach ($command->fullyQualifiedNames as $fullyQualifiedName) { 39 | $escapedFullyQualifiedClassName = addslashes($fullyQualifiedName->getFullyQualifiedName()); 40 | if (!$this->editor->hasBelow($command->file, "/^use $escapedFullyQualifiedClassName;$/", 0)) { 41 | $this->insertUseStatementHandler->handle(new InsertUseStatement($command->file, $fullyQualifiedName)); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CommandBus/Command.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CommandBus; 13 | 14 | /** 15 | * An imperative message. 16 | */ 17 | interface Command 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CommandBus/CommandBus.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CommandBus; 13 | 14 | /** 15 | * Finds the CommandHandler that supports the given command and calls it. 16 | */ 17 | class CommandBus 18 | { 19 | private $commandHandlers = []; 20 | 21 | public function addCommandHandler(CommandHandler $commandHandler): void 22 | { 23 | $this->commandHandlers[] = $commandHandler; 24 | } 25 | 26 | public function handle(Command $command): void 27 | { 28 | foreach ($this->commandHandlers as $commandHandler) { 29 | if ($commandHandler->supports($command)) { 30 | $commandHandler->handle($command); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/CommandBus/CommandHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\CommandBus; 13 | 14 | /** 15 | * Handles a specific Command. 16 | */ 17 | interface CommandHandler 18 | { 19 | public function supports(Command $command): bool; 20 | 21 | public function handle(Command $command): void; 22 | } 23 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/ConstructorGenerator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen; 13 | 14 | use Memio\SpecGen\CommandBus\CommandBus; 15 | use Memio\SpecGen\GenerateConstructor\GenerateConstructor; 16 | use PhpSpec\CodeGenerator\Generator\Generator; 17 | use PhpSpec\Locator\Resource; 18 | 19 | /** 20 | * When phpspec finds an undefined method named "__construct" in a specification, it calls this generator. 21 | */ 22 | class ConstructorGenerator implements Generator 23 | { 24 | private $commandBus; 25 | 26 | public function __construct(CommandBus $commandBus) 27 | { 28 | $this->commandBus = $commandBus; 29 | } 30 | 31 | public function supports( 32 | Resource $resource, 33 | string $generation, 34 | array $data 35 | ): bool { 36 | return 'method' === $generation && '__construct' === $data['name']; 37 | } 38 | 39 | public function generate(Resource $resource, array $data = []): void 40 | { 41 | $generateConstructor = new GenerateConstructor( 42 | $resource->getSrcFilename(), 43 | $resource->getSrcClassName(), 44 | $data['name'], 45 | $data['arguments'] 46 | ); 47 | $this->commandBus->handle($generateConstructor); 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function getPriority(): int 54 | { 55 | return 1; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateConstructor/GenerateConstructor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateConstructor; 13 | 14 | use Memio\SpecGen\CommandBus\Command; 15 | 16 | /** 17 | * Data Transfer Object (DTO). 18 | * 19 | * Information given by phpspec that will allow us to generate a constructor. 20 | */ 21 | class GenerateConstructor implements Command 22 | { 23 | public $fileName; 24 | public $fullyQualifiedName; 25 | public $methodName; 26 | public $arguments; 27 | 28 | public function __construct( 29 | string $fileName, 30 | string $fullyQualifiedName, 31 | string $methodName, 32 | array $arguments 33 | ) { 34 | $this->fileName = $fileName; 35 | $this->fullyQualifiedName = $fullyQualifiedName; 36 | $this->methodName = $methodName; 37 | $this->arguments = $arguments; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateConstructor/GenerateConstructorHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateConstructor; 13 | 14 | use Memio\Model\File; 15 | use Memio\Model\FullyQualifiedName; 16 | use Memio\Model\Method; 17 | use Memio\Model\Objekt; 18 | use Memio\Model\Property; 19 | use Memio\SpecGen\CommandBus\Command; 20 | use Memio\SpecGen\CommandBus\CommandHandler; 21 | use Memio\SpecGen\Marshaller\VariableArgumentMarshaller; 22 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; 23 | 24 | class GenerateConstructorHandler implements CommandHandler 25 | { 26 | private const NON_OBJECT_TYPES = [ 27 | 'string', 28 | 'bool', 29 | 'int', 30 | 'double', 31 | 'callable', 32 | 'resource', 33 | 'array', 34 | 'null', 35 | 'mixed', 36 | ]; 37 | 38 | private $eventDispatcher; 39 | private $variableArgumentMarshaller; 40 | 41 | public function __construct( 42 | EventDispatcherInterface $eventDispatcher, 43 | VariableArgumentMarshaller $variableArgumentMarshaller 44 | ) { 45 | $this->eventDispatcher = $eventDispatcher; 46 | $this->variableArgumentMarshaller = $variableArgumentMarshaller; 47 | } 48 | 49 | public function supports(Command $command): bool 50 | { 51 | return $command instanceof GenerateConstructor; 52 | } 53 | 54 | public function handle(Command $command): void 55 | { 56 | $method = new Method($command->methodName); 57 | $object = Objekt::make($command->fullyQualifiedName)->addMethod($method); 58 | $file = File::make($command->fileName)->setStructure($object); 59 | $arguments = $this->variableArgumentMarshaller->marshal($command->arguments); 60 | foreach ($arguments as $argument) { 61 | $argumentType = $argument->getType(); 62 | $argumentName = $argument->getName(); 63 | $fullyQualifiedName = new FullyQualifiedName($argumentType); 64 | if ($this->shouldAddUseStatement($file, $fullyQualifiedName)) { 65 | $file->addFullyQualifiedName($fullyQualifiedName); 66 | } 67 | $object->addProperty(new Property($argumentName)); 68 | $method->addArgument($argument); 69 | $body = $method->getBody(); 70 | if (!empty($body)) { 71 | $body .= "\n"; 72 | } 73 | $body .= ' $this->'.$argumentName.' = $'.$argumentName.';'; 74 | $method->setBody($body); 75 | } 76 | $generatedConstructor = new GeneratedConstructor($file); 77 | $this->eventDispatcher->dispatch( 78 | $generatedConstructor, 79 | GeneratedConstructor::EVENT_NAME 80 | ); 81 | } 82 | 83 | private function shouldAddUseStatement(File $file, FullyQualifiedName $fullyQualifiedName): bool 84 | { 85 | $type = $fullyQualifiedName->getFullyQualifiedName(); 86 | if (in_array($type, self::NON_OBJECT_TYPES, true)) { 87 | return false; 88 | } 89 | 90 | return true; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateConstructor/GeneratedConstructor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateConstructor; 13 | 14 | use Memio\Model\File; 15 | use Symfony\Contracts\EventDispatcher\Event; 16 | 17 | /** 18 | * Data Transfer Object (DTO). 19 | * 20 | * The built model that describes the constructor. 21 | */ 22 | class GeneratedConstructor extends Event 23 | { 24 | public const EVENT_NAME = 'generated_constructor'; 25 | 26 | public $file; 27 | 28 | public function __construct(File $file) 29 | { 30 | $this->file = $file; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateConstructor/InsertGeneratedConstructorListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateConstructor; 13 | 14 | use Memio\SpecGen\CodeEditor\CodeEditor; 15 | use Memio\SpecGen\CodeEditor\InsertConstructor; 16 | use Memio\SpecGen\CodeEditor\InsertProperties; 17 | use Memio\SpecGen\CodeEditor\InsertUseStatements; 18 | 19 | /** 20 | * As a developer using phpspec, I want generated cosntructors to be saved in my source code. 21 | * 22 | * Given a class I'm specifying 23 | * And a new constructor in it 24 | * When it has been generated 25 | * Then it should be inserted at the begining of the file 26 | * And use statements should be inserted when necessary 27 | * And properties for the constructor's arguments should be inserted 28 | */ 29 | class InsertGeneratedConstructorListener 30 | { 31 | private $codeEditor; 32 | 33 | public function __construct(CodeEditor $codeEditor) 34 | { 35 | $this->codeEditor = $codeEditor; 36 | } 37 | 38 | public function onGeneratedConstructor( 39 | GeneratedConstructor $generatedConstructor 40 | ): void { 41 | $fileName = $generatedConstructor->file->getFilename(); 42 | $fullyQualifiedNames = $generatedConstructor->file->allFullyQualifiedNames(); 43 | $allMethods = $generatedConstructor->file->getStructure()->allMethods(); 44 | $allProperties = $generatedConstructor->file->getStructure()->allProperties(); 45 | $method = array_shift($allMethods); // $object should contain only one method, the generated one. 46 | 47 | $file = $this->codeEditor->open($fileName); 48 | $this->codeEditor->handle(new InsertUseStatements($file, $fullyQualifiedNames)); 49 | $this->codeEditor->handle(new InsertProperties($file, $allProperties)); 50 | $this->codeEditor->handle(new InsertConstructor($file, $method)); 51 | $this->codeEditor->save($file); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateConstructor/LogGeneratedConstructorListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateConstructor; 13 | 14 | use PhpSpec\IO\IO; 15 | 16 | /** 17 | * As a developer using phpspec, I want to know when a constructor has been generated. 18 | * 19 | * Given a new constructor in my specification 20 | * When it has been generated 21 | * Then I should be notified 22 | */ 23 | class LogGeneratedConstructorListener 24 | { 25 | private $io; 26 | 27 | public function __construct(IO $io) 28 | { 29 | $this->io = $io; 30 | } 31 | 32 | public function onGeneratedConstructor( 33 | GeneratedConstructor $generatedConstructor 34 | ): void { 35 | $object = $generatedConstructor->file->getStructure(); 36 | $className = $object->getName(); 37 | $propertiesCount = count($object->allProperties()); 38 | 39 | $propertiesWord = (1 === $propertiesCount ? 'property' : 'properties'); 40 | $this->io->write(<<Generated $propertiesCount $propertiesWord for $className, with its constructor 43 | 44 | OUTPUT 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateMethod/GenerateMethod.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateMethod; 13 | 14 | use Memio\SpecGen\CommandBus\Command; 15 | 16 | /** 17 | * Data Transfer Object (DTO). 18 | * 19 | * Information given by phpspec that will allow us to generate a method. 20 | */ 21 | class GenerateMethod implements Command 22 | { 23 | public $fileName; 24 | public $fullyQualifiedName; 25 | public $methodName; 26 | public $arguments; 27 | 28 | public function __construct( 29 | string $fileName, 30 | string $fullyQualifiedName, 31 | string $methodName, 32 | array $arguments 33 | ) { 34 | $this->fileName = $fileName; 35 | $this->fullyQualifiedName = $fullyQualifiedName; 36 | $this->methodName = $methodName; 37 | $this->arguments = $arguments; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateMethod/GenerateMethodHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateMethod; 13 | 14 | use Memio\Model\File; 15 | use Memio\Model\FullyQualifiedName; 16 | use Memio\Model\Method; 17 | use Memio\Model\Objekt; 18 | use Memio\SpecGen\CommandBus\Command; 19 | use Memio\SpecGen\CommandBus\CommandHandler; 20 | use Memio\SpecGen\Marshaller\VariableArgumentMarshaller; 21 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; 22 | 23 | class GenerateMethodHandler implements CommandHandler 24 | { 25 | private const NON_OBJECT_TYPES = [ 26 | 'string', 27 | 'bool', 28 | 'int', 29 | 'double', 30 | 'callable', 31 | 'resource', 32 | 'array', 33 | 'null', 34 | 'mixed', 35 | ]; 36 | 37 | private $eventDispatcher; 38 | private $variableArgumentMarshaller; 39 | 40 | public function __construct( 41 | EventDispatcherInterface $eventDispatcher, 42 | VariableArgumentMarshaller $variableArgumentMarshaller 43 | ) { 44 | $this->eventDispatcher = $eventDispatcher; 45 | $this->variableArgumentMarshaller = $variableArgumentMarshaller; 46 | } 47 | 48 | public function supports(Command $command): bool 49 | { 50 | return $command instanceof GenerateMethod; 51 | } 52 | 53 | public function handle(Command $command): void 54 | { 55 | $method = new Method($command->methodName); 56 | $file = File::make($command->fileName) 57 | ->setStructure(Objekt::make($command->fullyQualifiedName) 58 | ->addMethod($method) 59 | ) 60 | ; 61 | $arguments = $this->variableArgumentMarshaller->marshal($command->arguments); 62 | foreach ($arguments as $argument) { 63 | $fullyQualifiedName = new FullyQualifiedName($argument->getType()); 64 | if ($this->shouldAddUseStatement($file, $fullyQualifiedName)) { 65 | $file->addFullyQualifiedName($fullyQualifiedName); 66 | } 67 | $method->addArgument($argument); 68 | } 69 | $generatedMethod = new GeneratedMethod($file); 70 | $this->eventDispatcher->dispatch( 71 | $generatedMethod, 72 | GeneratedMethod::EVENT_NAME 73 | ); 74 | } 75 | 76 | private function shouldAddUseStatement(File $file, FullyQualifiedName $fullyQualifiedName): bool 77 | { 78 | $type = $fullyQualifiedName->getFullyQualifiedName(); 79 | if (in_array($type, self::NON_OBJECT_TYPES, true)) { 80 | return false; 81 | } 82 | 83 | return true; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateMethod/GeneratedMethod.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateMethod; 13 | 14 | use Memio\Model\File; 15 | use Symfony\Contracts\EventDispatcher\Event; 16 | 17 | /** 18 | * Data Transfer Object (DTO). 19 | * 20 | * The built model that describes the method. 21 | */ 22 | class GeneratedMethod extends Event 23 | { 24 | public const EVENT_NAME = 'generated_method'; 25 | 26 | public $file; 27 | 28 | public function __construct(File $file) 29 | { 30 | $this->file = $file; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateMethod/InsertGeneratedMethodListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateMethod; 13 | 14 | use Memio\SpecGen\CodeEditor\CodeEditor; 15 | use Memio\SpecGen\CodeEditor\InsertMethod; 16 | use Memio\SpecGen\CodeEditor\InsertUseStatements; 17 | 18 | /** 19 | * As a developer using phpspec, I want generated methods to be saved in my source code. 20 | * 21 | * Given a class I'm specifying 22 | * And a new method in it 23 | * When it has been generated 24 | * Then it should be inserted at the end of the file 25 | * And use statements should be inserted when necessary 26 | */ 27 | class InsertGeneratedMethodListener 28 | { 29 | private $codeEditor; 30 | 31 | public function __construct(CodeEditor $codeEditor) 32 | { 33 | $this->codeEditor = $codeEditor; 34 | } 35 | 36 | public function onGeneratedMethod(GeneratedMethod $generatedMethod): void 37 | { 38 | $fileName = $generatedMethod->file->getFilename(); 39 | $fullyQualifiedNames = $generatedMethod->file->allFullyQualifiedNames(); 40 | $allMethods = $generatedMethod->file->getStructure()->allMethods(); 41 | $method = array_shift($allMethods); // $object should contain only one method, the generated one. 42 | 43 | $file = $this->codeEditor->open($fileName); 44 | $this->codeEditor->handle(new InsertUseStatements($file, $fullyQualifiedNames)); 45 | $this->codeEditor->handle(new InsertMethod($file, $method)); 46 | $this->codeEditor->save($file); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/GenerateMethod/LogGeneratedMethodListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\GenerateMethod; 13 | 14 | use PhpSpec\IO\IO; 15 | 16 | /** 17 | * As a developer using phpspec, I want to know when a method has been generated. 18 | * 19 | * Given a new method in my specification 20 | * When it has been generated 21 | * Then I should be notified 22 | */ 23 | class LogGeneratedMethodListener 24 | { 25 | private $io; 26 | 27 | public function __construct(IO $io) 28 | { 29 | $this->io = $io; 30 | } 31 | 32 | public function onGeneratedMethod(GeneratedMethod $generatedMethod) 33 | { 34 | $object = $generatedMethod->file->getStructure(); 35 | $className = $object->getName(); 36 | $methods = $object->allMethods(); 37 | $method = array_shift($methods); // $object should contain only one method, the generated one. 38 | $methodName = $method->getName(); 39 | 40 | $this->io->write(<<Generated $className#$methodName 43 | 44 | OUTPUT 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/Marshaller/Model/ArgumentCollection.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Marshaller\Model; 13 | 14 | use Memio\Model\Argument; 15 | 16 | class ArgumentCollection 17 | { 18 | private $arguments = []; 19 | private $nameCount = []; 20 | 21 | public function add(string $type, string $name): void 22 | { 23 | $this->nameCount[$name] = (isset($this->nameCount[$name]) ? $this->nameCount[$name] + 1 : 1); 24 | $indexedName = $name.$this->nameCount[$name]; 25 | $isNameDuplicated = ($this->nameCount[$name] > 1); 26 | $this->arguments[] = new Argument($type, $isNameDuplicated ? $indexedName : $name); 27 | if (2 !== $this->nameCount[$name]) { 28 | return; 29 | } 30 | $argumentsCount = count($this->arguments); 31 | for ($i = 0; $i < $argumentsCount; ++$i) { 32 | $argument = $this->arguments[$i]; 33 | if ($argument->getName() === $name) { 34 | $this->arguments[$i] = new Argument($argument->getType(), $name.'1'); 35 | break; 36 | } 37 | } 38 | } 39 | 40 | public function all(): array 41 | { 42 | return $this->arguments; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/Marshaller/Service/NameGuesser.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Marshaller\Service; 13 | 14 | class NameGuesser 15 | { 16 | private const NON_OBJECT_TYPES = [ 17 | 'string', 18 | 'bool', 19 | 'int', 20 | 'double', 21 | 'callable', 22 | 'resource', 23 | 'array', 24 | 'null', 25 | 'mixed', 26 | ]; 27 | 28 | public function guess(string $type): string 29 | { 30 | if (in_array($type, self::NON_OBJECT_TYPES, true)) { 31 | return 'argument'; 32 | } 33 | $nameSpaceBits = explode('\\', $type); 34 | $name = lcfirst(end($nameSpaceBits)); 35 | $interfaceSuffixPosition = strpos($name, 'Interface'); 36 | $hasInterfaceSuffix = (false !== $interfaceSuffixPosition && 0 < $interfaceSuffixPosition); 37 | if (!$hasInterfaceSuffix) { 38 | return $name; 39 | } 40 | 41 | return substr($name, 0, $interfaceSuffixPosition); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/Marshaller/Service/TypeGuesser.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Marshaller\Service; 13 | 14 | use Prophecy\Doubler\Generator\ReflectionInterface; 15 | use Prophecy\Prophecy\ProphecySubjectInterface; 16 | 17 | class TypeGuesser 18 | { 19 | public function guess($variable): string 20 | { 21 | if (is_callable($variable)) { 22 | return 'callable'; 23 | } 24 | if (!is_object($variable)) { 25 | return $this->getNonObjectType($variable); 26 | } 27 | $interfaces = class_implements($variable); 28 | unset($interfaces[ProphecySubjectInterface::class]); 29 | unset($interfaces[ReflectionInterface::class]); 30 | $interface = current($interfaces); 31 | if (false !== $interface) { 32 | return $interface; 33 | } 34 | if ($variable instanceof ProphecySubjectInterface) { 35 | return get_parent_class($variable); 36 | } 37 | 38 | return get_class($variable); 39 | } 40 | 41 | private function getNonObjectType($variable): string 42 | { 43 | $normalizations = [ 44 | 'boolean' => 'bool', 45 | 'integer' => 'int', 46 | 'NULL' => 'null', 47 | ]; 48 | $type = gettype($variable); 49 | if (isset($normalizations[$type])) { 50 | $type = $normalizations[$type]; 51 | } 52 | 53 | return $type; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/Marshaller/VariableArgumentMarshaller.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen\Marshaller; 13 | 14 | use Memio\SpecGen\Marshaller\Model\ArgumentCollection; 15 | use Memio\SpecGen\Marshaller\Service\NameGuesser; 16 | use Memio\SpecGen\Marshaller\Service\TypeGuesser; 17 | 18 | class VariableArgumentMarshaller 19 | { 20 | private $nameGuesser; 21 | private $typeGuesser; 22 | 23 | public function __construct(NameGuesser $nameGuesser, TypeGuesser $typeGuesser) 24 | { 25 | $this->nameGuesser = $nameGuesser; 26 | $this->typeGuesser = $typeGuesser; 27 | } 28 | 29 | public function marshal(array $variables): array 30 | { 31 | $argumentCollection = new ArgumentCollection(); 32 | foreach ($variables as $variable) { 33 | $type = $this->typeGuesser->guess($variable); 34 | $name = $this->nameGuesser->guess($type); 35 | $argumentCollection->add($type, $name); 36 | } 37 | 38 | return $argumentCollection->all(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/MemioSpecGenExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen; 13 | 14 | use Memio\SpecGen\GenerateConstructor\GeneratedConstructor; 15 | use Memio\SpecGen\GenerateMethod\GeneratedMethod; 16 | use PhpSpec\Extension; 17 | use PhpSpec\ServiceContainer; 18 | 19 | /** 20 | * Adding to phpspec's Dependency Injection Container Memio SpecGen's services. 21 | * 22 | * Here we over write phpspec's generators by ours. 23 | */ 24 | class MemioSpecGenExtension implements Extension 25 | { 26 | private const CODE_GENERATOR_TAG = ['code_generator.generators']; 27 | 28 | public function load(ServiceContainer $container, array $params): void 29 | { 30 | $this->defineSharedServices($container); 31 | $this->defineCodeEditor($container); 32 | $this->defineGenerateConstructorHandler($container); 33 | $this->defineGenerateMethodHandler($container); 34 | $this->defineGenerators($container); 35 | } 36 | 37 | private function defineSharedServices(ServiceContainer $container): void 38 | { 39 | $container->define('redaktilo.editor', function () { 40 | return \Gnugat\Redaktilo\EditorFactory::createEditor(); 41 | }); 42 | $container->define('memio.pretty_printer', function () { 43 | return \Memio\Memio\Config\Build::prettyPrinter(); 44 | }); 45 | $container->define('memio_spec_gen.event_dispatcher', function (ServiceContainer $container) { 46 | return new \Symfony\Component\EventDispatcher\EventDispatcher(); 47 | }); 48 | $container->define('memio_spec_gen.command_bus', function (ServiceContainer $container) { 49 | return new \Memio\SpecGen\CommandBus\CommandBus(); 50 | }); 51 | $container->define('memio_spec_gen.variable_argument_marshaller', function (ServiceContainer $container) { 52 | return new \Memio\SpecGen\Marshaller\VariableArgumentMarshaller( 53 | new \Memio\SpecGen\Marshaller\Service\NameGuesser(), 54 | new \Memio\SpecGen\Marshaller\Service\TypeGuesser() 55 | ); 56 | }); 57 | } 58 | 59 | private function defineCodeEditor(ServiceContainer $container): void 60 | { 61 | $container->define('memio_spec_gen.code_editor', function (ServiceContainer $container) { 62 | $editor = $container->get('redaktilo.editor'); 63 | $prettyPrinter = $container->get('memio.pretty_printer'); 64 | 65 | $insertConstructorHandler = new \Memio\SpecGen\CodeEditor\InsertConstructorHandler($editor, $prettyPrinter); 66 | $insertMethodHandler = new \Memio\SpecGen\CodeEditor\InsertMethodHandler($editor, $prettyPrinter); 67 | $insertUseStatementHandler = new \Memio\SpecGen\CodeEditor\InsertUseStatementHandler( 68 | $editor, 69 | $prettyPrinter 70 | ); 71 | $insertUseStatementsHandler = new \Memio\SpecGen\CodeEditor\InsertUseStatementsHandler( 72 | $editor, 73 | $insertUseStatementHandler 74 | ); 75 | $insertPropertyHandler = new \Memio\SpecGen\CodeEditor\InsertPropertyHandler( 76 | $editor, 77 | $prettyPrinter 78 | ); 79 | $insertPropertiesHandler = new \Memio\SpecGen\CodeEditor\InsertPropertiesHandler( 80 | $insertPropertyHandler 81 | ); 82 | 83 | $commandBus = new \Memio\SpecGen\CommandBus\CommandBus(); 84 | $commandBus->addCommandHandler($insertConstructorHandler); 85 | $commandBus->addCommandHandler($insertMethodHandler); 86 | $commandBus->addCommandHandler($insertUseStatementHandler); 87 | $commandBus->addCommandHandler($insertUseStatementsHandler); 88 | $commandBus->addCommandHandler($insertPropertyHandler); 89 | $commandBus->addCommandHandler($insertPropertiesHandler); 90 | 91 | return new \Memio\SpecGen\CodeEditor\CodeEditor($commandBus, $editor); 92 | }); 93 | } 94 | 95 | private function defineGenerateConstructorHandler(ServiceContainer $container): void 96 | { 97 | $eventDispatcher = $container->get('memio_spec_gen.event_dispatcher'); 98 | $commandBus = $container->get('memio_spec_gen.command_bus'); 99 | 100 | $insertGeneratedConstructorListener = new \Memio\SpecGen\GenerateConstructor\InsertGeneratedConstructorListener( 101 | $container->get('memio_spec_gen.code_editor'), 102 | $container->get('memio.pretty_printer') 103 | ); 104 | $logGeneratedConstructorListener = new \Memio\SpecGen\GenerateConstructor\LogGeneratedConstructorListener( 105 | $container->get('console.io') 106 | ); 107 | $eventDispatcher->addListener(GeneratedConstructor::EVENT_NAME, [$insertGeneratedConstructorListener, 'onGeneratedConstructor']); 108 | $eventDispatcher->addListener(GeneratedConstructor::EVENT_NAME, [$logGeneratedConstructorListener, 'onGeneratedConstructor']); 109 | 110 | $generateConstructorHandler = new \Memio\SpecGen\GenerateConstructor\GenerateConstructorHandler( 111 | $container->get('memio_spec_gen.event_dispatcher'), 112 | $container->get('memio_spec_gen.variable_argument_marshaller') 113 | ); 114 | $commandBus->addCommandHandler($generateConstructorHandler); 115 | } 116 | 117 | private function defineGenerateMethodHandler(ServiceContainer $container): void 118 | { 119 | $eventDispatcher = $container->get('memio_spec_gen.event_dispatcher'); 120 | $commandBus = $container->get('memio_spec_gen.command_bus'); 121 | 122 | $insertGeneratedMethodListener = new \Memio\SpecGen\GenerateMethod\InsertGeneratedMethodListener( 123 | $container->get('memio_spec_gen.code_editor'), 124 | $container->get('memio.pretty_printer') 125 | ); 126 | $logGeneratedMethodListener = new \Memio\SpecGen\GenerateMethod\LogGeneratedMethodListener( 127 | $container->get('console.io') 128 | ); 129 | $eventDispatcher->addListener(GeneratedMethod::EVENT_NAME, [$insertGeneratedMethodListener, 'onGeneratedMethod']); 130 | $eventDispatcher->addListener(GeneratedMethod::EVENT_NAME, [$logGeneratedMethodListener, 'onGeneratedMethod']); 131 | 132 | $generateMethodHandler = new \Memio\SpecGen\GenerateMethod\GenerateMethodHandler( 133 | $container->get('memio_spec_gen.event_dispatcher'), 134 | $container->get('memio_spec_gen.variable_argument_marshaller') 135 | ); 136 | $commandBus->addCommandHandler($generateMethodHandler); 137 | } 138 | 139 | private function defineGenerators(ServiceContainer $container): void 140 | { 141 | $container->define('code_generator.generators.method', function (ServiceContainer $container) { 142 | return new \Memio\SpecGen\MethodGenerator($container->get('memio_spec_gen.command_bus')); 143 | }, self::CODE_GENERATOR_TAG); 144 | $container->define('code_generator.generators.constructor', function (ServiceContainer $container) { 145 | return new \Memio\SpecGen\ConstructorGenerator($container->get('memio_spec_gen.command_bus')); 146 | }, self::CODE_GENERATOR_TAG); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/Memio/SpecGen/MethodGenerator.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Memio\SpecGen; 13 | 14 | use Memio\SpecGen\CommandBus\CommandBus; 15 | use Memio\SpecGen\GenerateMethod\GenerateMethod; 16 | use PhpSpec\CodeGenerator\Generator\Generator; 17 | use PhpSpec\Locator\Resource; 18 | 19 | /** 20 | * When phpspec finds an undefined method in a specification, it calls this generator. 21 | */ 22 | class MethodGenerator implements Generator 23 | { 24 | private $commandBus; 25 | 26 | public function __construct(CommandBus $commandBus) 27 | { 28 | $this->commandBus = $commandBus; 29 | } 30 | 31 | public function supports(Resource $resource, string $generation, array $data): bool 32 | { 33 | return 'method' === $generation; 34 | } 35 | 36 | public function generate(Resource $resource, array $data = []): void 37 | { 38 | $generateMethod = new GenerateMethod( 39 | $resource->getSrcFilename(), 40 | $resource->getSrcClassName(), 41 | $data['name'], 42 | $data['arguments'] 43 | ); 44 | $this->commandBus->handle($generateMethod); 45 | } 46 | 47 | public function getPriority(): int 48 | { 49 | return 0; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/Memio/SpecGen/Build.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace tests\Memio\SpecGen; 13 | 14 | use Memio\SpecGen\MemioSpecGenExtension; 15 | use PhpSpec\ServiceContainer; 16 | use PhpSpec\ServiceContainer\IndexedServiceContainer; 17 | 18 | class Build 19 | { 20 | private static $serviceContainer; 21 | 22 | public static function serviceContainer(): ServiceContainer 23 | { 24 | if (null === self::$serviceContainer) { 25 | self::$serviceContainer = new IndexedServiceContainer(); 26 | 27 | self::$serviceContainer->define('console.io', function (ServiceContainer $container) { 28 | return new NullIO(); 29 | }); 30 | 31 | $memioSpecGenExtension = new MemioSpecGenExtension(); 32 | $memioSpecGenExtension->load(self::$serviceContainer, []); 33 | } 34 | 35 | return self::$serviceContainer; 36 | } 37 | 38 | public static function fixtures(): void 39 | { 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Memio/SpecGen/Generator/GenerateConstructorTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace tests\Memio\SpecGen\Generator; 13 | 14 | use PhpSpec\Locator\Resource; 15 | use tests\Memio\SpecGen\Build; 16 | use tests\Memio\SpecGen\GeneratorTestCase; 17 | 18 | class GenerateConstructorTest extends GeneratorTestCase 19 | { 20 | private const NAME_SPACE = 'Vendor\Project'; 21 | private const CLASS_NAME = 'Vendor\Project\MyClass'; 22 | 23 | private $constructorGenerator; 24 | 25 | protected function setUp(): void 26 | { 27 | $this->constructorGenerator = Build::serviceContainer()->get('code_generator.generators.constructor'); 28 | } 29 | 30 | /** 31 | * @test 32 | */ 33 | public function it_inserts_constructor_at_the_begining_of_the_class() 34 | { 35 | $filename = $this->getFixtureFilename(); 36 | 37 | $resource = $this->prophesize(Resource::class); 38 | $resource->getSrcFilename()->willReturn($filename); 39 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 40 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 41 | 42 | $this->constructorGenerator->generate($resource->reveal(), [ 43 | 'name' => '__construct', 44 | 'arguments' => [], 45 | ]); 46 | 47 | $this->assertExpectedCode($filename); 48 | } 49 | 50 | /** 51 | * @test 52 | */ 53 | public function it_inserts_properties_with_initialization_for_each_constructor_arguments() 54 | { 55 | $filename = $this->getFixtureFilename(); 56 | 57 | $resource = $this->prophesize(Resource::class); 58 | $resource->getSrcFilename()->willReturn($filename); 59 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 60 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 61 | 62 | $this->constructorGenerator->generate($resource->reveal(), [ 63 | 'name' => '__construct', 64 | 'arguments' => [ 65 | new \DateTime(), 66 | ], 67 | ]); 68 | 69 | $this->assertExpectedCode($filename); 70 | } 71 | 72 | /** 73 | * @test 74 | */ 75 | public function it_prevents_constructor_to_use_a_special_class_name() 76 | { 77 | $filename = $this->getFixtureFilename(); 78 | 79 | $resource = $this->prophesize(Resource::class); 80 | $resource->getSrcFilename()->willReturn($filename); 81 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 82 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 83 | 84 | $this->constructorGenerator->generate($resource->reveal(), [ 85 | 'name' => '__construct', 86 | 'arguments' => [ 87 | 77, 88 | 3.14, 89 | 'letsgoboys', 90 | true, 91 | ], 92 | ]); 93 | 94 | $this->assertExpectedCode($filename); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /tests/Memio/SpecGen/Generator/GenerateMethodTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace tests\Memio\SpecGen\Generator; 13 | 14 | use PhpSpec\Locator\Resource; 15 | use tests\Memio\SpecGen\Build; 16 | use tests\Memio\SpecGen\GeneratorTestCase; 17 | 18 | class GenerateMethodTest extends GeneratorTestCase 19 | { 20 | private const NAME_SPACE = 'Vendor\Project'; 21 | private const CLASS_NAME = 'Vendor\Project\MyClass'; 22 | 23 | private $methodGenerator; 24 | 25 | protected function setUp(): void 26 | { 27 | $this->methodGenerator = Build::serviceContainer()->get('code_generator.generators.method'); 28 | } 29 | 30 | /** 31 | * @test 32 | */ 33 | public function it_inserts_method_at_the_end_of_the_class() 34 | { 35 | $filename = $this->getFixtureFilename(); 36 | 37 | $resource = $this->prophesize(Resource::class); 38 | $resource->getSrcFilename()->willReturn($filename); 39 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 40 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 41 | 42 | $this->methodGenerator->generate($resource->reveal(), [ 43 | 'name' => 'myMethod', 44 | 'arguments' => [], 45 | ]); 46 | 47 | $this->assertExpectedCode($filename); 48 | } 49 | 50 | /** 51 | * @test 52 | */ 53 | public function it_type_hints_arguments() 54 | { 55 | $filename = $this->getFixtureFilename(); 56 | 57 | $resource = $this->prophesize(Resource::class); 58 | $resource->getSrcFilename()->willReturn($filename); 59 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 60 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 61 | 62 | $this->methodGenerator->generate($resource->reveal(), [ 63 | 'name' => 'myMethod', 64 | 'arguments' => [ 65 | new \DateTime(), 66 | [], 67 | 'string', 68 | ], 69 | ]); 70 | 71 | $this->assertExpectedCode($filename); 72 | } 73 | 74 | /** 75 | * @test 76 | */ 77 | public function it_names_object_argument_after_their_type() 78 | { 79 | $filename = $this->getFixtureFilename(); 80 | 81 | $resource = $this->prophesize(Resource::class); 82 | $resource->getSrcFilename()->willReturn($filename); 83 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 84 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 85 | 86 | $this->methodGenerator->generate($resource->reveal(), [ 87 | 'name' => 'myMethod', 88 | 'arguments' => [ 89 | new \DateTime(), 90 | ], 91 | ]); 92 | 93 | $this->assertExpectedCode($filename); 94 | } 95 | 96 | /** 97 | * @test 98 | */ 99 | public function it_prevents_methods_to_be_longer_than_120_characters() 100 | { 101 | $filename = $this->getFixtureFilename(); 102 | 103 | $resource = $this->prophesize(Resource::class); 104 | $resource->getSrcFilename()->willReturn($filename); 105 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 106 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 107 | 108 | $this->methodGenerator->generate($resource->reveal(), [ 109 | 'name' => 'myMethod', 110 | 'arguments' => [1, 2, 3, 4, 5, 6, 7, 8], 111 | ]); 112 | 113 | $this->assertExpectedCode($filename); 114 | } 115 | 116 | /** 117 | * @test 118 | */ 119 | public function it_prevents_methods_to_use_a_special_class_name() 120 | { 121 | $filename = $this->getFixtureFilename(); 122 | 123 | $resource = $this->prophesize(Resource::class); 124 | $resource->getSrcFilename()->willReturn($filename); 125 | $resource->getSrcNamespace()->willReturn(self::NAME_SPACE); 126 | $resource->getSrcClassname()->willReturn(self::CLASS_NAME); 127 | 128 | $this->methodGenerator->generate($resource->reveal(), [ 129 | 'name' => 'myMethod', 130 | 'arguments' => ['string', 1.1, 1, true], 131 | ]); 132 | 133 | $this->assertExpectedCode($filename); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /tests/Memio/SpecGen/GeneratorTestCase.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace tests\Memio\SpecGen; 13 | 14 | use PHPUnit\Framework\TestCase; 15 | 16 | class GeneratorTestCase extends TestCase 17 | { 18 | protected function getFixtureFilename(): string 19 | { 20 | $path = $this->getPath(); 21 | $method = $this->getMethod(); 22 | $skeletonFilename = __DIR__.'/../../../fixtures/skeleton/'.$path.'/'.$method.'.txt'; 23 | $filename = __DIR__.'/../../../fixtures/actual/'.$path.'/'.$method.'.txt'; 24 | if (file_exists($filename)) { 25 | unlink($filename); 26 | } 27 | copy($skeletonFilename, $filename); 28 | 29 | return $filename; 30 | } 31 | 32 | protected function assertExpectedCode(string $actualFilename) 33 | { 34 | $expectedFilename = __DIR__.'/../../../fixtures/expected/'.$this->getPath().'/'.$this->getMethod().'.txt'; 35 | 36 | $this->assertFileEquals($expectedFilename, $actualFilename); 37 | } 38 | 39 | private function getPath(): string 40 | { 41 | $trace = debug_backtrace(); 42 | $testFqcn = $trace[2]['class']; 43 | $type = substr($testFqcn, strlen('Memio\SpecGen\Tests\Generator\\')); 44 | 45 | return str_replace('\\', '/', $type); 46 | } 47 | 48 | private function getMethod(): string 49 | { 50 | $trace = debug_backtrace(); 51 | 52 | return $trace[2]['function']; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/Memio/SpecGen/NullIO.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace tests\Memio\SpecGen; 13 | 14 | use PhpSpec\IO\IO; 15 | 16 | class NullIO implements IO 17 | { 18 | public function write(string $message): void 19 | { 20 | } 21 | 22 | public function isVerbose(): bool 23 | { 24 | return false; 25 | } 26 | } 27 | --------------------------------------------------------------------------------