Skip to content

Commit

Permalink
Merge pull request #5 from thegatesdev/dev/dev
Browse files Browse the repository at this point in the history
Immutability and naming improvements for v4
  • Loading branch information
thegatesdev authored Nov 6, 2023
2 parents c22afe7 + 164448a commit 69e5834
Show file tree
Hide file tree
Showing 21 changed files with 405 additions and 412 deletions.
98 changes: 49 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ A simple, type safe configuration structure
- [About](#about)
- [Usage](#usage)
- [Including the library in your project](#including-in-your-project)
- [Element basics](#element-basics)
- [Element conversion](#conversion)
- [Element crawling](#crawling)
- [Applying options](#datatype-and-mapoptions)
- [Basics](#element-basics)
- [Conversion](#conversion)
- [Transformation](#transforming)
- [DataTypes and MapOptions](#datatype-and-mapoptions)

## About

Expand All @@ -21,84 +21,81 @@ as that API was quite limiting and ugly for my use cases.

My goal with this library is to make it easy to wrap configuration values
in a clean and understandable structure, providing plenty of utility methods
for specific scenario's.
for each scenario.

Feel free to open an issue, or even a pull request, if you have any concerns or suggestions.
Feel free to open an issue, or even a pull request if you have any concerns or suggestions.

## Usage

### Including in your project

Since Maple is public on Github, you can easily include it from JitPack.
Since Maple is public on GitHub, you can find it on JitPack.
Just head to https://jitpack.io/#thegatesdev/maple, select a version and follow the instructions for your build system.

### Element Basics

**Creating elements**
**Building elements**

All elements are immutable. Creating elements is done as such;

Creating list, map and value types is as easy as calling their constructors;
```java
DataMap myMap = new DataMap();
DataList myList = new DataList();
DataValue<String> myImmutableValue = new StaticDataValue<>("hello world");
DataValue<String> myDynamicValue = new DynamicDataValue<>(String.class, () -> "hello world");
// Values ...
DataValue<String> stringValue = DataValue.of("Hello world!");
// Maps ...
DataMap myMap = DataMap.builder()
.add("message", stringValue)
.build();
// And lists!
DataList myList = DataList.builder()
.add(stringValue)
.build();
```

You can also use builders with existing data, using the `addFrom` methods.

**Checking types**

There are multiple methods to check the type of an element itself;
There are multiple methods to check the type of element itself;

```java
DataElement myElement = new DataMap();
DataElement myElement = DataMap.EMPTY;

myElement.isList(); // False
myElement.isMap(); // True

myElement.getType(); // ElementType.MAP
myElement.type(); // ElementType.MAP

myElement.ifMap(map -> print("myElement is a map!"), () -> print("myElement is not a map!"));
```

**Modifying elements**

Simple setting and adding operation are currently supported.
More will be added in future releases, like removing and clearing.

```java
DataList myList = new DataList();

myList.add(new StaticDataValue<>("Hello"));
myList.add(new StaticDataValue<>("World"));
myList.set(1, new StaticDataValue<>("Universe"));

DataMap myMap = new DataMap();
myMap.set("Earth", new StaticDataValue<>("Humans"));
myMap.set("Mars", new StaticDataValue<>("Aliens"));
```

**Getting from elements**

All `get` methods will throw when an invalid request is made.

```java
DataMap myMap = //.. Map with information
DataMap myMap;

// Plain elements
DataElement otherElement = myMap.getOrThrow("somekey");
DataElement otherElement = myMap.get("somekey");

DataMap otherMap = myMap.getMap("mapkey");
DataList otherList = myMap.getList("listkey");

DataElement optionalElement = myMap.find("invalid_key"); // Returns 'null' if not found

// Values
String stringValue = myMap.get("message", String.class);
String stringValue = myMap.get("message", String.class, "no message"); // With default
String stringValue = myMap.find("message", String.class, "no message"); // With default
int intValue = myMap.getInt("count", 0);

myMap.each(element -> print("Found an element"));
```

### Conversion

Maple was meant to be used with data from other sources, e.g. json or yaml configuration files.
Maple was meant to be used with data from other sources, like json or yaml configuration files.

To convert plain Java objects to a Maple structure, for example the output from snakeyaml, use the `Conversion` class.
To convert plain Java objects to a Maple structure, for example, the output from snakeyaml, use the `Conversion` class.
```java
Conversion conversion = new DefaultConversion();

Expand All @@ -109,30 +106,33 @@ DataMap data = conversion.convertMap(fileOutput);
This will convert the entire structure to a Maple representation.
The `DefaultConversion` implementation should be adequate for most use cases.

### Crawling
### Transforming

Every Maple element supports two transformation methods; `transform` and `crawl`.
These methods have only one difference:
`transform` visits only the *children* of an element,
while `crawl` visits *all descendants* of an element

Every Maple element supports the 'crawl' operation. Crawling will visit every descendant of an element, and optionally replace it.
A crawl operation to replace every value element with a message could look like this:

Crawling can be used to replace placeholder values to their actual values.
```java
DataMap map = //..

map.crawl(element -> {
if (!element.isValue()) return Optional.empty(); // Don't do anything
return Optional.of(new StaticDataValue<>("You have been hacked!"));
}); // Replaces all value elements with a string value saying "You have been hacked!"
DataMap myMap;
DataMap result = myMap.crawl(element -> {
if (element.isValue()) return DataValue.of("You have been hacked!");
return element;
});
```

### DataType and MapOptions

A `DataType` defines a type of data that can be read from an element.
The `MapOptions` class uses those data types to enforce option types on a map.
The `MapOptions` class uses those data types to enforce and apply option types on a map.

```java
MapOptions options = MapOptions.builder()
.add("number_option", DataType.number())
.add("string_options", DataType.string(), "default")
.optional("optional_enum", DataType.enumeration(PizzaTopping.CHEESE))
.optional("optional_enum", DataType.enumeration(PizzaTopping.class), PizzaTopping.CHEESE)
.build();
// Apply these options to a map
DataMap result = options.apply(someMap);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/io/github/thegatesdev/maple/ElementType.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ public enum ElementType {
/**
* @return the name of the element type
*/
public String getElementName() {
public String elementName() {
return elementName;
}

/**
* @return the name of the element type as used in a sentence
*/
public String getInlineName() {
public String inlineName() {
return inlineName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import io.github.thegatesdev.maple.element.DataElement;
import io.github.thegatesdev.maple.element.DataList;
import io.github.thegatesdev.maple.element.DataMap;
import io.github.thegatesdev.maple.element.StaticDataValue;
import io.github.thegatesdev.maple.element.DataValue;

import java.util.List;
import java.util.Map;
Expand All @@ -29,7 +29,7 @@
* This conversion is able to convert most existing Java types to their element equivalent.
* Arrays, Lists, and optionally Iterables will be converted to {@link DataList}.
* Maps will be converted to {@link DataMap}.
* The remaining types will be wrapped in a {@link StaticDataValue}.
* The remaining types will be wrapped in a {@link DataValue}.
*/
public final class DefaultConversion implements Conversion {

Expand All @@ -45,7 +45,7 @@ public DefaultConversion useToStringKeys(boolean useToStringKeys) {
}

/**
* Indicate to convert {@link Iterable} entries to their {@link DataList} equivalent, instead of wrapping them in a {@link StaticDataValue}.
* Indicate to convert {@link Iterable} entries to their {@link DataList} equivalent, instead of wrapping them in a {@link DataValue}.
* Default is {@code true}.
*/
public DefaultConversion convertIterable(boolean convertIterable) {
Expand All @@ -63,22 +63,22 @@ private DataElement apply(Object object) {
if (object instanceof List<?> someList) return convertList(someList);
if (convertIterable && object instanceof Iterable<?> someIterable) return convertList(List.of(someIterable));

return new StaticDataValue<>(object);
return DataValue.of(object);
}

public DataMap convertMap(Map<?, ?> someMap) {
var output = new DataMap(someMap.size());
var output = DataMap.builder(someMap.size());
someMap.forEach((key, value) -> {
var result = apply(value);
if (key instanceof String stringKey) output.set(stringKey, result);
else if (useToStringKeys) output.set(key.toString(), result);
if (key instanceof String stringKey) output.add(stringKey, result);
else if (useToStringKeys) output.add(key.toString(), result);
});
return output;
return output.build();
}

public DataList convertList(List<?> someList) {
var output = new DataList(someList.size());
var output = DataList.builder(someList.size());
for (Object value : someList) output.add(apply(value));
return output;
return output.build();
}
}
35 changes: 0 additions & 35 deletions src/main/java/io/github/thegatesdev/maple/element/Crawler.java

This file was deleted.

Loading

0 comments on commit 69e5834

Please sign in to comment.