diff --git a/README.md b/README.md index 30de2a12..728424fe 100644 --- a/README.md +++ b/README.md @@ -215,6 +215,14 @@ type = "apple" apple = "yes" ``` +Validate a toml file +---------- + +A **TOML** file can be created and validated thanks to a **TOLS** file. + +For more specification see [tols.md](tols.md) + + Seriously? ---------- diff --git a/tests/cache/cache-1.0.xsd b/tests/cache/cache-1.0.xsd new file mode 100644 index 00000000..05c89729 --- /dev/null +++ b/tests/cache/cache-1.0.xsd @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cache/cache.tols b/tests/cache/cache.tols new file mode 100644 index 00000000..534f8abb --- /dev/null +++ b/tests/cache/cache.tols @@ -0,0 +1,36 @@ +[cache.clients] +primitive = "Hash" # could be omitted + [cache.clients.client] # defines a new prototype, its name is not important + primitive = "Hash" + [cache.clients.client.occurrence] + min = 0 # at least one occurrence, no maximum +# start the prototype + [cache.clients.client.type] + primitive = "String" # typing + required = true # default is false + [cache.clients.client.type.range] + in = ["redis", "memcache"] + notin = ["mysql"] #mysql as cache is not supported + + [cache.clients.client.alias] + primitive = "String" # typing + required = true # default is false + + [cache.clients.client.dsn] + primitive = "Array" + [cache.clients.client.dsn.content] + primitive = "String" + pattern = "^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$" # regex for ip address, this is an example is not working + + [cache.clients.client.logging] + primitive = "Boolean" + default = true + + [cache.clients.client.options] + primitive = "Hash" + [cache.clients.client.options.connection_persistent] + primitive = "Boolean" + default = true + + [cache.clients.client.options.connection_timeout] + primitive = "Integer" \ No newline at end of file diff --git a/tests/cache/cache.toml b/tests/cache/cache.toml new file mode 100644 index 00000000..e283994c --- /dev/null +++ b/tests/cache/cache.toml @@ -0,0 +1,13 @@ +[cache.clients.default] +type = "redis" +alias = "default" +dsn = ["127.0.0.1"] +logging = false + +[cache.clients.secondary] +type = "memcache" +alias = "secondary" +dsn = ["127.0.0.2", "127.0.0.3"] +logging = false + [cache.clients.secondary.options] + connection_persistent = true \ No newline at end of file diff --git a/tests/cache/cache.xml b/tests/cache/cache.xml new file mode 100644 index 00000000..7036a94e --- /dev/null +++ b/tests/cache/cache.xml @@ -0,0 +1,12 @@ + + + + 127.0.0.1 + + + + 127.0.0.2 + 127.0.0.3 + + + \ No newline at end of file diff --git a/tests/cache/cache.yml b/tests/cache/cache.yml new file mode 100644 index 00000000..345740b6 --- /dev/null +++ b/tests/cache/cache.yml @@ -0,0 +1,14 @@ +cache: + clients: + default: + type: redis + alias: default + dsn: 127.0.0.1 + logging: true + secondary: + type: memcache + alias: secondary + dsn: [127.0.0.2, 127.0.0.3] + logging: false + options: + connection_persistent: true \ No newline at end of file diff --git a/tests/example.tols b/tests/example.tols new file mode 100644 index 00000000..a91b67bf --- /dev/null +++ b/tests/example.tols @@ -0,0 +1,59 @@ +# This is a TOLS document. Boom. +# This is also a TOML document. Boooom. + +[title] +primitive = "String" +required = true + +[owner] + [owner.name] + primitive = "String" + required = true + + [owner.organization] + primitive = "String" + required = false + + [owner.dob] + primitive = "Datetime" + required = true + [owner.dob.range] + min = 1913-05-27T07:32:00Z + max = 2013-05-27T07:32:00Z + +[database] + [database.server] + primitive = "String" + required = true + + [database.ports] + primitive = "Array" + required = true + [database.ports.range] + min = 0 + + [database.ports.content] + primitive = "Integer" + + [database.ports.content.range] + min = 1024 + max = 49151 + + [database.connection_max] + primitive = "Integer" + required = false + default = 5000 + + [database.enabled] + primitive = "Boolean" + default = false + +# the toml should have at least one server with ip +[servers.0.ip] +primitive = "String" +required = true + +# having the following line doesn't change anything. +#[clients] +# primitive = "Array" +# required = false \ No newline at end of file diff --git a/tols.md b/tols.md new file mode 100644 index 00000000..0c5c519b --- /dev/null +++ b/tols.md @@ -0,0 +1,221 @@ +TOLS +==== + +Tom's Obvious Liuggio Scheme. + +By Tom Preston-Werner, Giulio De Donato. + +TOLS is like XSD, only more readable and simpler. + +There are 3 simple rules to follow: + +- A TOLS file is itself a valid TOML file. +- Each element could be validated. +- Explicit validation - if an element has not a validation scheme is valid by default. + +Use cases +---------- + +Given a TOLS file, as developer I want to **validate** an existant TOML file, having the proper **default** values. + +Given a TOLS file, as developer I want to easily **create** a TOML file. + +Example +------- + +```toml +# This is a TOLS document. Boom. +# This is also a TOML document. Boooom. (see rule n.1) + +[title] +primitive = "String" # the title must be a String +required = true # + [title.length] + max = 254 # max string length (exclusive <) + +[age] +primitive = "Integer" # the age must be an Integer + [age.range] + min = 17 # age is not required, but if the value is defined, should be minimum 17 (exclusive >) + max = 100 # age is not required, but if the value is defined, should be maximum 100 (exclusive <) +``` + +The above **validates** the following two examples + +```toml +title = "TOML Example" +age = 34 +``` + +```toml +title = "TOML Example" +``` + +and also could help to **generates** a toml file (see use case n.2) + +```toml +title = "" +# age = 18 +``` + +# Boolean example + +```toml +# toml +enabled = true +``` + +```toml +# tols +[enabled] +primitive = "Boolean" # Typing the enable value to Boolean +default = true +# required = false # if omitted the required is false by default +``` + +# Integer, Float and Datetime example < Boolean + +Integer, Float and Datetime share the same schema + +```toml +# toml +age = 34 +``` + +```toml +# tols +[age] +primitive = "Integer" # Typing the value +default = 190 # The default value for the current key +required = false # by default is false + [age.range] + min = 0 # (exclusive <) + max = 0 # (exclusive >) +``` + +# String example < Boolean + +```toml +# tols + +[email] +primitive = "String" # typing +required = true # default is false +# default = "liuggio@gmail.com" # the default value for the current key + [email.length] + max = 254 # max string length (exclusive <) + min = 5 # min length (exclusive >) + [email.range] + in = ["tom@github.com", "liuggio@gmail.com"] # email could be one of +pattern= "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$" #regular expression +``` + +# Array + +```toml +# toml file +data = [ ["gamma", "delta"], [1, 2] ] +``` + +Here the scheme validator + +```toml +# tols + +[data] +primitive = "Array" # Typing + [data.length] + max = 2 # max array length (exclusive <) + min = 0 # min array length (exclusive >) + [data.content] + primitive = "Array" # in toml you can't mix data types, so you could explicit the first nested content +``` +Mmmm this is so easy, I want to validate also "gamma" and "delta" how could I do? + +```toml +# tols +[data] + [data.0] # this is the first element of data ["gamma", "delta"] + primitive = "Array" # is an Array + [data.0.length] + max = 2 # max length (exclusive <) + min = 0 # min length (exclusive >) + [data.0.content] + primitive = "String" # the content should be a String +# pattern = /?/ # regular expr + [data.0.content.length] + max = 254 # content takes the String as scheme behaviour + + [data.1] # we are validating the [1, 2] + primitive = "Array" # should be an array + [data.1.length] + max = 2 # max string length (exclusive <) + min = 0 # min length (exclusive >) + [data.0.content] + primitive = "Integer" # content takes the Integer Scheme Behaviour + [data.0.content.range] + min = 0 + max = 10 +``` + +# Hash + +```toml +# toml + +[fruit.type] +apple = "yes" +orange = "no" +``` + +```toml +# tols +[fruit.type.apple] +primitive = "String" +required = true + [fruit.type.apple.length] + max = 3 +``` + +or just put the validation in the apple.type content + +```toml +# tols +[fruit.type] +primitive = "Hash" +required = true + [fruit.type.apple.length] + max = 3 + [fruit.type.apple.content] + primitive = "String" + required = true + [fruit.type.apple.content.length] + max = 3 +``` + +All the keywords +------- + +TOLS schema has 12 keywords to know. + +- **primitive** could be: ["String", "Integer", "Float", "Boolean", "Datetime", "Array", "Hash"]. + +- **default** contains the default value for the current field. + +- **required** is a Boolean value, by default is false. + +- **length** is a hash that contains two values **min** and **max**, only when primitives are [String, Array, Hash]. + +- **range** is a hash that contains values **min** and **max**, only when primitives are [Integer, Float, Datetime], + and **in** and **notin** for all primitives. + +- **pattern** is a String and contains a valid Regular Expression only when primitives is a String. + +- **content** is a Hash and describes the behaviour of the first nested element. + +- **occurrence** define the number of repetition of a primitive, is a hash with two values **min** and **max**. + +TOLS is a valid TOML file, could I validate a TOLS file? +------- + +Don't drink too much man.