GithubHelp home page GithubHelp logo

dgroup / tagyml Goto Github PK

View Code? Open in Web Editor NEW
4.0 3.0 0.0 116 KB

Laconic API for YAML files processing

License: MIT License

Java 100.00%
yaml yaml-parser yml yml-files java oop java-library oop-principles elegantobjects

tagyml's Introduction

Maven Javadocs License: MIT Commit activity Hits-of-Code

Build Status 0pdd Dependency Status Known Vulnerabilities

DevOps By Rultor.com EO badge We recommend IntelliJ IDEA

Qulice SQ maintainability Codebeat Codacy Badge Codecov

ATTENTION: We're still in a very early alpha version, the API may and will change frequently. Please, use it at your own risk, until we release version 1.0.

Maven:

<dependency>
    <groupId>io.github.dgroup</groupId>
    <artifactId>tagyml</artifactId>
</dependency>

Gradle:

dependencies {
    compile 'io.github.dgroup:tagyml:<version>'
}

Get started

Represents the YAML file as an object Teams

The examples below are built on top of snakeyaml framework, but you can override it by using the extension point in favour of your favourite framework.

  1. Define YAML file for version 1.0.

    version: 1.0
    
    teams:
    
      - id: 100
        name:     BSS dream team
        lead:
          name:   Bob Marley
          email:  [email protected]
        properties:
          total-devs: 5
          total-managers: 10
    
      - id: 200
        name:     OSS dream team
        lead:
          name:   Jules Verne
          email:  [email protected]
        properties:
          total-devs: 5
          total-managers: 5

    in

    tagyml $ tree
    ...
    |-- src
    |   |-- main
    |   |   |-- ...
    |   |
    |   `-- test
    |       |-- java
    |       |   `-- ...
    |       `-- resources
    |           `-- yaml
    |               |-- teams.yaml
    |               |-- ...
    ...
    
  2. Define the interfaces for the domain model

    /** 
     * YAML file-based team.
     */
    public interface Team {
        int id() throws YamlFormatException;
        String name() throws YamlFormatException;
        User lead() throws YamlFormatException;
        Properties properties() throws YamlFormatException;
    }
    
    /**
     * YAML file-based user.
     */
    public interface User {
        String name();
        String email();
    }

    See UncheckedYamlFormatException in case if you don't wan't to throw the checked exception during YAML file parsing procedure.

  3. Define the YAML parsing process

    public class Teams implements Scalar<Iterable<Team>> {
    
        private static final Logger LOG = LoggerFactory.getLogger(Teams.class);
    
        /**
         * @param path The path to the YAML file.
         * @param charset The charset of YAML file to read.
         */
        public Teams(final Path path, final Charset charset) {
            this.path = path;
            this.charset = charset;
        }
        
        @Override
        public Iterable<Team> value() throws YamlFormatException {
            // Parse YAML file using first supported YAML format
            return new FirstIn<>(
                // Print to logs the details about failed attempt of
                // parsing YAML file using a particular format.
                (version, exception) -> LOG.warn(
                    new FormattedText(
                        "Unable to parse '%s' using '%s' format",
                        this.path, version
                    ).asString(),
                    exception
                ),
                // The exception message in case if YAML file can't be
                // parsed using any specified formats below
                new FormattedText(
                    "The file %s has unsupported YAML format", this.path
                ),
                // The supported YAML formats
                new TeamsV1(this.path, this.charset),
                new TeamsV2(this.path, this.charset),
                ...
                new TeamsVn(this.path, this.charset)
            ).value();
        }
    }

    See FirstIn.

  4. Define YAML format for version 1.0 - TeamsV1

    final class TeamsV1 implements Format<Iterable<Team>> {
    
        private final Path path;
        private final Charset charset;
    
        TeamsV1(final Path path, final Charset charset) {
            this.path = path;
            this.charset = charset;
        }
    
        @Override
        public String version() {
            return "1.0";
        }
    
        @Override
        public Iterable<Team> value() throws YamlFormatException {
            return new Snakeyaml(YamlFile.class)
                .apply(new YamlText(this.path, this.charset))
                .tagTeams();
        }
    
        /**
         * The object which represents YAML file.
         * The YAML file should have at least `version` and collection of `team`.
         * The EO concept is against getters/setters, but we need them in order to
         *  parse the file by snakeyaml lib, thus, once we completed the parsing
         *  procedure, we should restrict any possible access to such type of objects.
         */
        private static class YamlFile {
            public double version;
            public List<YmlTeam> teams;
    
            public double tagVersion() throws YamlFormatException {
                return new Version(this.version).value();
            }
    
            public Iterable<Team> tagTeams() throws YamlFormatException {
                return new Mapped<>(
                    YamlTeam::tagTeam, new TagOf<>("teams", this.teams).value()
                );
            }
        }
    
        /**
         * Represents 1 element from YAML tag `teams`.
         */
        private static class YmlTeam {
            public int id;
            public String name;
            public YmlTeamMember lead;
            public Map<String, String> properties;
    
            public Team tagTeam() {
                return new Team() {
                    @Override
                    public int id() throws YamlFormatException {
                        return new TagOf<>("id", id).value();
                    }
    
                    @Override
                    public String name() throws YamlFormatException {
                        return new TagOf<>("name", name).value();
                    }
    
                    @Override
                    public User lead() throws YamlFormatException {
                        return new TagOf<>("lead", lead).value().tagUser();
                    }
    
                    @Override
                    public Properties properties() throws YamlFormatException {
                        return new PropertiesOf("properties", properties).value();
                    }
                };
            }
        }
    
        /**
         * Represents YAML tag `lead`
         */
        private static class YmlTeamMember {
            public String name;
            public String email;
    
            public User tagUser() {
                return new User() {
                    @Override
                    public String name() {
                        return new Unchecked(new TagOf<>("name", name)).value();
                    }
    
                    @Override
                    public String email() {
                        return new Unchecked(new TagOf<>("email", email)).value();
                    }
                );
            }
        }
    }

    See Format, Snakeyaml, Version, PropertiesOf, TagOf and Unchecked.

    Instead of Snakeyaml you may implement Yaml using your favourite framework in the same way.

  5. Parse YAML file in EO way

    @Test
    public void yamlParsingProcessIsSuccessfull() throws YmlFormatException {
        final Iterable<Team> teams = new Teams(
            Paths.get("src", "test", "resources", "yml", "1.0", "teams.yml")
        ).value();
        MatcherAssert.assertThat(
            "There are 2 teams defined in YAML file",
            teams, Matchers.iterableWithSize(2)
        );
        MatcherAssert.assertThat(
            "The 1st team defined in YAML tag has id 100",
            teams.iterator().next().id(),
            new IsEqual<>(100)
        );
        MatcherAssert.assertThat(
            "The 1st team defined in YAML tag has property `total-dev`",
            teams.iterator().next().properties().getProperty("total-dev"),
            new IsEqual<>(5)
        );
    }

    See SnakeyamlTest for details. Of course, the test above is testing a lot of things and should be separated into bunch of tests with single MatcherAssert.assertThat each, but here it was done for educational purposes.

