Merge branch 'emilybache:main' into main

This commit is contained in:
uivraeus 2023-02-20 12:45:26 +01:00 committed by GitHub
commit 317d04c61d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 374 additions and 6667 deletions

View File

@ -1,17 +0,0 @@
exclude:
- /js/lib/.*
component_depth: 1
languages:
- cpp
- csharp
- go
- groovy
- java
- javascript
- perl
- php
- python
- ruby
- scala
- script
- swift

39
.github/workflows/jq.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: jq
on:
pull_request:
branches:
- main
paths:
- jq/*
jobs:
test-jq-translation:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Rust Toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
# TODO: this step takes ~2m, consider using https://github.com/marketplace/actions/cargo-install
- name: Install jaq
run: |
cargo install --locked --git https://github.com/01mf02/jaq
- name: Expect unit test to fail
working-directory: jq
run: |
! ./test-gilded-rose.sh
- name: Expect texttest fixture output (aka 'verify')
working-directory: jq
run: |
jaq --arg days 31 -nr "$(cat gilded-rose.jq) $(cat texttest_fixture.jq)" |
diff - ../texttests/ThirtyDays/stdout.gr

View File

@ -2,7 +2,7 @@
Bonjour et bienvenue dans l'équipe de la Rose dorée.
Comme vous le savez, notre petite taverne située à proximité d'une cité importante est dirigée par l'amicale aubergiste Allison.
Comme vous le savez, notre petite taverne située à proximité d'une cité importante est dirigée par l'aubergiste amicale Allison.
Nous achetons et vendons uniquement les meilleurs produits.
Malheureusement, la qualité de nos marchandises se dégrade constamment à l'approche de leur date de péremption.
@ -36,6 +36,6 @@ Cela nécessite une mise à jour de notre système :
Vous pouvez faire les changements que vous voulez à la méthode `updateQuality` et ajouter autant de code que vous voulez, tant que tout fonctionne correctement.
Cependant, nous devons vous prévenir, vous ne devez en aucun cas modifier la classe `Item` ou ses propriétés car cette classe appartient au gobelin à l'étage qui entrerait dans une rage instantanée et vous tuerait sans délai : il ne croit pas au partage du code.
(Vous pouvez ajouter rendre la méthode `updateQuality` statique, ainsi que des propriétés dans la classe `Item` si vous voulez, nous vous couvrirons)
(Vous pouvez rendre la méthode `updateQuality` statique, ainsi que des propriétés dans la classe `Item` si vous voulez, nous vous couvrirons)
Juste une précision, un produit ne peut jamais voir sa qualité augmenter au-dessus de 50, cependant "Sulfuras" est un objet légendaire et comme tel sa qualité est de 80 et elle ne change jamais.

View File

@ -22,7 +22,7 @@
- "**Aged Brie**"(오래된 브리치즈)은(는) 시간이 지날수록 `Quality` 값이 올라갑니다.
- `Quality` 값은 50를 초과 할 수 없습니다.
- `Sulfuras`는 전설의 아이템이므로, 반드시 판매될 필요도 없고 `Quality` 값도 떨어지지 않습니다.
- "**Backstage passes**(백스테이지 입장권)"는 "**Aged Brie**"와 유사하게 `SellIn` 값에 가까워 질수록 `Quality` 값이 상승하고, **10일 전**까지는 매일 *2* 씩 증가하다, **5일 전**이 되면 매일 *3* 씩 증가하지만, 콘서트 종료 후에는 *0*으로 떨어집니다.
- "**Backstage passes**(백스테이지 입장권)"는 "**Aged Brie**"와 유사하게 `SellIn` 값에 가까워 질수록 `Quality` 값이 상승하고, **10일 부터는** 매일 *2* 씩 증가하다, **5일 부터는**이 되면 매일 *3* 씩 증가하지만, 콘서트 종료 후에는 *0*으로 떨어집니다.
## 시스템 업데이트 요구 사항
@ -34,4 +34,4 @@
이것들은 저기 구석에있는 고블린의 것이고, 그 친구는 코드의 공유 소유권을 믿지 않기 때문에, 미친듯이 화를 내며(insta-rage) 여러분에게 한 방(one-shot)을 날릴 수도 있습니다. (`UpdateQuality()` 메서드와 `Items` 속성을 정적(static)으로 만드는 것은 괜찮습니다. 저희가 책임질게요.)
다시 한 번 확인하자면, 아이템의 `Quality`는 50 이상으로 증가할 수는 없습니다. 하지만 `Sulfuras`는 전설의 아이템이기 때문에 `Quality` 값은 80이며, 값이 바뀌지 않습니다.
다시 한 번 확인하자면, 아이템의 `Quality`는 50 이상으로 증가할 수는 없습니다. 하지만 `Sulfuras`는 전설의 아이템이기 때문에 `Quality` 값은 80이며, 값이 바뀌지 않습니다.

15
Java/README.md Normal file
View File

@ -0,0 +1,15 @@
# Gilded Rose starting position in Java
## Run the Text Fixture from Command-Line
```
./gradlew -q text
```
### Specify Number of Days
For e.g. 10 days:
```
./gradlew -q text --args 10
```

View File

@ -19,3 +19,9 @@ sourceCompatibility = '1.8'
test {
useJUnitPlatform()
}
task texttest(type: JavaExec) {
main = "com.gildedrose.TexttestFixture"
classpath = sourceSets.test.runtimeClasspath
args "30"
}

View File

@ -1,10 +1,10 @@
# Gilded Rose Refactoring Kata
This Kata was originally created by Terry Hughes (http://twitter.com/TerryHughes). It is already on GitHub [here](https://github.com/NotMyself/GildedRose). See also [Bobby Johnson's description of the kata](http://iamnotmyself.com/2011/02/13/refactor-this-the-gilded-rose-kata/).
This Kata was originally created by Terry Hughes (http://twitter.com/TerryHughes). It is already on GitHub [here](https://github.com/NotMyself/GildedRose). See also [Bobby Johnson's description of the kata](https://iamnotmyself.com/refactor-this-the-gilded-rose-kata/).
I translated the original C# into a few other languages, (with a little help from my friends!), and slightly changed the starting position. This means I've actually done a small amount of refactoring already compared with the original form of the kata, and made it easier to get going with writing tests by giving you one failing unit test to start with. I also added test fixtures for Text-Based approval testing with TextTest (see [the TextTests](https://github.com/emilybache/GildedRose-Refactoring-Kata/tree/master/texttests))
As Bobby Johnson points out in his article ["Why Most Solutions to Gilded Rose Miss The Bigger Picture"](http://iamnotmyself.com/2012/12/07/why-most-solutions-to-gilded-rose-miss-the-bigger-picture), it'll actually give you
As Bobby Johnson points out in his article ["Why Most Solutions to Gilded Rose Miss The Bigger Picture"](https://iamnotmyself.com/why-most-solutions-to-gilded-rose-miss-the-bigger-picture/), it'll actually give you
better practice at handling a legacy code situation if you do this Kata in the original C#. However, I think this kata
is also really useful for practicing writing good tests using different frameworks and approaches, and the small changes I've made help with that. I think it's also interesting to compare what the refactored code and tests look like in different programming languages.
@ -35,7 +35,7 @@ Whichever testing approach you choose, the idea of the exercise is to do some de
## Text-Based Approval Testing
This code comes with comprehensive tests that use this approach. For information about how to run them, see the [texttests README](https://github.com/emilybache/GildedRose-Refactoring-Kata/tree/master/texttests)
Most language versions of this code have a [TextTest](https://texttest.org) fixture for Approval testing. For information about this, see the [TextTests README](https://github.com/emilybache/GildedRose-Refactoring-Kata/tree/master/texttests)
## Translating this code
@ -51,8 +51,3 @@ Please don't write too much code in the starting position or add too many unit t
If your programming language doesn't have an easy way to add a command-line interface, then the TextTest fixture is probably not necessary.
## Better Code Hub
I analysed this repo according to the clean code standards on [Better Code Hub](https://bettercodehub.com) just to get an independent opinion of how bad the code is. Perhaps unsurprisingly, the compliance score is low!
[![BCH compliance](https://bettercodehub.com/edge/badge/emilybache/GildedRose-Refactoring-Kata?branch=master)](https://bettercodehub.com/)

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<StartupObject>GildedRoseKata.Program</StartupObject>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>

View File

@ -0,0 +1,7 @@
{
"sdk": {
"version": "7.0.0",
"rollForward": "latestMajor",
"allowPrerelease": true
}
}

21
jq/README.md Normal file
View File

@ -0,0 +1,21 @@
# Installs
[install jaq](https://github.com/01mf02/jaq#installation) (latest development version)
# Failing Unit Test
```shell
./test-gilded-rose.sh
```
# TextTest Fixture
```shell
jaq -nr "$(cat gilded-rose.jq) $(cat texttest_fixture.jq)"
```
Specify days (e.g. 10 days):
```shell
jaq --arg days 10 -nr "$(cat gilded-rose.jq) $(cat texttest_fixture.jq)"
```

54
jq/gilded-rose.jq Normal file
View File

@ -0,0 +1,54 @@
def update_quality:
[
foreach .[] as $item (
null;
$item |
if .name != "Aged Brie" and .name != "Backstage passes to a TAFKAL80ETC concert" then
if .quality > 0 then
if .name != "Sulfuras, Hand of Ragnaros" then
.quality = .quality - 1
else . end
else . end
else
if .quality < 50 then
.quality = .quality + 1
|
if .name == "Backstage passes to a TAFKAL80ETC concert" then
if .sell_in < 11 then
if .quality < 50 then
.quality = .quality + 1
else . end
else . end
|
if .sell_in < 6 then
if .quality < 50 then
.quality = .quality + 1
else . end
else . end
else . end
else . end
end
|
if .name != "Sulfuras, Hand of Ragnaros" then
.sell_in = .sell_in - 1
else . end
|
if .sell_in < 0 then
if .name != "Aged Brie" then
if .name != "Backstage passes to a TAFKAL80ETC concert" then
if .quality > 0 then
if .name != "Sulfuras, Hand of Ragnaros" then
.quality = .quality - 1
else . end
else . end
else
.quality = .quality - .quality
end
else
if .quality < 50 then
.quality = .quality + 1
else . end
end
else . end
)
];

3
jq/test-gilded-rose.sh Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
jaq -en "$(cat gilded-rose.jq)"'[{name:"foo",sell_in:0,quality:0}] | update_quality | .[].name == "fixme"'

22
jq/texttest_fixture.jq Normal file
View File

@ -0,0 +1,22 @@
"OMGHAI!",
(
[
{ name: "+5 Dexterity Vest", sell_in: 10, quality: 20 },
{ name: "Aged Brie", sell_in: 2, quality: 0 },
{ name: "Elixir of the Mongoose", sell_in: 5, quality: 7 },
{ name: "Sulfuras, Hand of Ragnaros", sell_in: 0, quality: 80 },
{ name: "Sulfuras, Hand of Ragnaros", sell_in: -1, quality: 80 },
{ name: "Backstage passes to a TAFKAL80ETC concert", sell_in: 15, quality: 20 },
{ name: "Backstage passes to a TAFKAL80ETC concert", sell_in: 10, quality: 49 },
{ name: "Backstage passes to a TAFKAL80ETC concert", sell_in: 5, quality: 49 },
{ name: "Conjured Mana Cake", sell_in: 3, quality: 6} # <-- :O
] |
{ items: ., day: 0 } |
recurse(.day += 1 | .items = (.items | update_quality); .day < ($ARGS.named.days // 2 | tonumber)) |
(
(["-------- day ", (.day | tostring), " --------"] | add),
("name, sellIn, quality"),
(.items[] | [.name, .sell_in, .quality | tostring] | join(", ")),
""
)
)

5
julia/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.jl.*.cov
*.jl.cov
*.jl.mem
/Manifest.toml
/docs/build/

89
julia/gilded_rose.jl Normal file
View File

@ -0,0 +1,89 @@
import Base
mutable struct Item{T<:Integer}
name::String
sellin::T
quality::T
end
Base.show(io::IO, x::Item) = print(io, "$(x.name), $(x.sellin), $(x.quality)")
struct GildedRose
items
end
function update_quality!(gr::GildedRose)
for item in gr.items
if item.name != "Aged Brie" && item.name != "Backstage passes to a TAFKAL80ETC concert"
if item.quality > 0
if item.name != "Sulfuras, Hand of Ragnaros"
item.quality = item.quality - 1
end
end
else
if item.quality < 50
item.quality = item.quality + 1
if item.name == "Backstage passes to a TAFKAL80ETC concert"
if item.sellin < 11
if item.quality < 50
item.quality = item.quality + 1
end
end
if item.sellin < 6
if item.quality < 50
item.quality = item.quality + 1
end
end
end
end
end
if item.name != "Sulfuras, Hand of Ragnaros"
item.sellin = item.sellin - 1
end
if item.sellin < 0
if item.name != "Aged Brie"
if item.name != "Backstage passes to a TAFKAL80ETC concert"
if item.quality > 0
if item.name != "Sulfuras, Hand of Ragnaros"
item.quality = item.quality - 1
end
end
else
item.quality = item.quality - item.quality
end
else
if item.quality < 50
item.quality = item.quality + 1
end
end
end
end
return nothing
end
# Technically, julia espouses a REPL-driven workflow, so the preferred way to run this
# would be from the REPL. However, if you'd like to run this function from the
# commandline, run `$ julia -e 'include("gilded_rose.jl"); main(;days=3)'` or whatever
# number you want for `days`.
function main(; days::Int64=2)
println("OMGHAI!")
items = [
Item("+5 Dexterity Vest", 10, 20),
Item("Aged Brie", 2, 0),
Item("Elixir of the Mongoose", 5, 7),
Item("Sulfuras, Hand of Ragnaros", 0, 80),
Item("Sulfuras, Hand of Ragnaros", -1, 80),
Item("Backstage passes to a TAFKAL80ETC concert", 15, 20),
Item("Backstage passes to a TAFKAL80ETC concert", 10, 49),
Item("Backstage passes to a TAFKAL80ETC concert", 5, 49),
Item("Conjured Mana Cake", 3, 6),
]
for day in 1:days
println("-------- day $day --------")
println("name, sellin, quality")
for item in items
println(item)
end
update_quality!(GildedRose(items))
end
end

16
julia/runtests.jl Normal file
View File

@ -0,0 +1,16 @@
using Test
# To run the tests, include this file into your REPL
# julia> include("runtests.jl")
include("gilded_rose.jl")
@testset "gilded_rose.jl" begin
# Test foo
items = [Item("foo", 0, 0)]
gildedrose = GildedRose(items)
update_quality!(gildedrose)
@test items[1].name == "fixme"
end

View File

@ -1,3 +0,0 @@
[*.php]
indent_size = 4

10
php/.gitignore vendored
View File

@ -1,6 +1,6 @@
/.idea
/report.xml
/.phpstorm.meta.php
/.phpunit.result.cache
/.idea
/build
/vendor
/vendor
/.editorconfig
/.phpunit.result.cache
/composer.lock

View File

@ -7,14 +7,15 @@ GildedRose Kata.
The kata uses:
- [PHP 7.3 or 7.4 or 8.0+](https://www.php.net/downloads.php)
- [8.0+](https://www.php.net/downloads.php)
- [Composer](https://getcomposer.org)
Recommended:
- [Git](https://git-scm.com/downloads)
Clone the repository
See [GitHub cloning a repository](https://help.github.com/en/articles/cloning-a-repository) for details on how to
create a local copy of this project on your computer.
```sh
git clone git@github.com:emilybache/GildedRose-Refactoring-Kata.git
@ -41,7 +42,6 @@ The project uses composer to install:
- [ApprovalTests.PHP](https://github.com/approvals/ApprovalTests.php)
- [PHPStan](https://github.com/phpstan/phpstan)
- [Easy Coding Standard (ECS)](https://github.com/symplify/easy-coding-standard)
- [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer/wiki)
## Folders
@ -56,20 +56,30 @@ The project uses composer to install:
- `Fixture`
- `texttest_fixture.php` this could be used by an ApprovalTests, or run from the command line
## Fixture
To run the fixture from the php directory:
```shell
php .\fixtures\texttest_fixture.php 10
```
Change **10** to the required days.
## Testing
PHPUnit is configured for testing, a composer script has been provided. To run the unit tests, from the root of the PHP
project run:
```shell script
composer test
composer tests
```
A Windows a batch file has been created, like an alias on Linux/Mac (e.g. `alias pu="composer test"`), the same
PHPUnit `composer test` can be run:
A Windows a batch file has been created, like an alias on Linux/Mac (e.g. `alias pu="composer tests"`), the same
PHPUnit `composer tests` can be run:
```shell script
pu
pu.bat
```
### Tests with Coverage Report
@ -83,6 +93,8 @@ composer test-coverage
The test-coverage report will be created in /builds, it is best viewed by opening /builds/**index.html** in your
browser.
The [XDEbug](https://xdebug.org/download) extension is required for generating the coverage report.
## Code Standard
Easy Coding Standard (ECS) is configured for style and code standards, **PSR-12** is used. The current code is not upto
@ -100,7 +112,7 @@ On Windows a batch file has been created, like an alias on Linux/Mac (e.g. `alia
PHPUnit `composer check-cs` can be run:
```shell script
cc
cc.bat
```
### Fix Code
@ -115,7 +127,7 @@ On Windows a batch file has been created, like an alias on Linux/Mac (e.g. `alia
PHPUnit `composer fix-cs` can be run:
```shell script
fc
fc.bat
```
## Static Analysis
@ -130,7 +142,7 @@ On Windows a batch file has been created, like an alias on Linux/Mac (e.g. `alia
PHPUnit `composer phpstan` can be run:
```shell script
ps
ps.bat
```
**Happy coding**!

View File

@ -1,8 +1,17 @@
{
"name": "emilybache/gilded-rose-refactoring-kata",
"description": "A kata to practice refactoring, tests and polymorphism",
"license": "MIT",
"require": {
"php": "^7.3 || ^8.0"
"php": "^8.0"
},
"require-dev": {
"approvals/approval-tests": "dev-Main",
"phpunit/phpunit": "^9.5",
"phpstan/phpstan": "^1.9",
"phpstan/phpstan-phpunit": "^1.3",
"symplify/easy-coding-standard": "^11.1",
"symplify/phpstan-extensions": "^11.1"
},
"autoload": {
"psr-4": {
@ -14,18 +23,7 @@
"Tests\\": "tests/"
}
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"phpstan/phpstan": "^0.12.85",
"phpstan/phpstan-phpunit": "^0.12.18",
"symplify/easy-coding-standard": "^9.3",
"symplify/phpstan-extensions": "^9.3",
"approvals/approval-tests": "^1.4"
},
"scripts": {
"checkcode": "phpcs src tests --standard=PSR12",
"fixcode": "phpcbf src tests --standard=PSR12",
"test": "phpunit",
"tests": "phpunit",
"test-coverage": "phpunit --coverage-html build/coverage",
"check-cs": "ecs check",

6549
php/composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,34 +3,45 @@
declare(strict_types=1);
use PhpCsFixer\Fixer\ArrayNotation\ArraySyntaxFixer;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\EasyCodingStandard\ValueObject\Option;
use PhpCsFixer\Fixer\Strict\DeclareStrictTypesFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(ArraySyntaxFixer::class)
->call('configure', [[
'syntax' => 'short',
]]);
// composer require --dev symplify/easy-coding-standard
// vendor/bin/ecs init
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::PATHS, [
__DIR__ . '/fixtures',
return static function (ECSConfig $ecsConfig): void {
$ecsConfig->paths([
__DIR__ . '/src',
__DIR__ . '/tests',
__DIR__ . '/ecs.php', // check this file too!
]);
$parameters->set
(Option::SETS,
[
SetList::CLEAN_CODE,
SetList::COMMON,
SetList::PSR_12,
]
);
$ecsConfig->skip([
// rules to skip
]);
$parameters->set(Option::INDENTATION, "spaces");
// run and fix, one by one
$ecsConfig->sets([
SetList::SPACES,
SetList::ARRAY,
SetList::DOCBLOCK,
SetList::NAMESPACES,
SetList::CONTROL_STRUCTURES,
SetList::CLEAN_CODE,
SetList::STRICT,
SetList::PSR_12,
SetList::PHPUNIT,
]);
$parameters->set(Option::LINE_ENDING, "\n");
// add declare(strict_types=1); to all php files:
$ecsConfig->rule(DeclareStrictTypesFixer::class);
// change $array = array(); to $array = [];
$ecsConfig->ruleWithConfiguration(ArraySyntaxFixer::class, [
'syntax' => 'short',
]);
// [default: PHP_EOL]; other options: "\n"
$ecsConfig->lineEnding("\n");
};

View File

@ -25,7 +25,7 @@ $items = [
$app = new GildedRose($items);
$days = 2;
if (count($argv) > 1) {
if ((is_countable($argv) ? count($argv) : 0) > 1) {
$days = (int) $argv[1];
}

View File

@ -8,8 +8,8 @@ parameters:
- tests
- fixtures
# The level 8 is the highest level
level: 8
# max is the highest level
level: max
checkGenericClassInNonGenericObjectType: false

View File

@ -1 +1 @@
composer test
composer tests

View File

@ -7,13 +7,11 @@ namespace GildedRose;
final class GildedRose
{
/**
* @var Item[]
* @param Item[] $items
*/
private $items;
public function __construct(array $items)
{
$this->items = $items;
public function __construct(
private array $items
) {
}
public function updateQuality(): void
@ -29,12 +27,12 @@ final class GildedRose
if ($item->quality < 50) {
$item->quality = $item->quality + 1;
if ($item->name == 'Backstage passes to a TAFKAL80ETC concert') {
if ($item->sell_in < 11) {
if ($item->sellIn < 11) {
if ($item->quality < 50) {
$item->quality = $item->quality + 1;
}
}
if ($item->sell_in < 6) {
if ($item->sellIn < 6) {
if ($item->quality < 50) {
$item->quality = $item->quality + 1;
}
@ -44,10 +42,10 @@ final class GildedRose
}
if ($item->name != 'Sulfuras, Hand of Ragnaros') {
$item->sell_in = $item->sell_in - 1;
$item->sellIn = $item->sellIn - 1;
}
if ($item->sell_in < 0) {
if ($item->sellIn < 0) {
if ($item->name != 'Aged Brie') {
if ($item->name != 'Backstage passes to a TAFKAL80ETC concert') {
if ($item->quality > 0) {

View File

@ -4,32 +4,17 @@ declare(strict_types=1);
namespace GildedRose;
final class Item
final class Item implements \Stringable
{
/**
* @var string
*/
public $name;
/**
* @var int
*/
public $sell_in;
/**
* @var int
*/
public $quality;
public function __construct(string $name, int $sell_in, int $quality)
{
$this->name = $name;
$this->sell_in = $sell_in;
$this->quality = $quality;
public function __construct(
public string $name,
public int $sellIn,
public int $quality
) {
}
public function __toString(): string
{
return "{$this->name}, {$this->sell_in}, {$this->quality}";
return (string) "{$this->name}, {$this->sellIn}, {$this->quality}";
}
}