Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
ef5debb8c9 | |||
848606e620 | |||
104856f425 | |||
efe875bd05 |
8
.woodpecker.yml
Normal file
8
.woodpecker.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
pipeline:
|
||||||
|
phpunit:
|
||||||
|
image: walkero/phpunit-alpine:php8.0-phpunit9
|
||||||
|
commands:
|
||||||
|
- composer install
|
||||||
|
- phpunit --testdox
|
||||||
|
|
||||||
|
|
@ -8,3 +8,5 @@ This is a library to help write juice-mixing stuff in PHP.
|
|||||||
* Calculate weights for mixing based on the VG/PG ratio or a specific values.
|
* Calculate weights for mixing based on the VG/PG ratio or a specific values.
|
||||||
* Calculate weights for nicotine based on the nicotine strength and base.
|
* Calculate weights for nicotine based on the nicotine strength and base.
|
||||||
* Interfaces allow for custom entity-backed implementations.
|
* Interfaces allow for custom entity-backed implementations.
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,6 +15,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "~7.0"
|
"php": "~7.0|~8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
77
doc/json-schemas.md
Normal file
77
doc/json-schemas.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Json Schemas
|
||||||
|
|
||||||
|
Juicer comes with a number of schemas to validate data.
|
||||||
|
|
||||||
|
## Definitions
|
||||||
|
|
||||||
|
**Flavoring Key**:
|
||||||
|
A combination of the BrandKey and a unique combination of letters and
|
||||||
|
optional version info. Ex. `FW-VBIC` for FlavorWest Vanilla Bean Ice
|
||||||
|
Cream, or `TFA-MSHM-DX` for TFA DX Marshmallow. Max length is 32 chars.
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
* Flavoring keys always start with a vendor prefix of 2-4 characters.
|
||||||
|
* Variation of a flavor are appended, such as `DX` or `V2`
|
||||||
|
* Flavoring names should follow existing use as far as possible, while
|
||||||
|
making it easy to associate similar flavorings from various vendors.
|
||||||
|
|
||||||
|
Exammples:
|
||||||
|
|
||||||
|
FW-VBIC FlavorWest Vanilla Bean Ice Cream
|
||||||
|
TFA-VBIC The Flavor Artisan Vanilla Bean Ice Cream
|
||||||
|
CAP-VCUS Capella Vanilla Custard
|
||||||
|
CAP-VCUS-V2 Capella Vanilla Custard V2
|
||||||
|
TFA-MSHM The Flavor Artisan Marshmallow
|
||||||
|
TFA-MSHM-DX The Flavor Artisan Marshmallow DX
|
||||||
|
FA-FUJA FlavourArt Fuji Apple
|
||||||
|
|
||||||
|
## ingredient.schema.json
|
||||||
|
|
||||||
|
Defines an ingredient.
|
||||||
|
|
||||||
|
{
|
||||||
|
"flavoringKey": "TFA-WCHO",
|
||||||
|
"brandKey": "TFA",
|
||||||
|
"brandName": "The Flavor Apprentice",
|
||||||
|
"flavoringName": "White Chocolate",
|
||||||
|
"ingredients": [
|
||||||
|
"Ethyl Alcohol",
|
||||||
|
"Vanillin",
|
||||||
|
"Acetoin"
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"suggestedPercent": 2,
|
||||||
|
"suggestedSteep": 7,
|
||||||
|
"specificGravity": 1.004,
|
||||||
|
"base": "PG100",
|
||||||
|
"isAdditive": false
|
||||||
|
},
|
||||||
|
"flavorProfiles": [
|
||||||
|
"White Chocolate"
|
||||||
|
],
|
||||||
|
"warnings": [],
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
|
|
||||||
|
## recipe.schema.json
|
||||||
|
|
||||||
|
Defines a recipe
|
||||||
|
|
||||||
|
{
|
||||||
|
"url": "https://vape.noccy.com/recipe/tasty",
|
||||||
|
"recipeName": "Tasty",
|
||||||
|
"author": "Noccy",
|
||||||
|
"recommendedSteep": 0,
|
||||||
|
"ingredients": [
|
||||||
|
{
|
||||||
|
"flavor": "FW Vanilla Bean Ice Cream",
|
||||||
|
"percent": 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"flavor": "FW Real Lemonade",
|
||||||
|
"percent": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -8,20 +8,20 @@ use NoccyLabs\Juicer\Ingredient\NicotineBase;
|
|||||||
printf("Apparent Specific Gravity of base mixes:\n\n");
|
printf("Apparent Specific Gravity of base mixes:\n\n");
|
||||||
printf(" VG | PG | ASG\n");
|
printf(" VG | PG | ASG\n");
|
||||||
printf(" ------|------|------------------------\n");
|
printf(" ------|------|------------------------\n");
|
||||||
for ($pg = 0; $pg < 100; $pg += 10) {
|
for ($pg = 0; $pg <= 100; $pg += 10) {
|
||||||
$base = new Base("PG{$pg}");
|
$base = new Base("PG{$pg}");
|
||||||
printf(" %3d%% | %3d%% | %.4fg/mL\n", 100-$pg, $pg, $base->getSpecificGravity());
|
printf(" %3d%% | %3d%% | %.4fg/mL\n", 100-$pg, $pg, $base->getSpecificGravity());
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "\n\n";
|
echo "\n\n";
|
||||||
|
|
||||||
$asgstrength = [ 24, 20, 18, 15 ];
|
$asgstrength = [ 24, 20, 18, 15, 0 ];
|
||||||
$asgheader = join("", array_map(function ($s) { return sprintf("%2dmg ", $s); } , $asgstrength));
|
$asgheader = join("", array_map(function ($s) { return sprintf("%2dmg ", $s); } , $asgstrength));
|
||||||
|
|
||||||
printf("Apparent Specific Gravity of nicotine bases:\n\n");
|
printf("Apparent Specific Gravity of nicotine bases:\n\n");
|
||||||
printf(" VG | PG | %s\n", $asgheader);
|
printf(" VG | PG | %s\n", $asgheader);
|
||||||
printf(" ------|------|-------------------------------------\n");
|
printf(" ------|------|-------------------------------------\n");
|
||||||
for ($pg = 0; $pg < 100; $pg += 10) {
|
for ($pg = 0; $pg <= 100; $pg += 10) {
|
||||||
printf(" %3d%% | %3d%% |", 100-$pg, $pg);
|
printf(" %3d%% | %3d%% |", 100-$pg, $pg);
|
||||||
$base = new Base("PG{$pg}");
|
$base = new Base("PG{$pg}");
|
||||||
foreach($asgstrength as $s) {
|
foreach($asgstrength as $s) {
|
||||||
|
68
src/Helper/Normalizer.php
Normal file
68
src/Helper/Normalizer.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Helper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize percentages to a full 100%.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Normalizer
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $inputs = [];
|
||||||
|
|
||||||
|
protected $ratio = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizer constructor.
|
||||||
|
*
|
||||||
|
* @param array The percentages indexed by a unique key
|
||||||
|
*/
|
||||||
|
public function __construct(array $inputPercents=[])
|
||||||
|
{
|
||||||
|
foreach ($inputPercents as $k=>$p)
|
||||||
|
$this->setPart($k, $p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the percentage of a component.
|
||||||
|
*
|
||||||
|
* @param mixed The key used to access this part later
|
||||||
|
* @param float The percent of this part
|
||||||
|
*/
|
||||||
|
public function setPart($key, float $percent)
|
||||||
|
{
|
||||||
|
$this->inputs[$key] = $percent;
|
||||||
|
$total = array_sum(array_values($this->inputs));
|
||||||
|
$this->ratio = 100 / $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the original percentage of the key.
|
||||||
|
*
|
||||||
|
* @param mixed The key
|
||||||
|
* @return float Original percentage as provided
|
||||||
|
*/
|
||||||
|
public function getPercent($key)
|
||||||
|
{
|
||||||
|
if (!array_key_exists($key, $this->inputs))
|
||||||
|
throw new \Exception();
|
||||||
|
|
||||||
|
return floatval($this->inputs[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the normalized percentage where the added total equals 100%
|
||||||
|
*
|
||||||
|
* @param mixed The key
|
||||||
|
* @return float Normalized percentage as provided
|
||||||
|
*/
|
||||||
|
public function getNormalizedPercent($key)
|
||||||
|
{
|
||||||
|
if (!array_key_exists($key, $this->inputs))
|
||||||
|
throw new \Exception();
|
||||||
|
|
||||||
|
return floatval($this->inputs[$key]) * $this->ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
src/Ingredient/Importer/JsonImporter.php
Normal file
45
src/Ingredient/Importer/JsonImporter.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Ingredient\Importer;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Ingredient;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
|
||||||
|
|
||||||
|
class JsonImporter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Import ingredient from json
|
||||||
|
*
|
||||||
|
* @param string The json string to parse and import
|
||||||
|
* @return IngredientInterface
|
||||||
|
*/
|
||||||
|
public function import(string $json): IngredientInterface
|
||||||
|
{
|
||||||
|
$data = json_decode($json);
|
||||||
|
|
||||||
|
$ingredient = new Ingredient($data->flavoringName, $data->brandKey);
|
||||||
|
|
||||||
|
print_r($data);
|
||||||
|
|
||||||
|
return $ingredient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import ingredient from json contained in a file
|
||||||
|
*
|
||||||
|
* @param string The filename to read and import
|
||||||
|
* @return IngredientInterface
|
||||||
|
*/
|
||||||
|
public function readFromFile(string $filename): IngredientInterface
|
||||||
|
{
|
||||||
|
$fd = fopen($filename, "r");
|
||||||
|
if (!$fd) {
|
||||||
|
throw new \InvalidArgumentException();
|
||||||
|
}
|
||||||
|
$json = fread($fd, filesize($filename));
|
||||||
|
fclose($fd);
|
||||||
|
|
||||||
|
return $this->import($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
0
src/Recipe/Exporter/XmlExporter.php
Normal file
0
src/Recipe/Exporter/XmlExporter.php
Normal file
15
src/Recipe/Importer/ImporterInterface.php
Normal file
15
src/Recipe/Importer/ImporterInterface.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe\Importer;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Recipe\RecipeInterface;
|
||||||
|
|
||||||
|
interface ImporterInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function readFromFile(string $filename): RecipeInterface;
|
||||||
|
|
||||||
|
public function import(string $data): RecipeInterface;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -10,7 +10,7 @@ use NoccyLabs\Juicer\Ingredient\Ingredient;
|
|||||||
* Import recipes from Json
|
* Import recipes from Json
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class JsonImporter
|
class JsonImporter implements ImporterInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
57
src/Recipe/Importer/XmlImporter.php
Normal file
57
src/Recipe/Importer/XmlImporter.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe\Importer;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Recipe\RecipeInterface;
|
||||||
|
use NoccyLabs\Juicer\Recipe\Recipe;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Ingredient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import recipes from XML
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class XmlImporter implements ImporterInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import a recipe from xml
|
||||||
|
*
|
||||||
|
* @param string The xml string to parse and import
|
||||||
|
* @return RecipeInterface
|
||||||
|
*/
|
||||||
|
public function import(string $xml): RecipeInterface
|
||||||
|
{
|
||||||
|
$data = simplexml_parse_string($xml);
|
||||||
|
|
||||||
|
$recipe = new Recipe();
|
||||||
|
$recipe->setRecipeName((string)$data->recipe);
|
||||||
|
$recipe->setRecipeAuthor((string)$data->author);
|
||||||
|
$recipe->setDescription((string)$data->description);
|
||||||
|
|
||||||
|
foreach ((array)@$data->ingredients->ingredient as $ingredientData) {
|
||||||
|
$ingredient = new Ingredient($ingredientData->flavor, $ingredientData->brand, $ingredientData->percent);
|
||||||
|
$recipe->addIngredient($ingredient);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import a recipe from json contained in a file
|
||||||
|
*
|
||||||
|
* @param string The filename to read and import
|
||||||
|
* @return RecipeInterface
|
||||||
|
*/
|
||||||
|
public function readFromFile(string $filename): RecipeInterface
|
||||||
|
{
|
||||||
|
$fd = fopen($filename, "r");
|
||||||
|
if (!$fd) {
|
||||||
|
throw new \InvalidArgumentException();
|
||||||
|
}
|
||||||
|
$xml = fread($fd, filesize($filename));
|
||||||
|
fclose($fd);
|
||||||
|
|
||||||
|
return $this->import($xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
tests/Helper/NormalizerTest.php
Normal file
37
tests/Helper/NormalizerTest.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Helper;
|
||||||
|
|
||||||
|
|
||||||
|
class NormalizerTest extends \PhpUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testThatNormalizedPercentagesAreSane()
|
||||||
|
{
|
||||||
|
$normalizer = new Normalizer([
|
||||||
|
'A' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(10, $normalizer->getPercent("A"));
|
||||||
|
$this->assertEquals(100, $normalizer->getNormalizedPercent("A"));
|
||||||
|
|
||||||
|
$normalizer = new Normalizer([
|
||||||
|
'A' => 10,
|
||||||
|
'B' => 10,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(10, $normalizer->getPercent("A"));
|
||||||
|
$this->assertEquals(50, $normalizer->getNormalizedPercent("A"));
|
||||||
|
$this->assertEquals(10, $normalizer->getPercent("B"));
|
||||||
|
$this->assertEquals(50, $normalizer->getNormalizedPercent("B"));
|
||||||
|
|
||||||
|
$normalizer = new Normalizer([
|
||||||
|
'A' => 2,
|
||||||
|
'B' => 8,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(20, $normalizer->getNormalizedPercent("A"));
|
||||||
|
$this->assertEquals(80, $normalizer->getNormalizedPercent("B"));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user