tagyml's People

Contributors

dgroup avatar rultor avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

tagyml's Issues

.travis.yml:27-47: Activate JDK11, 12 for CI...

The puzzle DEV-5c50c062 from #DEV has to be resolved:

tagyml/.travis.yml

Lines 27 to 47 in dba32d9

# @todo #/DEV Activate JDK11, 12 for CI process.addons:
# For now its disabled due to 'https://travis-ci.org/dgroup/tagyml/jobs/579535606'
# Exception in thread "main" java.lang.reflect.InvocationTargetException
# at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
# at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
# at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
# at java.base/java.lang.reflect.Method.invoke(Method.java:566)
# at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:513)
# at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:525)
# Caused by: java.lang.RuntimeException: Class java/util/UUID could not be instrumented.
# at org.jacoco.agent.rt.internal_8ff85ea.core.runtime.ModifiedSystemClassRuntime.createFor(ModifiedSystemClassRuntime.java:140)
# at org.jacoco.agent.rt.internal_8ff85ea.core.runtime.ModifiedSystemClassRuntime.createFor(ModifiedSystemClassRuntime.java:101)
# FATAL ERROR in native method: processing of -javaagent failed
# at org.jacoco.agent.rt.internal_8ff85ea.PreMain.createRuntime(PreMain.java:55)
# at org.jacoco.agent.rt.internal_8ff85ea.PreMain.premain(PreMain.java:47)
# ... 6 more
# Caused by: java.lang.NoSuchFieldException: $jacocoAccess
# at java.base/java.lang.Class.getField(Class.java:2000)
# at org.jacoco.agent.rt.internal_8ff85ea.core.runtime.ModifiedSystemClassRuntime.createFor(ModifiedSystemClassRuntime.java:138)
# ... 9 more
# Aborted (core dumped)

