Comparing version 0.0.2 to 0.1.0
250
index.js
/** | ||
* babelute | ||
* Chained mediators pattern for (much) better software design. A whole new world. | ||
* Babelute. | ||
* Method chaining applications to Templating and Domain Language (multi)Modeling. | ||
* | ||
* Domain Language (Multi)Modeling solves many software design problems. | ||
* From developpement process (how to start, what to design, how to design, how to iterate, ...) | ||
* to how to understand, design and articulate business related problems and/or pure code logics. | ||
* | ||
* It provides natural ways of thinking models and code that are really close to how human mind | ||
* works. Much much more close than OO (including AOP) is. | ||
* | ||
* Babelute gives elegant and really simple ways to define/handle/use/transform chainable methods | ||
* in pure javascript or through it's own simple DSL | ||
* (a minimalist optimal string representation of call chains for writing/serialising babelute | ||
* sentences and/or lexics). | ||
* | ||
* It relays entierly on Method Chaining pseudo design pattern. | ||
* In consequence, it's made with really few code, and is really light (less than 2ko gzip/min without own | ||
* DSL parser - which is also really light (+- 1ko gzip/min)) | ||
* | ||
* Babelute's parsing and output are both really fast. | ||
* The pattern and method are already heavily used in other fast libs, that solve elegantly really | ||
* disconnected problems, | ||
* that have shown that was a really good approach to have both | ||
* expressivness and performance (jquery (zepto, sprint), elenpi, aright, yamvish, deepjs chains, ...). | ||
* | ||
* @author Gilles Coomans | ||
* @licence MIT | ||
* @copyright 2016 Gilles Coomans | ||
*/ | ||
// core class and statics | ||
var Babelute = require('./lib/babelute'); | ||
/* | ||
************************************* All code below was the first shoot before full understanding.... it's just there for reflexion base. | ||
// serializer to Babelute DSL | ||
require('./lib/stringify'); | ||
// Babelute DSL parser | ||
Babelute.parser = require('./lib/parser'); | ||
Dans les chaines : | ||
// Babelute Document | ||
require('./lib/document'); | ||
interprétation immédiate | ||
interprétation différée | ||
interprétation différée avec choix du dictionaire sémantique | ||
avantages écriture sérialisé : | ||
- pas obligatoire d'avoir l'api défini | ||
--> au parsing on peut direct enqueuer la représentation objet | ||
*/ | ||
/* | ||
dico.engine.base = { | ||
// mettre ici ce qui est commun. lors run : d'abord regarder dans engin courant puis regarder dans base | ||
log:function(){ | ||
} | ||
} | ||
Babelute.prototype.output = function(target, ?engines...){ | ||
var handler = this._queue[0], | ||
index = 0, | ||
f; | ||
while (handler) { | ||
f = typeof handler.name === 'string' ? engine[handler.name] : handler.name; | ||
if (!f) { | ||
handler = this._queue[++index]; | ||
continue; | ||
} | ||
if (f.__chaim__) | ||
f.output(target, engines); | ||
else | ||
f.apply(target, handler.args); | ||
handler = this._queue[++index]; | ||
} | ||
return target; | ||
} | ||
//__________________________________________________ | ||
//__________________________________________________ | ||
var quantityMixHandler = function(name){ | ||
return function(quantity){ | ||
return this.mix(name, quantity); | ||
} | ||
} | ||
dico | ||
.toApi('cuisine', 'beurre', quantityMixHandler('beurre')) | ||
.toApi('cuisine', 'sucre', quantityMixHandler('sucre')) | ||
.toApi('cuisine', 'chocolat', quantityMixHandler('chocolat')) | ||
.toApi('cuisine', 'oeuf', quantityMixHandler('oeuf')) | ||
.toApi('cuisine', 'oeufBattu', quantityMixHandler('oeufBattu')) | ||
.toApi('cuisine', 'cuire', function(temp, duration){ | ||
return this._enqueue('cuire', [temp, duration]); | ||
}) | ||
.toApi('cuisine', 'empiler', function(path){ | ||
var parts = [].slice.call(arguments, 1); | ||
return this._enqueue('empiler', [path, parts]); | ||
}) | ||
.toApi('cuisine', 'mix', function(name){ | ||
name = typeof name === 'string' ? name : false; | ||
var parts = [].slice.call(arguments, name ? 1 : 0); | ||
return this._enqueue('mix', [name, parts]); | ||
}) | ||
//__________________________________________________ | ||
dico.engine.object = { | ||
mix:function(name, parts){ | ||
var obj = this[name] = { | ||
type:'mix', | ||
name:name | ||
}; | ||
if(parts) | ||
if(obj.forEach) | ||
obj.parts = parts.map(function(p){ return p.output({}, 'object'); }); | ||
else | ||
obj.quantity = parts || 0; | ||
}, | ||
cuire:function(name, temp, duration){ | ||
this[name].cooked = { | ||
temparature:temp, | ||
duration:duration | ||
} | ||
}, | ||
empiler:function(path, parts){ | ||
if(!this[path] || !this[path].type === 'stack') | ||
{ | ||
var stack = { | ||
type:'stack', | ||
name:path | ||
}; | ||
if(this[path]) | ||
stack.layers = [this[path]]; | ||
else | ||
stack.layers= []; | ||
this[path] = stack; | ||
} | ||
stack.layers = stack.layers.concat(parts.map(function(p){ return p.output({}, 'object'); })); | ||
}, | ||
prendre:function(path, quantity){ | ||
} | ||
}; | ||
// exemple (rough) | ||
var c = chaim.initier('recette-cuisine'), o = chaim.initier('object'); | ||
var recette = c() | ||
.beurre(500) | ||
.mix('pate', c().prendre('beurre', 250), c().sucre(250), c().oeuf(3), c().farine(250)) | ||
.cuire('pate', 180, 25); | ||
var gateauDB = function(recette){ | ||
return this | ||
.meta('author', db().ownerID()) | ||
.meta('creationDate', db().now()) | ||
.use(recette) | ||
}; | ||
var output = quatreQuart.output({}, 'object'); | ||
Babelute.prototype.gateauChocolat = function() { | ||
return this | ||
.mix('pâte', c().beurre(250), c().farine(250), c().oeufBattu(3)) | ||
.mix('coulis', c().menthe(3), c().framboises(200)) | ||
.attendre('15min') | ||
.mix('gateau', c().prendre('pâte', 2 / 3), c().sucre(250)) | ||
.empiler('gateau', c().prendre('coulis'), c().prendre('pâte', 1 / 3), c().napage('chocolat')) | ||
.cuire('gateau', 180, '25min'); | ||
} | ||
*/ | ||
var Babelute = function() { | ||
this.__chaim__ = true; | ||
this._queue = []; | ||
} | ||
Babelute.engine = {} | ||
Babelute.parse = function(initier, string) {} | ||
// Babelute main initier | ||
Babelute.ch = function(target) { | ||
return new Babelute(target); | ||
} | ||
Babelute.prototype = { | ||
_enqueue: function(name, args) { | ||
this._queue.push({ name: name, args: args }); | ||
return this; | ||
}, | ||
use: function(chaim) { | ||
if (!chaim) | ||
return this; | ||
var args = [].slice.call(arguments, 1); | ||
var method = chaim; | ||
if (typeof chaim === 'string') { | ||
method = this[chaim]; | ||
if (!method) | ||
throw new Error('Babelute : method not found : ' + chaim); | ||
} | ||
if (method.__chaim__) | ||
this._queue = this._queue.concat(method._queue); | ||
else | ||
method.apply(this, args); | ||
return this; | ||
}, | ||
toString: function() { | ||
return this._queue.map(function(item) { | ||
return item.name + '(' + (item.args ? item.args.join(',') : '') + ')'; | ||
}).join('.'); | ||
} | ||
}; | ||
Babelute.engine.toObject = { | ||
object: function(name, child) { | ||
this[name] = {}; | ||
if (child) | ||
child.toObject(this[name]); | ||
}, | ||
array: function(name) { | ||
this[name] = []; | ||
} | ||
} | ||
Babelute.prototype.toObject = function(target) { | ||
var handler = this._queue[0], | ||
index = 0, | ||
f; | ||
while (handler) { | ||
f = typeof handler.name === 'string' ? engine[handler.name] : handler.name; | ||
if (!f) { | ||
handler = this._queue[++index]; | ||
continue; | ||
} | ||
if (f.__chaim__ && f.toObject) | ||
f.toObject(target); | ||
else | ||
f.apply(target, handler.args); | ||
handler = this._queue[++index]; | ||
} | ||
return target; | ||
}; | ||
module.exports = Babelute; |
{ | ||
"name": "babelute", | ||
"version": "0.0.2", | ||
"description": "Chained mediators pattern for (much) better software design. A whole new world.", | ||
"version": "0.1.0", | ||
"description": "Internal Domain Specific Language javascript framework", | ||
"main": "index.js", | ||
@@ -14,12 +14,10 @@ "scripts": { | ||
"keywords": [ | ||
"mediator", | ||
"chained-mediator", | ||
"chained-syntax", | ||
"ontology", | ||
"domain-language", | ||
"software-design", | ||
"model", | ||
"internal-DSL", | ||
"domain-specific-language", | ||
"method-chaining", | ||
"domain-specific-modeling", | ||
"model-driven", | ||
"modeling", | ||
"document", | ||
"semantic", | ||
"concept" | ||
"semantic" | ||
], | ||
@@ -31,3 +29,6 @@ "author": "Gilles Coomans", | ||
}, | ||
"homepage": "https://github.com/nomocas/babelute#readme" | ||
"homepage": "https://github.com/nomocas/babelute#readme", | ||
"dependencies": { | ||
"elenpi": "^0.3.0" | ||
} | ||
} |
170
README.md
@@ -1,11 +0,171 @@ | ||
# babelute | ||
# Babelute | ||
Chained mediators pattern for (much) better software design. A whole new world. | ||
Internal Domain Specific Language javascript framework based on Method Chaining | ||
and dedicated to Domain Specific (multi)Modeling (DSM). | ||
From simple chained api definition to really smart domain-language based developpement. | ||
or How to design and code as you think... | ||
And boost your productivity as never. | ||
So simple pattern, so much to tell... | ||
Really small, simple, incredibly powerful and super fast. | ||
Work in progress. | ||
(documentation in progress) | ||
## Aim | ||
The aim of Babelute is to provide : | ||
- a simple "(meta) meta language" (a grammar - based on Method Chaining) and tools for Domain Specific Language definition | ||
- tools for managing dictionaries (called lexics) of those DSL (namespaces, translations between languages, real semantics depending to specific context, etc) | ||
- helpers for writing structured "sentences" (called "babelutes") in those DSL (always based on Method Chaining) | ||
- ways to interpret/run sentences depending on a particular context (sentence-to-sentence or sentence-to-specific-actions) | ||
- ways to execute Babelute sentences immediatly (and only once - classical simple Method Chaining) | ||
- ways to execute Babelute sentences on demand (sentence's elements are kept in local array), and therefor they could be seen as multi-purpose template. (where they release all their potential) | ||
- tools to make Babelute sentences handelable and editable | ||
- a lightweight optimal serialised form of Babelute sentences and the associated parser/stringifier | ||
## Fluent Interfaces as DSL | ||
Expressing DSL with Fluent Interface is something that is well known today. | ||
The term "Fluent Interface" comes from Martin Fowler's [2005 article](http://martinfowler.com/bliki/FluentInterface.html) where he associated clearly Internal DSL and fluency. | ||
Fluent interfaces does not mean necessary Method Chaining. It's just one way to achieve it. | ||
And Method Chaining doesn't mean necessary Internal DSL. | ||
Fluent Internal DSL are much more about choosing right words with right semantics for optimaly expressing particular problems through readable and meaningful sentences. Not simply chaining calls. | ||
Examples of Domain Specific Language expressed with Method Chaining : | ||
SQL in JAVA : http://www.jooq.org/ | ||
```java | ||
create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count()) | ||
.from(AUTHOR) | ||
.join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID)) | ||
.where(BOOK.LANGUAGE.eq("DE")) | ||
.and(BOOK.PUBLISHED.gt(date("2008-01-01"))) | ||
.groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) | ||
.having(count().gt(5)) | ||
.orderBy(AUTHOR.LAST_NAME.asc().nullsFirst()) | ||
.limit(2) | ||
.offset(1) | ||
``` | ||
RTF Doc construction in JAVA : https://github.com/ullenboom/jrtf/ | ||
```java | ||
rtf().section( | ||
p( "first paragraph" ), | ||
p( tab(), | ||
" second par ", | ||
bold( "with something in bold" ), | ||
text( " and " ), | ||
italic( underline( "italic underline" ) ) | ||
) | ||
).out( out ); | ||
``` | ||
Further reading : | ||
- http://leecampbell.blogspot.be/2008/11/method-chaining-to-create-your-dsl.html | ||
- https://sanaulla.info/2013/05/30/creating-internal-dsls-in-java-java-8-adopting-martin-fowlers-approach | ||
- https://msdn.microsoft.com/en-us/magazine/ee291514.aspx | ||
- https://books.google.be/books?id=EhOXBQAAQBAJ&pg=PA403&lpg=PA403&dq=method+chaining+DSL&source=bl&ots=vMd25Y86E1&sig=d7SbHZoiLA8X1g4nsoo5Ph5kHTA&hl=fr&sa=X&ved=0ahUKEwiR_-32usvOAhUSahoKHTk2C9Y4ChDoAQgwMAM#v=onepage&q=method%20chaining%20DSL&f=false | ||
## DSM | ||
Model Driven approach. (Model First, automation, standard) | ||
## Translation Chain : From High Level to Code Level | ||
Community of Abstract and Concreet DSLs. | ||
## DSL as "Template" | ||
Method Chaining along with Command Design Pattern to build Facade. | ||
RSIC vs CISC | ||
Auto-parsing | ||
## Template as Document | ||
From persistence, to meta-programing, to shadow document. | ||
### Order means everything | ||
### Lightweight optimal serialised form | ||
#### Introduce elenpi | ||
#### Persitence | ||
### Document edition and meta-programing | ||
#### Chained DSL Facade as Document Pilot | ||
#### GUI for all | ||
### Document instanciation, data-binding and Shadow Document | ||
## Todo soon | ||
- debug and report | ||
- open problem : meta-model and model evolution and versioning | ||
(maybe introduce Consumer Contract Driven logics) | ||
## Further | ||
- coordination problem and method | ||
- Link with ontologies | ||
- Inference Engine | ||
- DSL repository | ||
- Web exposition | ||
- DSL-DB | ||
# Babelute examples | ||
```javascript | ||
var b = require('babelute').b; | ||
// define language "foo" with 3 words | ||
Babelute.toLexic('family', ['myMethod', 'mySecondMethod', 'myThirdMethod']); | ||
// you could directly write sentences with it | ||
var myBabelute = b('foo') | ||
.myMethod() | ||
.mySecondMethod('John', true) | ||
.myThirdMethod( | ||
b('foo') | ||
.mySecondMethod('Biloud', false); | ||
); | ||
//... | ||
// then provides semantics for those words | ||
Babelute.toActions('foo:bar', { | ||
myMethod:function(env, subject, args){ | ||
subject.first = true; | ||
}, | ||
mySecondMethod:function(env, subject, args){ | ||
subject.second = 'Hello '+ args[0] + ' ! ' + (args[1] ? 'Greetings.' : ''); | ||
}, | ||
myThirdMethod:function(env, subject, args){ | ||
subject.third = args[0]._output(env, {}); // sub-babelute usage | ||
} | ||
}); | ||
//... | ||
// then output sentence with your semantics | ||
var output = myBabelute._output('foo:bar', {}); | ||
// => {first:true, second:'Hello John ! Greetings.', third:{ second:'Hello Biloud !' } } | ||
``` | ||
More coming really soon. | ||
## Licence | ||
@@ -12,0 +172,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
61087
15
1277
182
1
2
+ Addedelenpi@^0.3.0
+ Addedelenpi@0.3.2(transitive)