xcore

package module
v2.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 2, 2022 License: MIT Imports: 14 Imported by: 56

README

@UTF-8

Go Report Card GoDoc GolangCI

XCore for GO v2

Minimum version of GO: 1.17 (for time.Time compatibility)

The XCore package is used to build basic object for programmation. for the WebAbility compatility code For GO, the actual existing code includes:

  • XCache: Application Memory Caches, thread safe.
  • XDataset: Basic nested data structures for any purpose (template injection, configuration files, database records, etc) Support thread safe operations on thread safe structures (XDatasetTS and XDatasetCollectionTS)
  • XLanguage: language dependent text tables, thread safe
  • XTemplate: template system with meta language, thread safe cloning

Manuals are available on godoc.org GoDoc

TO DO:

  • XDataset.Set should accept path too > > >
  • Get*Collection should convert types too
  • XTemplate must concatenate strings after compilation
  • Implements functions as data entry for template Execute (simple data or loop functions, can get backs anything, creates an interface) Some improvements to check, later:
  • Adds mutex on XTemplate ?? (they should be used locally on every thread, or not ??), maybe adds a flag "thread safe" ?
  • XCache: activate persistant cache too (shared memory) ????? maybe not for go itself, but for instance to talk with other memory data used by other languages and apps, or to not loose the caches if the app is restarted.

Version Changes Control

v2.1.2 - 2022-03-02

  • XTemplate: Added = to metalanguage string tags to resolve also the paths (bug corrected).

v2.1.1 - 2022-03-01

  • XTemplate: Added > to metalanguage string tags to resolve also the paths (bug corrected).

v2.1.0 - 2022-02-27

  • XLanguage: bug corrected on unlock of stringload and loadFromFile (was blocking the system)
  • XTemplate: The metalanguage keywords are now only recognized if they match authorized characters (for instance &&keyword&&), to avoid bugs in JS with && and || and !!.
  • Print functions of time.Time corrected (as in go 1.17, the print format changes) into the *test.go test functions

v2.0.9 - 2021-11-25

  • XCache modified to defer mutex unlocks instead of directly unlock into the code, to avoid dead locks in case of thread panic and crashes.
  • XLanguage modified to defer mutex unlocks instead of directly unlock into the code, to avoid dead locks in case of thread panic and crashes.

v2.0.8 - 2021-05-18

  • XTemplate is now clonable: newtemplate := template.Clone()

v2.0.7 - 2021-03-23

  • []interface{} added to NewXDataset to be decoded as []map[string]interface{} because of decoded JSON

v2.0.5 - 2021-03-23

  • function NewXDataset(data) and NewXDatasetCollection(data) added, to build XDatasets based on a classic map[string]interface{}
  • XDatasetTS added to the manual
  • XLanguage is now thread safe
  • XTemplate: Error corrected in string() function (was saying XLanguage)
  • Each cache entry is now able to manage its own TLL if set. New function SetTTL(id, duration)

v2.0.4 - 2020-04-13

  • XLanguage: Added GetEntries() func (not thread safe yet)

v2.0.3 - 2020-04-08

  • XLanguage: Error corrected on loadXMLString: the data was not loading correctly into the XLanguage object.

v2.0.1, v2.0.2 - 2020-03-29

  • Version adjustment for github and go modules v2

v2.0.0 - 2020-03-29

  • xdataset.go now as a coverage of 100% with xdataset_test.go
  • XCache now uses R/W mutex
  • New interfaces.go file to keep all the interfaces in it (XDatasetDef, XDatasetCollectionDef)
  • New xdatasetts.go for thread safe dataset
  • New xdatasetts_test.go for thread safe dataset tests
  • New xdatasetcollection.go for the collection of dataset (separation from xdataset.go)
  • New xdatasetcollection_test.go for collection tests
  • New xdatasetcollectionts.go for thread safe dataset
  • New xdatasetcollectionts_test.go for thread safe datasetcollection tests
  • XLanguage is now thread safe with R/W mutexes

v1.1.0 - 2020-03-01

  • Modularization of XCore
  • XLanguage tests and examples are now conform to Go test units
  • Implementation of XLanguage.String and XLanguage.GoString, removed Print
  • XCache tests and examples are now conform to Go test units
  • XDataset tests and examples are now conform to Go test units
  • Implementation of XDataset.String and XDataset.GoString, removed Print
  • Implementation of XDatasetCollection.String and XDatasetCollection.GoString, removed Print
  • XTemplate tests and examples are now conform to Go test units
  • Implementation of XTemplate.String and XTemplate.GoString, removed Print

v1.0.1 - 2020-02-10

  • Documentation corrections
  • Bug on String() and GoString() corrected

v1.0.0 - 2020-02-09

  • Version leveling
  • Documentation corrections
  • Change functions Stringify() by String() and GoString() for language compatibility
  • Tests functions enhanced