The puzzle was created by @dgroup on 01-Sep-19.

role: DEV.

If you have any technical questions, don't ask me, submit new tickets instead. The task will be "done" when the problem is fixed and the text of the puzzle is removed from the source code. Here is more about PDD and about me.

YamlFile.java:30-32: Rename to Yaml and extends Scalar....

The puzzle DEV-9b5f6a90 from #DEV has to be resolved:

* @todo #/DEV Rename to Yaml and extends Scalar. It shouldn't be focused on top
* on snakeyaml only, thus the implementation YamlOf should support other
* frameworks through the passing of org.cactoos.Scalar or org.cactoos.Func.

The puzzle was created by @rultor on 13-Jan-19.

If you have any technical questions, don't ask me, submit new tickets instead. The task will be "done" when the problem is fixed and the text of the puzzle is removed from the source code. Here is more about PDD and about me.

package-info.java:29-32: Avoid compound names within the...

The puzzle DEV-1900b3b7 from #DEV has to be resolved:

* @todo #/DEV Avoid compound names within the classes. The fix is required for
* the following packages:
* - {@link io.github.dgroup.yaml.file}
* - {@link io.github.dgroup.yaml.tag}, where TagIs rename to TagHas

The puzzle was created by @rultor on 13-Jan-19.

If you have any technical questions, don't ask me, submit new tickets instead. The task will be "done" when the problem is fixed and the text of the puzzle is removed from the source code. Here is more about PDD and about me.

pom.xml:137: Activate de.thetaphi:forbiddenapis in order...

The puzzle DEV-08faa53a from #DEV has to be resolved:

tagyml/pom.xml

Line 137 in 08123ca

<!-- @todo #/DEV Activate de.thetaphi:forbiddenapis in order to forbid the usage of forbidden API like static matchers, etc -->

The puzzle was created by @dgroup on 01-Jan-19.

If you have any technical questions, don't ask me, submit new tickets instead. The task will be "done" when the problem is fixed and the text of the puzzle is removed from the source code. Here is more about PDD and about me.

package-info.java:29-32: Avoid compound names within the...

The puzzle DEV-1567f494 from #DEV has to be resolved:

* @todo #/DEV Avoid compound names within the classes. The fix is required for
* the following packages:
* - {@link io.github.dgroup.tagyml.yaml}
* - {@link io.github.dgroup.tagyml.tag}, where TagIs rename to TagHas

The puzzle was created by @rultor on 13-Jan-19.

If you have any technical questions, don't ask me, submit new tickets instead. The task will be "done" when the problem is fixed and the text of the puzzle is removed from the source code. Here is more about PDD and about me.

package-info.java:29-30: Migrate unit tests to Assertion...

The puzzle DEV-85c94c26 from #DEV has to be resolved:

* @todo #/DEV Migrate unit tests to Assertion from cactoos-matchers once v0.13
* is released.

The puzzle was created by @dgroup on 01-Jan-19.

If you have any technical questions, don't ask me, submit new tickets instead. The task will be "done" when the problem is fixed and the text of the puzzle is removed from the source code. Here is more about PDD and about me.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.