v0.3.1 - 2020-02-09

  • XDatasetDef.Get must accept a path as key (id>id>id)
  • XTemplates now resolve {{ fields with path id>id>id
  • XTemplates now resolve @@ metalanguage with 1 and 2 Parameters
  • XTemplates now resolve && metalanguage with 1,2 and 3 Parameters
  • XTemplates now resolve ?? metalanguage with 1, and 2 Parameters
  • XTemplates now resolve !! debug orders
  • XTemplates now implements sub templates derivation (.none .first .last .(number) )
  • Manuals for XCache, XLanguage and XTemplate written with reference of the metalanguage
  • Examples for dataset and xtemplate added (working version)
  • XDataset and XDatasetCollection .Stringify now prints also field names.

v0.3.0 - 2020-02-06

  • The properties of XTemplateParam are now public so the full structure can be used to build other type of code based on the XTemplate rules
  • The subtemplates IDs must be lowers, numbers and . - _ in sight of integration with other systems that can mix tags [[]] within the code

v0.2.3 - 2020-01-23

  • Corrected a bug to avoid null pointer panic error if the array of data for XTemplate.Execute function is nil

v0.2.2 - 2019-12-21

  • XLanguage now support golang x/text/language instead of direct iso 2 charater language
  • godoc manuals for xlanguage, xdataset and xtemplate prepared

v0.2.1 - 2019-12-13

  • XCache manual enhanced with examples

v0.2.0 - 2019-12-06

  • XCache Code simplified to expose XCache definition as public, remove not usefull funcion (Get*)
  • XCache 0.2.0 is not compatible with XCache 0.1.* , you may need to change your code
  • Added more conversions between int-float-bool in XDataset.Get*

v0.1.2 - 2019-12-05

  • Code cleaned to meet golangci standards, golint checks, more documentation.

V0.1.1 - 2019-11-05

  • XCore Code comments enhanced to publish in godoc.org as libraries documentation

V0.1.0 - 2019-10-18

  • Code cleaned to pass 100% of goreportcard.com. Card note added in this document

V0.0.9 - 2019-07-18

  • Error corrected on XCache: removing an element from a slice when the element is the last one was causing out of bound index.
  • XCache.maxitem = 0 (no number of elements limit) is corrected: it was not working

V0.0.8 - 2019-06-25

  • Added Clone on XDatasetDef and XDataCollectionsetDef
  • XDataset testunit added

V0.0.7 - 2019-03-06

  • Time functions added to XDatasetDef and XDatasetCollectionDef interfaces, and XDataset and XDatasetCollection structures
  • Manual for XCache finished
  • Manual for XDataset finished
  • Preformat for XLanguage manual
  • Preformat for XTemplate manual

V0.0.6 - 2019-02-07

  • Added xcache.GetId(), xcache.GetMax() and xcache.GetExpire()
  • XCache Documentation modified

V0.0.5 - 2019-02-05

  • Added conversion between types con XDataset.Get* functions
  • Manuals for XDataSet and XTemplate complemented

V0.0.4 - 2019-01-06

  • XDataset.Get* functions added to comply with any type of data of a dataset for templates, config, database record etc.
  • XCache manual completed.

V0.0.3 - 2019-01-02

  • Added XCache.Flush function
  • Function XCache.Del implemented
  • Function XCache.Clean implemented for expiration, and free some space
  • Function XCache.Verify created
  • Function XCache.SetValidator added, to check cache validity agains a validator function
  • Files flags and code removed from XCache. If the cache is a file, the user should controls the files with its own Validator function (original funcions put in examples as a file validator). This lets a lots of flexibility to validate against any source of data (files, database, complex calculations, external streams, etc)
  • XCache is ready for candidate release

V0.0.2 - 2018-12-17

  • Creation of XCache with all set of functions.
  • Creation of XLanguage with all set of functions.
  • Creation of XTemplate with all set of functions. Basic work done
  • Creation of a set of interfaces that XTemplate need to execute and inject the template,
  • Creation of a basic XDataset and colection based on interfaces to build a set of data for the template.
  • Added xcore.go with version number as constant

V0.0.1 - 2018-11-14

  • First basic commit with XLanguage object created

Documentation

Overview

Package xcore is a set of basic objects for programation (XCache for caches, XDataset for data sets, XLanguage for languages and XTemplate for templates). For GO, the actual existing code includes:

- XCache: Application Memory Caches for any purpose, with time control and quantity control of object in the cache and also check changes against original source. It is a thread safe cache.

- XDataset: Basic nested data structures for any purpose (template injection, configuration files, database records, etc).

- XLanguage: language dependent text tables for internationalization of code. The sources can be text or XML file definitions.

- XTemplate: template system with meta language to create complex documents (compatible with any text language, HTML, CSS, JS, PDF, XML, etc), heavily used on CMS systems and others.

It is already used on sites that serve more than 60 million pages a month (500 pages per second on pike hour) and can be used on multithreading environment safely.

XCache

XCache is a library to cache all the data you want into current application memory for a very fast access to the data. The access to the data support multithreading and concurrency. For the same reason, this type of cache is not persistent (if you exit the application) and cannot grow too much (as memory is the limit). However, you can control a timeout of each cache piece, and eventually a comparison function against a source (file, database, etc) to invalid the cache.

1. Declare a new XCache with NewXCache() function:

import "github.com/webability-go/xcore"

// 50 items max
var myfiles = xcore.NewXCache("myfiles", 50, 0)

// 10 minutes expiration
var mydbtable = xcore.NewXCache("mydb-table", 0, 10 * time.Minute)

// No direct limits on the cache
var myotherdbtable = xcore.NewXCache("mydb-table", 0, 0)

2. Fill in the cache:

Once you have declared the cache, you can fill it with anything you want. The main cache object is an interface{} so you can put here anything you need, from simple variables to complex structures. You need to use the Set function: Note the ID is always a string, so convert a database key to string if needed.

func main() {
  myfiles.Set("https://developers.webability.info/", "somedata")
  myfiles.Set("/home/sites/file2.txt", "someotherdata")
	myrecords := GetAllMyDatabaseTableData()
	for _, rec := range myrecords {
    key, _ := rec.GetString("key")
		mydbtable.Set(key, rec)
  }
}

3. To use the cache, just ask for your entry with Get function:

func usemycache() {

  filedata, invalid := myfiles.Get("https://developers.webability.info/");
  dbdata, invalid2 := mydbtable.Get("4455");
  // do something with the fetched data
}

4. To maintain the cache:

You may need Del function, to delete a specific entry (maybe because you deleted the record in database). You may also need Clean function to deletes a percentage of the cache, or Flush to deletes it all. The Verify function is used to check cache entries against their sources through the Validator function. Be very careful, if the cache is big or the Validator function is complex (maybe ask for a remote server information), the verification may be VERY slow and huge CPU use. The Count function gives some stats about the cache.

func analyze() {

  // Actual size of cache
  fmt.Println(mydbtable.Count())
  // Removes 30% of objects
  objectsremoved := mydbtable.Clean(30)
  // New size of cache
  fmt.Println(mydbtable.Count())
  // totally flush the cache
  mydbtable.Flush()
  // New size of cache, should be 0
  fmt.Println(mydbtable.Count())
}

5. How to use Verify Function:

This function is recommended when the source is local and fast to check (for instance a language file or a template file). When the source is distant (other cluster database, any rpc source on another network, integration of many parts, etc), it is more recommended to create a function that will delete the cache when needed (on demand cache change).

The validator function is a func(id, time.Time) bool function. The first parameter is the ID entry in the cache, the second parameter the time of the entry was created. The validator function returns true is the cache is still valid, or false if it needs to be invalidated.

 var myfiles = xcore.NewXCache("myfiles", 50, 0)
 myfiles.Validator = FileValidator

 // FileValidator verify the file source. In this case, the ID is directly the filename full path
 func FileValidator(key string, otime time.Time) bool {

	  fi, err := os.Stat(key)
	  if err != nil {
		  // Does not exists anymore, invalid
		  return false
	  }
	  mtime := fi.ModTime()
	  if mtime.After(otime) {
		  // file is newer, invalid
	  	return false
 	}
	  // All ok, valid
	  return true
 }

The XCache is thread safe. The cache can be limited in quantity of entries and timeout for data. The cache is automanaged (for invalid expired data) and can be cleaned partially or totally manually.

XLanguage

The XLanguage table of text entries can be loaded from XML file, XML string or normal text file or string. It is used to keep a table of id=value set of entries in any languages you need, so it is easy to switch between XLanguage instance based on the required language needed. Obviously, any XLanguage you load in any language should have the same id entries translated, for the same use. The XLanguage object is thread safe

1. loading:

You can load any file or XML string directly into the object.

1.1 The XML Format is:

<?xml version="1.0" encoding="UTF-8"?>
<language id="NAMEOFTABLE" lang="LG">
  <entry id="ENTRYNAME">ENTRYVALUE</entry>
  <entry id="ENTRYNAME">ENTRYVALUE</entry>
  etc.
</language>

NAMEOFTABLE is the name of your table entry, for example "loginform", "user_report", etc.

LG is the ISO-3369 2 letters language ID, for example "es" for spanish, "en" for english, "fr" for french, etc.

ENTRYNAME is the ID of the entry, for example "greating", "yourname", "submitbutton".

ENTRYVALUE is the text for your entry, for example "Hello", "You are:", "Save" if your table is in english.

1.2 The flat text format is:

ENTRYNAME=ENTRYVALUE
ENTRYNAME=ENTRYVALUE
etc.

ENTRYNAME is the ID of the entry, for example "greating", "yourname", "submitbutton".

ENTRYVALUE is the text for your entry, for example "Hello", "You are:", "Save" if your table is in english.

There is no name of table or language in this format (you "know" what you are loading).

The advantage to use XML format is to have more control over your language, and eventyally add attributes into your entries, for instance you may add attributes translated="yes/no", verified="yes/no", and any other data that your system could insert. The XLanguage will ignore those attributes loading the table.

2. creation:

To create a new XLanguage empty structure:

lang := NewXLanguage(id, language)

There are 4 functions to create the language from a file or string, flat text or XML text:

langfromxmlfile := NewXLanguageFromXMLFile("path/to/filename")
langfromxmlstring := NewXLanguageFromXMLString("<xml>...")
langfromtextfile := NewXLanguageFromFile("path/to/file")
langfromtextstring := NewXLanguageFromString("entry=data\n...")

Then you can use the set of basic access functions:

SetName/SetLanguage functions are used to set the table name and language of the object (generally to build an object from scratch). GetName/GetLanguage functions are used to get the table name and language of the object (generally when you load it from some source). Set/Get/Del functions are used to add or modify a new entry, read an entry, or deletes an entry in the object.

XDataSet

1. Overview:

The XDataSet is a set of interfaces and basic classes ready-to-use to build a standard set of data optionally nested and hierarchical, that can be used for any purpose:

- Keep complex data in memory.

- Create JSON structures.

- Inject data into templates.

- Interchange database data (records set and record).

You can store into it generic supported data, as well as any complex interface structures:

- Int

- Float

- String

- Time

- Bool

- []Int

- []Float

- []Time

- []Bool

- XDataSetDef (anything extended with this interface)

- []String

- Anything else ( interface{} )

- XDataSetCollectionDef (anything extended with this interface)

The generic supported data comes with a set of functions to get/set those data directly into the XDataset.

Example:

import "github.com/webability-go/xcore"

data := xcore.XDataset{}
data["data1"] = "DATA1"
data["data2"] = "DATA1"
sm := xcore.XDataset{}
sm["data31"] = "DATA31"
data["data3"] = sm
data["data4"] = 123
data["data5"] = 123.432
data["data6"] = true
data["data7"] = func() string { return "ABC" }

d8_r1 := &xcore.XDataset{}
d8_r1.Set("data81", "rec 1: Entry 8-1")
d8_r1.Set("data82", "rec 1: Entry 8-2")

d8_r2 := &xcore.XDataset{}
d8_r2.Set("data81", "rec 2: Entry 8-1")
d8_r2.Set("data82", "rec 2: Entry 8-2")
d8_r2.Set("data83", "rec 2: Entry 8-3")

d8_r3 := &xcore.XDataset{}
d8_r3.Set("data81", "rec 3: Entry 8-1")
d8_r3.Set("data82", "rec 3: Entry 8-2")

d := xcore.XDatasetCollection{}
d.Push(d8_r1)
d.Push(d8_r2)
d.Push(d8_r3)

data["data8"] = &d
data["data9"] = "I exist"

Note that all references to XDataset and XDatasetCollection are pointers, always (to be able to modify the values of them).

2. XDatasetDef interface:

It is the interface to describe a simple set of data mapped as "name": value, where value can be of any type.

The interface implements a good amount of basic methods to get the value on various format such as GetString("name"), GetInt("name"), etc (see below).

If the value is another type as asked, the method should contert it if possible. For instance "key":123 required through GetString("key") should return "123".

The XDataset type is a simple map[string]interface{} with all the implemented methods and should be enough to use for almost all required cases.

However, you can build any complex structure that extends the interface and implements all the required functions to stay compatible with the XDatasetDef.

3. XDatasetCollectionDef Interface:

This is the interface used to extend any type of data as a Collection, i-e an array of XDatasetDef. This is a slice of any XDatasetDef compatible data.

The interface implements some methods to work on array structure such as Push, Pop, Shift, Unshift and some methods to search data into the array.

The XDatasetCollection type is a simple []DatasetDef with all the implemented methods and should be enough to use for almost all required cases.

XDataSetTS

1. Overview:

The XDataSetTS is a DatasetDef structure, thread safe. It is build on the XDataset with the same properties, but is thread safe to protect Read/Write accesses from different thread.

Example:

import "github.com/webability-go/xcore/v2"

data := &xcore.XDatasetTS{} // data is a XDatasetDef
data.Set("data1", "DATA1")
data.Set("newkey", 123.45)

You may also build a XDatasetTS to encapsulate a XDatasetDef that is not thread safe, to use it safely

import "github.com/webability-go/xcore/v2"

datanots := xcore.NewXDataset()
datats := xcore.NewXDatasetTS(datanots)

Note that all references to XDatasetTS are pointers, always (to be able to modify the values of them).

The DatasetTS meet the XDatasetDef interface

XTemplate

1. Overview:

This is a class to compile and keep a Template that can be injected with an XDataSet structure of data, with a metalanguage to inject the data.

The metalanguage is extremely simple and is made to be useful and **really** separate programation from template code (not like other many generic template systems that just mix code and data).

A template is a set of HTML/XML (or any other language) string with a meta language to inject variables and build a final string.

The XCore XTemplate system is based on the injection of parameters, language translation strings and data fields directly into the HTML (Or any other language you need) template.

The HTML itself (or any other language) is a text code not directly used by the template system, but used to dress the data you want to represent in your preferred language.

The variables to inject must be into a XDataSet structure or into a structure extended from XDataSetDef interface.

The injection of data is based on a XDataSet structure of values that can be nested into another XDataSet and XDataSetConnection and so on.

The template compiler recognize nested arrays to automatically make loops on the information.

Templates are made to store reusable HTML code, and overall easily changeable by people that do not know how to write programs.

A template can be as simple as a single character (no variables to inject) to a very complex nested, conditional and loops sub-templates.

Hello world!

Yes. this is a template, but a very simple one without need to inject any data.

Let's go more complex:

Having an array of data, we want to paint it beautifull:

{ "clientname": "Fred",
  "hobbies": [
     { "name": "Football" },
     { "name": "Ping-pong" },
     { "name": "Swimming" },
     { "name": "Videogames" }
  ]
}

We can create a template to inject this data into it:

%-- This is a comment. It will not appear in the final code. --%
Let's put your name here: {{clientname}}<br />
And lets put your hobbies here:<br />
@@hobbies:hobby@@     %-- note the 1rst id is the entry into the data to inject and the second one is the name of the sub-template to use --%

%-- And you need the template for each hobby:--%
[[hobby]]
I love {{name}}<br />
[[]]

2. Create and use XTemplateData:

In sight to create and use templates, you have all those possible options to use:

Creates the XTemplate from a string or a file or any other source:

package main

import (
  "fmt"
  "github.com/webability-go/xcore"
)

func main() {
  tmpl, _ := xcore.NewXTemplateFromString(`
%-- This is a comment. It will not appear in the final code. --%
Let's put your name here: {{clientname}}<br />
And lets put your hobbies here:<br />
@@hobbies:hobby@@     %-- note the 1rst id is the entry into the data to inject and the second one is the name of the sub-template to use --%

%-- And you need the template for each hobby:--%
[[hobby]]
I love {{name}}<br />
[[]]
`)
  // The creation of the data is obviously tedious here, in real life it should come from a JSON, a Database, etc
  data := xcore.XDataset{
    "clientname": "Fred",
    "hobbies": &XDatasetCollection{
      &XDataset{"name":"Football"},
      &XDataset{"name":"Ping-pong"},
      &XDataset{"name":"Swimming"},
      &XDataset{"name":"Videogames"},
    },
  }

  fmt.Println(tmpl.Execute(&data)
}

Clone the XTemplate:

xtemplate := xcore.NewXTemplate()
xtemplatecloned := xtemplate.Clone()

3. Metalanguage Reference:

3.1 Comments: %-- and --%

You may use comments into your template. The comments will be discarded immediately at the compilation of the template and do not interfere with the rest of your code.

Example:

%-- This is a comment. It will not appear in the final code. --%

%--
This subtemplate will not be compiled, usable or even visible since it is into a comment
[[templateid]]
Anything here
[[]]
--%

3.2 Nested Templates: [[...]] and [[]]

You can define new nested templates into your main template A nested template is defined by:

[[templateid]]
your nested template here
[[]]

The templteid is any combination of lowers letters only (a-z), numbers (0-9), and 3 special chars: . (point) - (dash) and _ (underline).

The template is closed with [[]].

There is no limits into nesting templates.

Any nested template will inheritate all the father elements and can use father elements too.

To call a sub-template, you need to use &&templateid&& syntax (described below in this document).

Example:

&&header&&
Welcome to my page
&&footer&&

[[header]]
<hr />
[[]]

[[footer]]
<hr />
&&copyright&&

  [[copyright]]
    © 2012 Ing. Philippe Thomassigny, a project of the WebAbility® Network.
  [[]]
[[]]

You may use more than one id into the same template to avoid repetition of the same code. The different id's are separated with a pipe |

[[looptemplate_first|looptemplate_last|looptemplate_odd]] %-- First element, last element and all odd elements will be red --%
  <div style="color: red;">{{data}}</div>
[[]]
[[looptemplate]] %-- All the other elements will be blue --%
  <div style="color: blue;">{{data}}</div>
[[]]

Important note: A template will be visible only on the same level of its declaration. For example, if you put a subtemplate "b" into a subtemplate "a", it will not be visible by &&b&& from the top level, but only into the subtemplate "a".

&&header&&
Welcome to my page
&&footer&&
&&copyright&& %-- WILL NOT WORK, into a sub-template --%

[[header]]
<hr />
[[]]

[[footer]]
<hr />
&&copyright&& %-- WILL WORK, same level --%

  [[copyright]]
    © 2012 Ing. Philippe Thomassigny, a project of the WebAbility® Network.
  [[]]
[[]]

3.3 Simple Elements: ##...## and {{...}}

There are 2 types of simple elements. Language elements and Data injector elements (also called field elements).

We "logically" define the 2 type of elements. The separation is only for human logic and template filling, however the language information can perfectly fit into the data to inject (and not use ## entries).

3.3.1 Languages elements: ##entry##

All the languages elements should have the format: ##entry##.

A language entry is generally anything written into your code or page that does not come from a database, and should adapt to the language of the client visiting your site.

Using the languages elements may depend on the internationalization of your page.

If your page is going to be in a single language forever, you really dont need to use languages entries.

The language elements generally carry titles, menu options, tables headers etc.

The language entries are set into the "#" entry of the main template XDataset to inject, and is a XLanguage table.

Example:

<div style="background-color: blue;">
##welcome##<br />
You may use the same parameter as many time you wish.<br />

<span onclick="alert('##hello##');" class="button">##clickme##!</span>
<span onclick="alert('##helloagain##');" class="button">##clickme## ##again##!</span>

</div>

With data to inject:

{
  "#": {
    "welcome": "Bienvenue",
    "clickme": "Clique sur moi",
    "again": "de nouveau"
  }
}

3.3.2 Field elements: {{fieldname}}

Fields values should have the format: {{fieldname}}.

Your fields source can be a database or any other preferred repository data source.

Example:

<div style="background-color: blue;">
Welcome to my site<br />
You may use the same parameter as many time you wish.<br />

Today's temperature is {{degres}} celsius<br />
or {{fdegres}} farenheit<br />

Is {{degres}} degres too cold ? Buy a pullover!<br />

</div>

You can access an element with its path into the data set to inject separating each field level with a > (greater than).

{{hobbies>1>name}}

This will take the name of the second hobby in the dataset defined upper. (collections are 0 indexed).

The 1 denotes the second record of the hobbies XDatasetCollection.

If the field is not found, it will be replaced with an empty string.

Tecnically your field names can be any string in the dataset. However do not use { } or > into the names of your fields or the XTemplate may not use them correctly.

We recommend to use lowercase names with numbers and ._- Accents and UTF8 symbols are also welcome.

3.3.3 Scope:

When you use an id to point a value, the template will first search into the available ids of the local level. If no id is found, the it will search into the upper levers if any, and so on.

Example:

{
  "detail": {
    "data1": {
      "data2": {
        "key1": {"appname": "Nested App", "name": "Juan", "status": 1},
        "key2": {"name": "José", "status": 2},
        "appname" => "DomCore"
      }
    }
  }
}

At the level of 'data2', using {{appname}} will get back 'DomCore'.

At the level of 'key1', using {{appname}} will get back 'Nested App'.

At the level of 'key2', using {{appname}} will get back 'DomCore'.

At the level of root, 'data1' or 'detail', using {{appname}} will get back an empty string.

3.3.4 Path access: id>id>id>id

At any level into the data array, you can access any entry into the subset array.

For instance, taking the previous array of data to inject, let's suppose we are into a nested meta elements at the 'data1' level. You may want to access directly the 'Juan' entry. The path will be:

{{data2>key1>name}}

The José's status value from the root will be:

{{detail>data1>data2>key2>status}}

3.4 Meta Elements

They consist into an injection of a XDataset, called the "data to inject", into the template.

The meta language is directly applied on the structure of the data array.

The data to inject is a nested set of variables and values with the structure you want (there is no specific construction rules).

You can inject nearly anything into a template meta elements.

Example of a data array to inject:

data := xcore.XDataset{
  "clientname": "Fred",
  "clientpicture": "face.jpg",
  "hobbies": &XDatasetCollection{
    &XDataset{"name":"Football","sport":"yes"},
    &XDataset{"name":"Ping-pong","sport":"yes"},
    &XDataset{"name":"Swimming","sport":"yes"},
    &XDataset{"name":"Videogames","sport":"no"},
  },
  "preferredhobby": &XDataset{
    "name":"Baseball",
    "sport":"yes",
  },
  "metadata": &XDataset{
    "preferred-color": "blue",
    "Salary": 3568.65,
    "hiredate": time.Time("2020-01-01T12:00:00"),
  },
}

You can access directly any data into the array with its relative path (relative to the level you are when the metaelements are applied, see below).

There are 4 structured meta elements in the XTemplate templates to use the data to inject:

Reference, Loops, Condition and Debug.

The structure of the meta elements in the template must follow the structure of the data to inject.

3.4.1 References to another template: &&order&&

3.4.1.1 When order is a single id (characters a-z0-9.-_), it will make a call to a sub template with the same set of data and replace the &&...&& with the result. The level in the data set is not changed.

Example based on previous array of Fred's data:

&&header&&
&&body&&

[[header]]
Sports shop<hr />
[[]]

[[body]]
{{clientname}} Data:
<img src="{{clientpicture}}" title="{{clientname}}" />
[[]]

3.4.1.2 When order contains 2 parameters separated by a semicolumn :, then second parameter is used to change the level of the data of array, with the subset with this id. The level in the data set is changed to this sub set.

Example based on previous array of Fred's data:

&&header&&
&&body:metadata&&

[[header]]
Sports shop<hr />
[[]]

[[body]]
{{clientname}} Data:  %-- Taken from the root data --%
Salary: {{salary}}<br /> %-- taken from the metadata subset --%
Hire date: {{hiredate}}<br /> %-- taken from the metadata subset--%
[[]]

3.4.1.3 When order contains 3 parameters separated by a semicolumn :, the second and third parameters are used to search the name of the new template based on the data fields to inject.

This is an indirect access to the template. The name of the subtemplate is build with parameter3 as prefix and the content of parameter2 value. The third parameter must be empty.

&&header&&
&&body:preferredhobby&&

[[header]]
Sports shop<hr />
[[]]

[[body]]
{{clientname}} Preferred hobby:
&&:sport:sport.&&  %-- will build sport_ + [yes/no] contained into the sport field. Be sure you have a template for each value ! --%

[[sport.yes]]{{name}} - It's a sport, sell him things![[]]
[[sport.no]]{{name}} - It's not a sport, recommend him next store.[[]]
[[sport]]{{name}} - We do not know that it is.[[]]
[[]]

3.4.2 Loops: @@order@@

3.4.2.1 Overview

This meta element will loop over each itterance of the set of data and concatenate each created template in the same order. You need to declare a sub template for this element.

You may aso declare derivated sub templates for the different possible cases of the loop: For instance, If your main subtemplate for your look is called "hobby", you may need a different template for the first element, last element, Nth element, Element with a value "no" in the sport field, etc.

The supported postfixes are:

When the array to iterate is empty:

- .none (for example "There is no hobby")

When the array contains elements, it will search in order, the following template and use the first found:

- templateid.key.[value] value is the key of the vector line. If the collection has a named key (string) or is a direct array (0, 1, 2...)

- templateid.first if it is the first element of the array set (new from v1.01.11)

- templateid.last if it is the first element of the array set (new from v1.01.11)

- templateid.even if the line number is even

- templateid in all other cases (odd is contained here if even is defined)

3.4.2.2 When order is a single id (characters a-z0-9.-_), it will make a call to the sub template id with the same subset of data with the same id and replace the @@...@@ for each itterance of the data with the result.

Example based on previous array of Fred's data:

&&header&&
&&body&&

[[header]]
Sports shop<hr />
[[]]

[[body]]
{{clientname}} Data:
<img src="{{clientpicture}}" title="{{clientname}}" />
Main hobby: {{preferredhobby>name}}<br />
Other hobbies:<br />
@@hobbies@@
[[hobbies.none]]There is no hobby<br />[[]]
[[hobbies]]{{name}}<br />[[]]
[[]]

3.4.2.3 When order contains 2 parameters separated by a semicolumn :, then first parameter is used to change the level of the data of array, with the subset with this id, and the second one for the template to use.

Example based on previous array of Fred's data:

&&header&&
&&body&&

[[header]]
Sports shop<hr />
[[]]

[[body]]
{{clientname}} Data:
<img src="{{clientpicture}}" title="{{clientname}}" />
Main hobby: {{preferredhobby>name}}<br />
Other hobbies:<br />
@@hobbies:hobby@@ %-- will iterate over hobbies in the data, but with hobby sub template --%
[[hobby.none]]There is no hobby<br />[[]]
[[hobby.key.1]]<span style="color: red;">{{name}}<span><br /><hr>[[]] %-- Paint the second line red (0 indexed) --%
[[hobby]]{{name}}<br />[[]]
[[]]

3.4.3 Conditional: ??order??

Makes a call to a subtemplate only if the field exists and have a value. This is very userfull to call a sub template for instance when an image or a video is set.

When the condition is not met, it will search for the [id].none template. The conditional element does not change the level in the data set.

3.4.3.1 When order is a single id (characters a-z0-9.-_), it will make a call to the sub template id with the same field in the data and replace the ??...?? with the corresponding template

Example based on previous array of Fred's data:

&&header&&
&&body&&

[[header]]
 Sports shop<hr />
[[]]

[[body]]
 {{clientname}} Data:
 ??clientpicture??
 [[clientpicture]]<img src="{{clientpicture}}" title="{{clientname}}" />[[]]
 [[clientpicture.none]]There is no photo<br />[[]]
[[]]

3.4.3.2 When order contains 2 parameters separated by a semicolumn :, then second parameter is used to change the level of the data of array, with the subset with this id.

Example based on previous array of Fred's data:

&&header&&
&&body&&

[[header]]
 Sports shop<hr />
[[]]

[[body]]
 {{clientname}} Data:
 ??clientpicture:photo??
 [[photo]]<img src="{{clientpicture}}" title="{{clientname}}" />[[]]
 [[photo.none]]There is no photo<br />[[]]
[[]]

If the asked field is a catalog, true/false, numbered, you may also use .[value] subtemplates

&&header&&
&&body&&

[[header]]
 Sports shop<hr />
[[]]

[[body]]
 {{clientname}} Data:
 ??preferredhobby>sport:preferredhobby??
 [[preferredhobby.yes]]{{preferredhobby>name}}<br />[[]]
 [[preferredhobby|preferredhobby.no|preferredhobby.none]]There is no preferred sport<br />[[]]
[[]]

3.5 Debug Tools: !!order!!

There are two keywords to dump the content of the data set. This is very useful when you dont know the code that calls the template, don't remember some values, or for debug facilities.

3.5.1 !!dump!!

Will show the totality of the data set, with ids and values.

3.5.1 !!list!!

Will show only the tree of parameters, values are not shown.

Index

Examples

Constants

View Source
const (
	MetaString  = 0 // a simple string to integrate into the code
	MetaComment = 1 // Comment, ignore it

	MetaLanguage  = 2 // one param of the URL parameters list, index-1 based [page]/value1/value2...
	MetaReference = 3 // an URL variable coming through a query ?variable=value
	MetaRange     = 4 // Parameter passed to the page Run by code
	MetaCondition = 5 // System (site) parameter
	MetaDump      = 6 // Main page called parameters (into .page file)
	MetaVariable  = 7 // this page parameters (into .page file), same as Main page parameters if it's the external called page

	MetaTemplateStart = 101 // Temporal nested box start tag
	MetaTemplateEnd   = 102 // Temporal nested box end tag

	MetaUnused = -1 // a "not used anymore" param to be freed
)

MetaString and other consts:

type of elements present in the template
View Source
const VERSION = "2.1.2"

VERSION is the used version nombre of the XCore library.

Variables

View Source
var LOG = false

LOG is the flag to activate logging on the library. if LOG is set to TRUE, LOG indicates to the XCore libraries to log a trace of functions called, with most important parameters. LOG can be set to true or false dynamically to trace only parts of code on demand.

Functions

This section is empty.

Types

type XCache

type XCache struct {
	// "ID": XCache has a unique id (informative).
	ID string
	// "Maxitems": The user can creates a cache with a maximum number of elements into it. In this case, when the cache reaches the maximum number of elements stored, then the system makes a clean of 10% of the oldest elements. This type of use is not recommended since is it heavy in CPU use to clean the cache.
	Maxitems int
	// "Validator" is a function that can be set to check the validity of the data (for instance if the data originates from a file or a database). The validator is called for each Get (and can be heavy for CPU or can wait a long time, for instance if the check is an external database on another cluster). Beware of this.
	Validator func(string, time.Time) bool
	// "Expire": The user can also create an expiration duration, so every elements in the cache is invalidated after a certain amount of time. It is more recommended to use the cache with an expiration duration. The obsolete objects are destroyed when the user tries to use them and return a "non existence" on Get. (this does not use CPU or extra locks).
	Expire time.Duration
	// contains filtered or unexported fields
}

XCache is the main cache structure, that contains a collection of XCacheEntries and some metadata.

func NewXCache

func NewXCache(id string, maxitems int, expire time.Duration) *XCache

NewXCache function will create a new XCache structure. The XCache is resident in memory, supports multithreading and concurrency. "id" is the unique id of the XCache. "maxitems" is the max authorized quantity of objects into the XCache. If 0, the cache hast no limit in quantity of objects. "expire" is a max duration of the objects into the cache. If 0, no limit Returns the *XCache created.

Example
cache1 := NewXCache("cacheid1", 0, 0)
cache2 := NewXCache("cacheid2", 100, 0)
cache3 := NewXCache("cacheid3", 0, 100*time.Minute)

fmt.Println("All caches empty:", cache1.Count(), cache2.Count(), cache3.Count())
Output:

All caches empty: 0 0 0

func (*XCache) Clean

func (c *XCache) Clean(perc int) int

Clean will delete expired entries, and free perc% of max items based on time. perc = 0 to 100 (percentage to clean). Returns quantity of removed entries. It Will **not** verify the cache against its source (if Validator is set). If you want to scan that, use the Verify function.

func (*XCache) Count

func (c *XCache) Count() int

Count will return the quantity of entries in the cache.

func (*XCache) Del

func (c *XCache) Del(key string)

Del will delete the entry of the cache if it exists.

func (*XCache) Flush

func (c *XCache) Flush()

Flush will empty the whole cache and free all the memory of it. Returns nothing.

func (*XCache) Get

func (c *XCache) Get(key string) (interface{}, bool)

Get will get the value of an entry. If the entry does not exists, returns nil, false. If the entry exists and is invalidated by time or validator function, then returns nil, true. If the entry is good, return <value>, false.

func (*XCache) Set

func (c *XCache) Set(key string, indata interface{})

Set will set an entry in the cache. If the entry already exists, just replace it with a new creation date. If the entry does not exist, it will insert it in the cache and if the cache if full (maxitems reached), then a clean is called to remove 10%. Returns nothing.

func (*XCache) SetTTL added in v2.0.6

func (c *XCache) SetTTL(key string, duration time.Duration)

Set will set a TTL on the entry in the cache. If the entry exists, just ads the TTL to the entry If the entry does not exist, it does nothing Returns nothing.

func (*XCache) Verify

func (c *XCache) Verify() int

Verify will first, Clean(0) keeping all the entries, then will delete expired entries using the Validator function. Returns the quantity of removed entries. Based on what the validator function does, calling Verify can be **very** slow and cpu dependant. Be very careful.

type XCacheEntry

type XCacheEntry struct {
	// contains filtered or unexported fields
}

XCacheEntry is the cache basic structure to save some data in memory.

type XDataset

type XDataset map[string]interface{}

XDataset is the basic dataset type that is xdatasetdef inferface compatible XDataset IS NOT thread safe

Example
tmp, _ := time.Parse(time.RFC3339, "2020-01-01T12:00:00.0Z")
ds := &XDataset{
	"v1":  123,
	"v2":  "abc",
	"vt":  tmp,
	"v3":  true,
	"vpi": 3.1415927,
}
fmt.Println(ds)

data := &XDataset{
	"clientname":    "Fred",
	"clientpicture": "face.jpg",
	"hobbies": &XDatasetCollection{
		&XDataset{"name": "Football", "sport": "yes"},
		&XDataset{"name": "Ping-pong", "sport": "yes"},
		&XDataset{"name": "Swimming", "sport": "yes"},
		&XDataset{"name": "Videogames", "sport": "no"},
	},
	"preferredhobby": &XDataset{
		"name":  "Baseball",
		"sport": "yes",
	},
	"metadata": &XDataset{
		"preferred-color": "blue",
		"Salary":          3568.65,
		"hiredate":        tmp,
	},
}

fmt.Println(data)
Output:

xcore.XDataset{v1:123 v2:abc v3:true vpi:3.1415927 vt:2020-01-01 12:00:00 +0000 UTC}
xcore.XDataset{clientname:Fred clientpicture:face.jpg hobbies:XDatasetCollection[0:xcore.XDataset{name:Football sport:yes} 1:xcore.XDataset{name:Ping-pong sport:yes} 2:xcore.XDataset{name:Swimming sport:yes} 3:xcore.XDataset{name:Videogames sport:no} ] metadata:xcore.XDataset{Salary:3568.65 hiredate:2020-01-01 12:00:00 +0000 UTC preferred-color:blue} preferredhobby:xcore.XDataset{name:Baseball sport:yes}}

func (*XDataset) Clone

func (d *XDataset) Clone() XDatasetDef

Clone will creates a totally new data memory cloned from this object

func (*XDataset) Del

func (d *XDataset) Del(key string)

Del will deletes the variable

func (*XDataset) Get

func (d *XDataset) Get(key string) (interface{}, bool)

Get will read the value of the key variable

func (*XDataset) GetBool

func (d *XDataset) GetBool(key string) (bool, bool)

GetBool will read the value of the key variable as a boolean cast type If the value is int, float, it will be convert with the rule 0: false, != 0: true If the value is anything else and it exists, it will return true if it's not nil

func (*XDataset) GetBoolCollection

func (d *XDataset) GetBoolCollection(key string) ([]bool, bool)

GetBoolCollection will read the value of the key variable as a collection of bool cast type

func (*XDataset) GetCollection

func (d *XDataset) GetCollection(key string) (XDatasetCollectionDef, bool)

GetCollection will read the value of the key variable as a XDatasetCollection cast type

func (*XDataset) GetDataset

func (d *XDataset) GetDataset(key string) (XDatasetDef, bool)

GetDataset will read the value of the key variable as a XDatasetDef cast type

func (*XDataset) GetFloat

func (d *XDataset) GetFloat(key string) (float64, bool)

GetFloat will read the value of the key variable as a float64 cast type

func (*XDataset) GetFloatCollection

func (d *XDataset) GetFloatCollection(key string) ([]float64, bool)

GetFloatCollection will read the value of the key variable as a collection of float cast type If the field is not an array it will be converted to an array. If the field is an array of another type, it will be converted.

func (*XDataset) GetInt

func (d *XDataset) GetInt(key string) (int, bool)

GetInt will read the value of the key variable as an integer cast type If the value is bool, will return 0/1 If the value is float, will return integer part of value

func (*XDataset) GetIntCollection

func (d *XDataset) GetIntCollection(key string) ([]int, bool)

GetIntCollection will read the value of the key variable as a collection of int cast type

func (*XDataset) GetString

func (d *XDataset) GetString(key string) (string, bool)

GetString will read the value of the key variable as a string cast type

func (*XDataset) GetStringCollection

func (d *XDataset) GetStringCollection(key string) ([]string, bool)

GetStringCollection will read the value of the key variable as a collection of strings cast type

func (*XDataset) GetTime

func (d *XDataset) GetTime(key string) (time.Time, bool)

GetTime will read the value of the key variable as a time cast type

func (*XDataset) GetTimeCollection

func (d *XDataset) GetTimeCollection(key string) ([]time.Time, bool)

GetTimeCollection will read the value of the key variable as a collection of time cast type

func (*XDataset) GoString

func (d *XDataset) GoString() string

GoString will transform the XDataset into a readable string for humans

func (*XDataset) Set

func (d *XDataset) Set(key string, data interface{})

Set will add a variable key with value data to the XDataset

func (*XDataset) String

func (d *XDataset) String() string

String will transform the XDataset into a readable string for humans

type XDatasetCollection

type XDatasetCollection []XDatasetDef

XDatasetCollection is the basic collection of XDatasetDefs

Example
tmp, _ := time.Parse(time.RFC3339, "2020-01-01T12:00:00.0Z")
ds := &XDataset{
	"v1":  123,
	"v2":  "abc",
	"vt":  tmp,
	"v3":  true,
	"vpi": 3.1415927,
}
fmt.Println(ds)

data := &XDataset{
	"clientname":    "Fred",
	"clientpicture": "face.jpg",
	"hobbies": &XDatasetCollection{
		&XDataset{"name": "Football", "sport": "yes"},
		&XDataset{"name": "Ping-pong", "sport": "yes"},
		&XDataset{"name": "Swimming", "sport": "yes"},
		&XDataset{"name": "Videogames", "sport": "no"},
	},
	"preferredhobby": &XDataset{
		"name":  "Baseball",
		"sport": "yes",
	},
	"metadata": &XDataset{
		"preferred-color": "blue",
		"Salary":          3568.65,
		"hiredate":        tmp,
	},
}

fmt.Println(data)
Output:

xcore.XDataset{v1:123 v2:abc v3:true vpi:3.1415927 vt:2020-01-01 12:00:00 +0000 UTC}
xcore.XDataset{clientname:Fred clientpicture:face.jpg hobbies:XDatasetCollection[0:xcore.XDataset{name:Football sport:yes} 1:xcore.XDataset{name:Ping-pong sport:yes} 2:xcore.XDataset{name:Swimming sport:yes} 3:xcore.XDataset{name:Videogames sport:no} ] metadata:xcore.XDataset{Salary:3568.65 hiredate:2020-01-01 12:00:00 +0000 UTC preferred-color:blue} preferredhobby:xcore.XDataset{name:Baseball sport:yes}}

func (*XDatasetCollection) Clone

Clone will make a full copy of the object into memory

func (*XDatasetCollection) Count

func (d *XDatasetCollection) Count() int

Count will return the quantity of elements into the collection

func (*XDatasetCollection) Get

func (d *XDatasetCollection) Get(index int) (XDatasetDef, bool)

Get will retrieve an element by index from the collection

func (*XDatasetCollection) GetCollection

func (d *XDatasetCollection) GetCollection(key string) (XDatasetCollectionDef, bool)

GetCollection will retrieve a collection from the XDatasetCollection

func (*XDatasetCollection) GetData

func (d *XDatasetCollection) GetData(key string) (interface{}, bool)

GetData will retrieve the first available data identified by key from the collection ordered by index

func (*XDatasetCollection) GetDataBool

func (d *XDatasetCollection) GetDataBool(key string) (bool, bool)

GetDataBool will retrieve the first available data identified by key from the collection ordered by index and return it as a boolean

func (*XDatasetCollection) GetDataFloat

func (d *XDatasetCollection) GetDataFloat(key string) (float64, bool)

GetDataFloat will retrieve the first available data identified by key from the collection ordered by index and return it as a float

func (*XDatasetCollection) GetDataInt

func (d *XDatasetCollection) GetDataInt(key string) (int, bool)

GetDataInt will retrieve the first available data identified by key from the collection ordered by index and return it as an integer

func (*XDatasetCollection) GetDataString

func (d *XDatasetCollection) GetDataString(key string) (string, bool)

GetDataString will retrieve the first available data identified by key from the collection ordered by index and return it as a string

func (*XDatasetCollection) GetDataTime

func (d *XDatasetCollection) GetDataTime(key string) (time.Time, bool)

GetDataTime will retrieve the first available data identified by key from the collection ordered by index and return it as a time

func (*XDatasetCollection) GoString

func (d *XDatasetCollection) GoString() string

GoString will transform the XDataset into a readable string for humans

func (*XDatasetCollection) Pop

Pop will remove the element at the end of the collection

func (*XDatasetCollection) Push

func (d *XDatasetCollection) Push(data XDatasetDef)

Push will adds a XDatasetDef at the end of the collection

func (*XDatasetCollection) Shift

func (d *XDatasetCollection) Shift() XDatasetDef

Shift will remove the element at the beginning of the collection

func (*XDatasetCollection) String

func (d *XDatasetCollection) String() string

String will transform the XDataset into a readable string

func (*XDatasetCollection) Unshift

func (d *XDatasetCollection) Unshift(data XDatasetDef)

Unshift will adds a XDatasetDef at the beginning of the collection

type XDatasetCollectionDef

type XDatasetCollectionDef interface {
	// Stringify will dump the content into a human readable string
	fmt.Stringer   // please implement String()
	fmt.GoStringer // Please implement GoString()

	// Will add a datasetdef to the beginning of the collection
	Unshift(data XDatasetDef)
	// Will remove the first datasetdef of the collection and return it
	Shift() XDatasetDef

	// Will add a datasetdef to the end of the collection
	Push(data XDatasetDef)
	// Will remove the last datasetdef of the collection and return it
	Pop() XDatasetDef

	// Will count the quantity of entries
	Count() int

	// Will get the entry by the index and let it in the collection
	Get(index int) (XDatasetDef, bool)

	// Will search for the data associated to the key by priority (last entry is the most important)
	// returns bool = false if nothing has been found
	GetData(key string) (interface{}, bool)

	// Same as GetData but will convert the result to a string if possible
	// returns bool = false if nothing has been found
	GetDataString(key string) (string, bool)
	// Same as GetData but will convert the result to an int if possible
	// returns bool = false if nothing has been found
	GetDataInt(key string) (int, bool)
	// Same as GetData but will convert the result to a boolean if possible
	// returns second bool = false if nothing has been found
	GetDataBool(key string) (bool, bool)
	// Same as GetData but will convert the result to a float if possible
	// returns bool = false if nothing has been found
	GetDataFloat(key string) (float64, bool)
	// Same as GetData but will convert the result to a Time if possible
	// returns bool = false if nothing has been found
	GetDataTime(key string) (time.Time, bool)
	// Same as GetData but will convert the result to a XDatasetCollectionDef of data if possible
	// returns bool = false if nothing has been found
	GetCollection(key string) (XDatasetCollectionDef, bool)

	// Clone the object
	Clone() XDatasetCollectionDef
}

XDatasetCollectionDef is the definition of a collection of XDatasetDefs

func NewXDatasetCollection added in v2.0.6

func NewXDatasetCollection(data []map[string]interface{}) XDatasetCollectionDef

NewXDatasetCollection is used to build an XDatasetCollection from a standard []map

type XDatasetCollectionTS

type XDatasetCollectionTS struct {
	// contains filtered or unexported fields
}

XDatasetCollectionTS is the basic collection of XDatasetDefs

Example
tmp, _ := time.Parse(time.RFC3339, "2020-01-01T12:00:00.0Z")
ds := &XDataset{
	"v1":  123,
	"v2":  "abc",
	"vt":  tmp,
	"v3":  true,
	"vpi": 3.1415927,
}
fmt.Println(ds)

data := &XDataset{
	"clientname":    "Fred",
	"clientpicture": "face.jpg",
	"hobbies": &XDatasetCollection{
		&XDataset{"name": "Football", "sport": "yes"},
		&XDataset{"name": "Ping-pong", "sport": "yes"},
		&XDataset{"name": "Swimming", "sport": "yes"},
		&XDataset{"name": "Videogames", "sport": "no"},
	},
	"preferredhobby": &XDataset{
		"name":  "Baseball",
		"sport": "yes",
	},
	"metadata": &XDataset{
		"preferred-color": "blue",
		"Salary":          3568.65,
		"hiredate":        tmp,
	},
}

fmt.Println(data)
Output:

xcore.XDataset{v1:123 v2:abc v3:true vpi:3.1415927 vt:2020-01-01 12:00:00 +0000 UTC}
xcore.XDataset{clientname:Fred clientpicture:face.jpg hobbies:XDatasetCollection[0:xcore.XDataset{name:Football sport:yes} 1:xcore.XDataset{name:Ping-pong sport:yes} 2:xcore.XDataset{name:Swimming sport:yes} 3:xcore.XDataset{name:Videogames sport:no} ] metadata:xcore.XDataset{Salary:3568.65 hiredate:2020-01-01 12:00:00 +0000 UTC preferred-color:blue} preferredhobby:xcore.XDataset{name:Baseball sport:yes}}

func (*XDatasetCollectionTS) Clone

Clone will make a full copy of the object into memory

func (*XDatasetCollectionTS) Count

func (dc *XDatasetCollectionTS) Count() int

Count will return the quantity of elements into the collection

func (*XDatasetCollectionTS) Get

func (dc *XDatasetCollectionTS) Get(index int) (XDatasetDef, bool)

Get will retrieve an element by index from the collection

func (*XDatasetCollectionTS) GetCollection

func (dc *XDatasetCollectionTS) GetCollection(key string) (XDatasetCollectionDef, bool)

GetCollection will retrieve a collection from the XDatasetCollectionTS

func (*XDatasetCollectionTS) GetData

func (dc *XDatasetCollectionTS) GetData(key string) (interface{}, bool)

GetData will retrieve the first available data identified by key from the collection ordered by index

func (*XDatasetCollectionTS) GetDataBool

func (dc *XDatasetCollectionTS) GetDataBool(key string) (bool, bool)

GetDataBool will retrieve the first available data identified by key from the collection ordered by index and return it as a boolean

func (*XDatasetCollectionTS) GetDataFloat

func (dc *XDatasetCollectionTS) GetDataFloat(key string) (float64, bool)

GetDataFloat will retrieve the first available data identified by key from the collection ordered by index and return it as a float

func (*XDatasetCollectionTS) GetDataInt

func (dc *XDatasetCollectionTS) GetDataInt(key string) (int, bool)

GetDataInt will retrieve the first available data identified by key from the collection ordered by index and return it as an integer

func (*XDatasetCollectionTS) GetDataString

func (dc *XDatasetCollectionTS) GetDataString(key string) (string, bool)

GetDataString will retrieve the first available data identified by key from the collection ordered by index and return it as a string

func (*XDatasetCollectionTS) GetDataTime

func (dc *XDatasetCollectionTS) GetDataTime(key string) (time.Time, bool)

GetDataTime will retrieve the first available data identified by key from the collection ordered by index and return it as a time

func (*XDatasetCollectionTS) GoString

func (dc *XDatasetCollectionTS) GoString() string

GoString will transform the XDataset into a readable string for humans

func (*XDatasetCollectionTS) Pop

Pop will remove the element at the end of the collection

func (*XDatasetCollectionTS) Push

func (dc *XDatasetCollectionTS) Push(data XDatasetDef)

Push will adds a XDatasetDef at the end of the collection

func (*XDatasetCollectionTS) Shift

func (dc *XDatasetCollectionTS) Shift() XDatasetDef

Shift will remove the element at the beginning of the collection

func (*XDatasetCollectionTS) String

func (dc *XDatasetCollectionTS) String() string

String will transform the XDataset into a readable string

func (*XDatasetCollectionTS) Unshift

func (dc *XDatasetCollectionTS) Unshift(data XDatasetDef)

Unshift will adds a XDatasetDef at the beginning of the collection

type XDatasetDef

type XDatasetDef interface {
	// Stringify will dump the content into a human readable string
	fmt.Stringer   // please implement String()
	fmt.GoStringer // Please implement GoString()

	// Set will associate the data to the key. If it already exists, it will be replaced
	Set(key string, data interface{})

	// Get will return the value associated to the key if it exists, or bool = false
	Get(key string) (interface{}, bool)
	// Same as Get but will return the value associated to the key as a XDatasetDef if it exists, or bool = false
	GetDataset(key string) (XDatasetDef, bool)
	// Same as Get but will return the value associated to the key as a XDatasetCollectionDef if it exists, or bool = false
	GetCollection(key string) (XDatasetCollectionDef, bool)

	// Same as Get but will return the value associated to the key as a string if it exists, or bool = false
	GetString(key string) (string, bool)
	// Same as Get but will return the value associated to the key as a bool if it exists, or bool = false
	GetBool(key string) (bool, bool)
	// Same as Get but will return the value associated to the key as an int if it exists, or bool = false
	GetInt(key string) (int, bool)
	// Same as Get but will return the value associated to the key as a float64 if it exists, or bool = false
	GetFloat(key string) (float64, bool)
	// Same as Get but will return the value associated to the key as a Time if it exists, or bool = false
	GetTime(key string) (time.Time, bool)
	// Same as Get but will return the value associated to the key as a []String if it exists, or bool = false
	GetStringCollection(key string) ([]string, bool)
	// Same as Get but will return the value associated to the key as a []bool if it exists, or bool = false
	GetBoolCollection(key string) ([]bool, bool)
	// Same as Get but will return the value associated to the key as a []int if it exists, or bool = false
	GetIntCollection(key string) ([]int, bool)
	// Same as Get but will return the value associated to the key as a []float64 if it exists, or bool = false
	GetFloatCollection(key string) ([]float64, bool)
	// Same as Get but will return the value associated to the key as a []Time if it exists, or bool = false
	GetTimeCollection(key string) ([]time.Time, bool)

	// Del will delete the data associated to the key and deletes the key entry
	Del(key string)
	// Clone the object
	Clone() XDatasetDef
}

XDatasetDef is a special interface to implement a set of data that can be scanned recursively (by XTemplate for instance)

to search data into it, Stringify it, and set/get/del entries of data
The get* methods must accept a path id>id>id...

func NewXDataset added in v2.0.6

func NewXDataset(data map[string]interface{}) XDatasetDef

NewXDataset is used to build an XDataset from a standard map

type XDatasetTS

type XDatasetTS struct {
	// contains filtered or unexported fields
}

XDatasetTS is a thread safe xdataset (not thread safe) encapsulator XDatasetTS IS thread safe

Example
tmp, _ := time.Parse(time.RFC3339, "2020-01-01T12:00:00.0Z")
ds := &XDataset{
	"v1":  123,
	"v2":  "abc",
	"vt":  tmp,
	"v3":  true,
	"vpi": 3.1415927,
}
dsts := NewXDatasetTS(ds)
fmt.Println(dsts)

data := &XDataset{
	"clientname":    "Fred",
	"clientpicture": "face.jpg",
	"hobbies": &XDatasetCollection{
		&XDataset{"name": "Football", "sport": "yes"},
		&XDataset{"name": "Ping-pong", "sport": "yes"},
		&XDataset{"name": "Swimming", "sport": "yes"},
		&XDataset{"name": "Videogames", "sport": "no"},
	},
	"preferredhobby": &XDataset{
		"name":  "Baseball",
		"sport": "yes",
	},
	"metadata": &XDataset{
		"preferred-color": "blue",
		"Salary":          3568.65,
		"hiredate":        tmp,
	},
}

datats := NewXDatasetTS(data)
fmt.Println(datats)
Output:

xcore.XDataset{v1:123 v2:abc v3:true vpi:3.1415927 vt:2020-01-01 12:00:00 +0000 UTC}
xcore.XDataset{clientname:Fred clientpicture:face.jpg hobbies:XDatasetCollection[0:xcore.XDataset{name:Football sport:yes} 1:xcore.XDataset{name:Ping-pong sport:yes} 2:xcore.XDataset{name:Swimming sport:yes} 3:xcore.XDataset{name:Videogames sport:no} ] metadata:xcore.XDataset{Salary:3568.65 hiredate:2020-01-01 12:00:00 +0000 UTC preferred-color:blue} preferredhobby:xcore.XDataset{name:Baseball sport:yes}}

func NewXDatasetTS

func NewXDatasetTS(maindata XDatasetDef) *XDatasetTS

NewXDatasetTS builds a thread safe encapsulator on a XDataset compatible structure

func (*XDatasetTS) Clone

func (ds *XDatasetTS) Clone() XDatasetDef

Clone will creates a totally new data memory cloned from this object

func (*XDatasetTS) Del

func (ds *XDatasetTS) Del(key string)

Del will deletes the variable

func (*XDatasetTS) Get

func (ds *XDatasetTS) Get(key string) (interface{}, bool)

Get will read the value of the key variable

func (*XDatasetTS) GetBool

func (ds *XDatasetTS) GetBool(key string) (bool, bool)

GetBool will read the value of the key variable as a boolean cast type If the value is int, float, it will be convert with the rule 0: false, != 0: true If the value is anything else and it exists, it will return true if it's not nil

func (*XDatasetTS) GetBoolCollection

func (ds *XDatasetTS) GetBoolCollection(key string) ([]bool, bool)

GetBoolCollection will read the value of the key variable as a collection of bool cast type

func (*XDatasetTS) GetCollection

func (ds *XDatasetTS) GetCollection(key string) (XDatasetCollectionDef, bool)

GetCollection will read the value of the key variable as a XDatasetCollection cast type

func (*XDatasetTS) GetDataset

func (ds *XDatasetTS) GetDataset(key string) (XDatasetDef, bool)

GetDataset will read the value of the key variable as a XDatasetDef cast type

func (*XDatasetTS) GetFloat

func (ds *XDatasetTS) GetFloat(key string) (float64, bool)

GetFloat will read the value of the key variable as a float64 cast type

func (*XDatasetTS) GetFloatCollection

func (ds *XDatasetTS) GetFloatCollection(key string) ([]float64, bool)

GetFloatCollection will read the value of the key variable as a collection of float cast type

func (*XDatasetTS) GetInt

func (ds *XDatasetTS) GetInt(key string) (int, bool)

GetInt will read the value of the key variable as an integer cast type If the value is bool, will return 0/1 If the value is float, will return integer part of value

func (*XDatasetTS) GetIntCollection

func (ds *XDatasetTS) GetIntCollection(key string) ([]int, bool)

GetIntCollection will read the value of the key variable as a collection of int cast type

func (*XDatasetTS) GetString

func (ds *XDatasetTS) GetString(key string) (string, bool)

GetString will read the value of the key variable as a string cast type

func (*XDatasetTS) GetStringCollection

func (ds *XDatasetTS) GetStringCollection(key string) ([]string, bool)

GetStringCollection will read the value of the key variable as a collection of strings cast type

func (*XDatasetTS) GetTime

func (ds *XDatasetTS) GetTime(key string) (time.Time, bool)

GetTime will read the value of the key variable as a time cast type

func (*XDatasetTS) GetTimeCollection

func (ds *XDatasetTS) GetTimeCollection(key string) ([]time.Time, bool)

GetTimeCollection will read the value of the key variable as a collection of time cast type

func (*XDatasetTS) GoString

func (ds *XDatasetTS) GoString() string

GoString will transform the XDataset into a readable string for humans

func (*XDatasetTS) Set

func (ds *XDatasetTS) Set(key string, data interface{})

Set will add a variable key with value data to the XDatasetTS

func (*XDatasetTS) String

func (ds *XDatasetTS) String() string

String will transform the XDataset into a readable string for humans

type XLanguage

type XLanguage struct {
	Name     string
	Language language.Tag
	// contains filtered or unexported fields
}

XLanguage is the oficial structure for the user

func NewXLanguage

func NewXLanguage(name string, lang language.Tag) *XLanguage

NewXLanguage will create an empty Language structure with a name and a language

Example
langES := NewXLanguage("messages", language.Spanish)
langEN := NewXLanguage("messages", language.English)
langFR := NewXLanguage("messages", language.French)

// You can load this from your system files for instance and keep your translation tables apart
langES.Set("panicerror", "Error crítico del sistema")
langEN.Set("panicerror", "System panic error")
langFR.Set("panicerror", "Erreur grave dans le système")

// pick a random general system language (for instance the client's OS language)
lang := langFR

// launch a panic errors
fmt.Println("Launch a panic error message in the selected language:", lang.Get("panicerror"))
Output:

Launch a panic error message in the selected language: Erreur grave dans le système

func NewXLanguageFromFile

func NewXLanguageFromFile(file string) (*XLanguage, error)

NewXLanguageFromFile will create an XLanguage structure with the data into the text file

Returns nil if there is an error

func NewXLanguageFromString

func NewXLanguageFromString(data string) (*XLanguage, error)

NewXLanguageFromString will create an XLanguage structure with the data into the string

Returns nil if there is an error

func NewXLanguageFromXMLFile

func NewXLanguageFromXMLFile(file string) (*XLanguage, error)

NewXLanguageFromXMLFile will create an XLanguage structure with the data into the XML file

Returns nil if there is an error
Example
langES, _ := NewXLanguageFromXMLFile("./testunit/a.es.language")
langEN, _ := NewXLanguageFromXMLFile("./testunit/a.en.language")
langFR, _ := NewXLanguageFromXMLFile("./testunit/a.fr.language")

// pick a random general system language (for instance the client's OS language)
lang := langES

// Say hello main language
fmt.Println(lang.Get("entry1") + " " + lang.Get("entry2"))
// Say hello in other languages
fmt.Println(langEN.Get("entry1") + " " + langEN.Get("entry2"))
fmt.Println(langFR.Get("entry1") + " " + langFR.Get("entry2"))
Output:

func NewXLanguageFromXMLString

func NewXLanguageFromXMLString(xml string) (*XLanguage, error)

NewXLanguageFromXMLString will create an XLanguage structure with the data into the XML String

Returns nil if there is an error

func (*XLanguage) Del

func (l *XLanguage) Del(entry string)

Del will remove an entry id-value from the language table

func (*XLanguage) Get

func (l *XLanguage) Get(entry string) string

Get will read an entry id-value from the language table

func (*XLanguage) GetEntries added in v2.0.4

func (l *XLanguage) GetEntries() map[string]string

GetEntries will return a COPY of the key-values pairs of the language.

func (*XLanguage) GetLanguage

func (l *XLanguage) GetLanguage() language.Tag

GetLanguage will return the language of the language table

func (*XLanguage) GetName

func (l *XLanguage) GetName() string

GetName will return the name of the language table

func (*XLanguage) GoString

func (l *XLanguage) GoString() string

GoString will transform the XDataset into a readable string for humans

func (*XLanguage) LoadFile

func (l *XLanguage) LoadFile(file string) error

LoadFile will Load a language from a file and replace the content of the XLanguage structure with the new data

Returns nil if there is an error

func (*XLanguage) LoadString

func (l *XLanguage) LoadString(data string) error

LoadString will Load a language from a string and replace the content of the XLanguage structure with the new data

Returns nil if there is an error

func (*XLanguage) LoadXMLFile

func (l *XLanguage) LoadXMLFile(file string) error

LoadXMLFile will Load a language from an XML file and replace the content of the XLanguage structure with the new data

Returns nil if there is an error

func (*XLanguage) LoadXMLString

func (l *XLanguage) LoadXMLString(data string) error

LoadXMLString will Load a language from an XML file and replace the content of the XLanguage structure with the new data

Returns nil if there is an error

func (*XLanguage) Set

func (l *XLanguage) Set(entry string, value string)

Set will add an entry id-value into the language table

func (*XLanguage) SetLanguage

func (l *XLanguage) SetLanguage(lang language.Tag)

SetLanguage will set the language ISO code (2 letters) of the language table

func (*XLanguage) SetName

func (l *XLanguage) SetName(name string)

SetName will set the name of the language table

func (*XLanguage) String

func (l *XLanguage) String() string

String will transform the XDataset into a readable string for humans

type XTemplate

type XTemplate struct {
	Name         string
	Root         *XTemplateData
	SubTemplates map[string]*XTemplate
}

XTemplate is the plain template structure

func NewXTemplate

func NewXTemplate() *XTemplate

NewXTemplate will create a new empty template

func NewXTemplateFromFile

func NewXTemplateFromFile(file string) (*XTemplate, error)

NewXTemplateFromFile will create a new template from a file containing the template code

func NewXTemplateFromString

func NewXTemplateFromString(data string) (*XTemplate, error)

NewXTemplateFromString will create a new template from a string containing the template code

Example
tmpl, _ := NewXTemplateFromString(`
%-- This is a comment. It will not appear in the final code. --%
Let's put your name here: {{clientname}}<br />
And lets put your hobbies here:<br />
%-- note the 1rst id is the entry into the data to inject and the second one is the name of the sub-template to use --%
@@hobbies:hobby@@
%-- And you need the template for each hobby:--%
[[hobby]]
I love {{name}}<br />
[[]]
`)
// The creation of the data is obviously tedious here, in real life it should come from a JSON, a Database, etc
data := XDataset{
	"clientname": "Fred",
	"hobbies": &XDatasetCollection{
		&XDataset{"name": "Football"},
		&XDataset{"name": "Ping-pong"},
		&XDataset{"name": "Swimming"},
		&XDataset{"name": "Videogames"},
	},
}

fmt.Println(tmpl.Execute(&data))
Output:

Let's put your name here: Fred<br />
And lets put your hobbies here:<br />
I love Football<br />
I love Ping-pong<br />
I love Swimming<br />
I love Videogames<br />

func (*XTemplate) AddTemplate

func (t *XTemplate) AddTemplate(name string, tmpl *XTemplate)

AddTemplate will add a sub template to this template

func (*XTemplate) Clone added in v2.0.8

func (t *XTemplate) Clone() *XTemplate

Clone will make a full new copy of the template into a new memory space

func (*XTemplate) Execute

func (t *XTemplate) Execute(data XDatasetDef) string

Execute will inject the Data into the template and creates the final string

func (*XTemplate) GetTemplate

func (t *XTemplate) GetTemplate(name string) *XTemplate

GetTemplate gets a sub template existing into this template

func (*XTemplate) GoString

func (t *XTemplate) GoString() string

GoString will transform the XDataset into a readable string for humans with values indexes

func (*XTemplate) LoadFile

func (t *XTemplate) LoadFile(file string) error

LoadFile will load a file into the template

func (*XTemplate) LoadString

func (t *XTemplate) LoadString(data string) error

LoadString will load a string into the template

func (*XTemplate) String

func (t *XTemplate) String() string

String will transform the XDataset into a readable string for humans

type XTemplateData

type XTemplateData []XTemplateParam

XTemplateData is an Array of all the parameters into the template

type XTemplateParam

type XTemplateParam struct {
	ParamType int
	Data      string
}

XTemplateParam is a parameter definition into the template

func (*XTemplateParam) Clone added in v2.0.8

func (tp *XTemplateParam) Clone() *XTemplateParam

Clone will make a copy of the param

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL