From 1d523e65432dd7f8dde945c37f5b4e23d2c3370b Mon Sep 17 00:00:00 2001 From: Mark Bjerke Date: Tue, 15 Dec 2015 11:30:50 -0800 Subject: [PATCH 1/5] Implement no-loop rule attribute --- .gitattributes | 17 +++++++++ .gitignore | 2 + lib/agenda.js | 10 ++++- lib/parser/nools/tokens.js | 18 +++++++++ lib/rule.js | 1 + readme.md | 28 ++++++++++++++ test/flow/noLoop.test.js | 76 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 test/flow/noLoop.test.js diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bdb0cab --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index c9bb555..44c4a1a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ node_modules nools.iml .idea atlassian-ide-plugin.xml +*.njsproj +*.dat diff --git a/lib/agenda.js b/lib/agenda.js index 99fd57e..cd585bc 100644 --- a/lib/agenda.js +++ b/lib/agenda.js @@ -84,7 +84,7 @@ module.exports = declare(EventEmitter, { register: function (node) { var agendaGroup = node.rule.agendaGroup; - this.rules[node.name] = {tree: new AVLTree({compare: this.comparator}), factTable: new FactHash()}; + this.rules[node.name] = { tree: new AVLTree({ compare: this.comparator }), factTable: new FactHash(), noLoop: {} }; if (agendaGroup) { this.addAgendaGroup(agendaGroup); } @@ -162,6 +162,14 @@ module.exports = declare(EventEmitter, { insert: function (node, insert) { var rule = this.rules[node.name], nodeRule = node.rule, agendaGroup = nodeRule.agendaGroup; + if (nodeRule.noLoop) { + if (rule.noLoop[insert.hashCode]) { + return; + } + else { + rule.noLoop[insert.hashCode] = true; + } + } rule.tree.insert(insert); this.getAgendaGroup(agendaGroup).insert(insert); if (agendaGroup) { diff --git a/lib/parser/nools/tokens.js b/lib/parser/nools/tokens.js index 3ac7080..23391e2 100644 --- a/lib/parser/nools/tokens.js +++ b/lib/parser/nools/tokens.js @@ -94,6 +94,20 @@ var ruleTokens = { }; })(), + noLoop: (function () { + var noLoopRegexp = /^(noLoop|no-loop)\s*:\s*(-?true|false)\s*[,;]?/; + return function (src, context) { + if (noLoopRegexp.test(src)) { + var parts = src.match(noLoopRegexp); + // + context.options.noLoop = Boolean(parts[2]) + return src.replace(parts[0], ""); + } else { + throw new Error("invalid format"); + } + }; + })(), + "agenda-group": function () { return this.agendaGroup.apply(this, arguments); }, @@ -102,6 +116,10 @@ var ruleTokens = { return this.autoFocus.apply(this, arguments); }, + "no-loop": function () { + return this.noLoop.apply(this, arguments); + }, + priority: function () { return this.salience.apply(this, arguments); }, diff --git a/lib/rule.js b/lib/rule.js index 75a73d8..75ee26e 100644 --- a/lib/rule.js +++ b/lib/rule.js @@ -227,6 +227,7 @@ var Rule = declare({ this.name = name; this.pattern = pattern; this.cb = cb; + this.noLoop = options.noLoop; if (options.agendaGroup) { this.agendaGroup = options.agendaGroup; this.autoFocus = extd.isBoolean(options.autoFocus) ? options.autoFocus : false; diff --git a/readme.md b/readme.md index e5bc0d9..56d58f0 100644 --- a/readme.md +++ b/readme.md @@ -37,6 +37,7 @@ Or [download the source](https://raw.github.com/C2FO/nools/master/nools.js) ([mi * [Structure](#rule-structure) * [Salience](#rule-salience) * [Scope](#rule-scope) + * [no-loop](#rule-no-loop) * [Constraints](#constraints) * [Custom](#custom-contraints) * [Not](#not-constraint) @@ -1003,6 +1004,33 @@ flow1 }); ``` + +### No-Loop + +When a rule's action modifies a fact it may cause the rule to activate again, causing an infinite loop. Setting no-loop to true will skip the creation of another Activation for the rule with the current set of facts. + +```javascript +this.rule("Hello", {noLoop: true}, [Message, "m", "m.text like /hello/"], function (facts) { + var m = facts.m; + m.text = 'hello world'; + this.modify(m) +}); + +``` +Or using the DSL + +```javascript +rule Hello { + no-loop: true; + when { + m: Message m.name like /hello/; + } + then { modify(m, function() { + m.text = 'hello world' + }); +} +``` + diff --git a/test/flow/noLoop.test.js b/test/flow/noLoop.test.js new file mode 100644 index 0000000..93dcdc4 --- /dev/null +++ b/test/flow/noLoop.test.js @@ -0,0 +1,76 @@ +"use strict"; +var it = require("it"), + assert = require("assert"), + nools = require("../../"); + +it.describe("no-loop", function (it) { + /*jshint indent*/ + function Message(name) { + this.name = name; + } + var cnt = 0; + + var flow1 = nools.flow("noLoop1", function () { + + this.rule("Hello2", { noLoop: true }, [Message, "m", "m.name =~ /Hello/"], function (facts) { + var m = facts.m; + m.name = 'Hello World'; + this.modify(m); + }); + }), + + flow2 = nools.flow("noLoop2", function () { + + this.rule("Hello1", [Message, "m", "m.name =~ /Hello/"], function (facts) { + var m = facts.m; + if (cnt++ < 2) { + m.name = 'Hello World'; + this.modify(m); + } + }); + }); + + var noolsSource = ` rule 'Hello3' { + no-loop: true; + when { + m: Message m.name =~/Hello/; + } + then { + modify(m, function () { + this.name = 'Hello World'; }); + } + }`; + + var flow3 = nools.compile(noolsSource, { + name: 'testDsl' + ,define: { + Message: Message + } + }); + + it.should("not loop with option on and loop otherwise", function () { + var fired1 = [], fired2 = [], fired3 = []; + var session1 = flow1.getSession(new Message("Hello")).on("fire", function (name) { + fired1.push(name); + }), + session2 = flow2.getSession(new Message("Hello")).on("fire", function (name) { + fired2.push(name); + }), + session3 = flow3.getSession(new Message("Hello")).on("fire", function (name) { + fired3.push(name); + }); + return session1.match() + .then(function () { + return session2.match().then(function () { + return session3.match().then(function () { + }) + }) + }) + .then(function () { + assert.deepEqual(fired1, ["Hello2"]); + assert.deepEqual(fired2, ["Hello1", "Hello1", "Hello1"]); + assert.deepEqual(fired3, ["Hello3"]); + }); + }); + +}); From d93efacb287d97911c1ea757a38b434d4aa1c079 Mon Sep 17 00:00:00 2001 From: Mark Bjerke Date: Tue, 15 Dec 2015 13:22:27 -0800 Subject: [PATCH 2/5] Fixes issue with using grave marks for dsl strings in test file: noloop.test.js --- test/flow/noLoop.test.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/test/flow/noLoop.test.js b/test/flow/noLoop.test.js index 93dcdc4..bcebe58 100644 --- a/test/flow/noLoop.test.js +++ b/test/flow/noLoop.test.js @@ -8,7 +8,7 @@ it.describe("no-loop", function (it) { function Message(name) { this.name = name; } - var cnt = 0; + var cnt = 0; var flow1 = nools.flow("noLoop1", function () { @@ -30,16 +30,7 @@ it.describe("no-loop", function (it) { }); }); - var noolsSource = ` rule 'Hello3' { - no-loop: true; - when { - m: Message m.name =~/Hello/; - } - then { - modify(m, function () { - this.name = 'Hello World'; }); - } - }`; + var noolsSource = "rule 'Hello3' { no-loop: true; when {m: Message m.name =~/Hello/;}then {modify(m, function () { this.name = 'Hello World'; });}}"; var flow3 = nools.compile(noolsSource, { name: 'testDsl' From 1259c3d5c4779e9e425dfb9db219c700bf12e92f Mon Sep 17 00:00:00 2001 From: Mark Bjerke Date: Thu, 17 Dec 2015 14:49:14 -0800 Subject: [PATCH 3/5] Implements extends functionality in the dsl These files address #162 , the extends keyword, which allows you to reference other types in either external or other defines as a base type. --- lib/compile/common.js | 16 ++++++++++--- lib/compile/transpile.js | 40 +++++++++++++++++++++++++-------- lib/parser/nools/tokens.js | 7 +++++- readme.md | 14 +++++++++++- test/flow.dsl.test.js | 24 ++++++++++++++++++++ test/rules/extends.nools | 46 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 14 deletions(-) create mode 100644 test/rules/extends.nools diff --git a/lib/compile/common.js b/lib/compile/common.js index 16f519f..15861da 100644 --- a/lib/compile/common.js +++ b/lib/compile/common.js @@ -29,7 +29,10 @@ var createFunction = function (body, defined, scope, scopeNames, definedNames) { var createDefined = (function () { - var _createDefined = function (action, defined, scope) { + var _createDefined = function (options, defined, scope) { + var action = options.properties + ,proto, base; + // if (isString(action)) { var declares = []; extd(defined).keys().forEach(function (i) { @@ -57,7 +60,14 @@ var createDefined = (function () { } } }; - var proto = ret.prototype; + if (options.extend) { + base = defined[options.extend]; + proto = Object.create(base.prototype); + ret.prototype = proto; + } + else { + proto = ret.prototype; + } for (var i in action) { proto[i] = action[i]; } @@ -66,7 +76,7 @@ var createDefined = (function () { }; return function (options, defined, scope) { - return _createDefined(options.properties, defined, scope); + return _createDefined(options, defined, scope); }; })(); diff --git a/lib/compile/transpile.js b/lib/compile/transpile.js index f0ae8be..ad9e6f5 100644 --- a/lib/compile/transpile.js +++ b/lib/compile/transpile.js @@ -7,26 +7,48 @@ var extd = require("../extended"), constraintMatcher = require("../constraintMatcher"), parser = require("../parser"); -function definedToJs(options) { +function definedToJs(options, extend) { /*jshint evil:true*/ options = isString(options) ? new Function("return " + options + ";")() : options; - var ret = ["(function(){"], value; - + var ret = ["(function(flow){"], value; + if (options.hasOwnProperty("constructor") && "function" === typeof options.constructor) { ret.push("var Defined = " + options.constructor.toString() + ";"); } else { ret.push("var Defined = function(opts){ for(var i in opts){if(opts.hasOwnProperty(i)){this[i] = opts[i];}}};"); } - ret.push("var proto = Defined.prototype;"); + if (extend) { + ret.push("var proto = Object.create(flow.getDefined('" + extend + "').prototype); proto.constructor = Defined; Defined.prototype = proto;"); + } + else { + ret.push("var proto = Defined.prototype;"); + } + for (var key in options) { - if (options.hasOwnProperty(key)) { + var str; + if (options.hasOwnProperty(key) && key !== 'constructor') { value = options[key]; - ret.push("proto." + key + " = " + (extd.isFunction(value) ? value.toString() : extd.format("%j", value)) + ";"); + str = ("proto." + key + " = "); + if (extd.isFunction(value)) { + str += value.toString(); + } + else { + if (value instanceof Array) { + str += JSON.stringify(value); + } + else { + str += extd.format("%j", value); + } + str += ";" + } + ret.push(str); } } ret.push("return Defined;"); - ret.push("}())"); - return ret.join(""); + ret.push("}(this))"); + var sJoin = ret.join(""); + debugger; + return sJoin; } @@ -148,7 +170,7 @@ exports.transpile = function (flowObj, options) { ret.push(extd(flowObj.define || []).map(function (defined) { var name = defined.name; defined[name] = {}; - return ["var", name, "= defined." + name, "= this.addDefined('" + name + "',", definedToJs(defined.properties) + ");"].join(" "); + return ["var", name, "= defined." + name, "= this.addDefined('" + name + "',", definedToJs(defined.properties, defined.extend) + ");"].join(" "); }).value().join("\n")); ret.push(extd(flowObj.scope || []).map(function (s) { var name = s.name; diff --git a/lib/parser/nools/tokens.js b/lib/parser/nools/tokens.js index 23391e2..faf4721 100644 --- a/lib/parser/nools/tokens.js +++ b/lib/parser/nools/tokens.js @@ -240,12 +240,17 @@ var topLevelTokens = { var name = src.match(/^([a-zA-Z_$][0-9a-zA-Z_$]*)/); if (name) { src = src.replace(name[0], "").replace(/^\s*|\s*$/g, ""); + var extend = src.match(/^extends\s+([a-zA-Z_$][0-9a-zA-Z_$]*)/); + if (extend) { + src = src.replace(extend[0], "").replace(/^\s*|\s*$/g, ""); + extend = extend[1]; + } if (utils.findNextToken(src) === "{") { name = name[1]; var body = utils.getTokensBetween(src, "{", "}", true).join(""); src = src.replace(body, ""); //should - context.define.push({name: name, properties: "(" + body + ")"}); + context.define.push({ name: name, extend: extend, properties: "(" + body + ")" }); return src; } else { throw new Error("unexpected token : expected : '{' found : '" + utils.findNextToken(src) + "'"); diff --git a/readme.md b/readme.md index 56d58f0..4dabbe3 100644 --- a/readme.md +++ b/readme.md @@ -146,6 +146,19 @@ To use the flow var flow = nools.compile(__dirname + "/helloworld.nools"), Message = flow.getDefined("message"); ``` +# Type Declaration 'extends' +Defined types in the DSL no support 'extends' keyword for inheritance. + +Any type present in the flow can be extended. Base types must be defined before extended types. + +``` +define EncodedMessage extends Message { + encoding: 'sha1' + ,constructor: function(message, encoding) { + Message.call(this, message); // call superclass manually + this.encoding = encoding + } +} ### Flow Events @@ -342,7 +355,6 @@ session.getFacts(Number); //[1, 2]; session.getFacts(String); //["A", "B"]; ``` - ## Firing the rules diff --git a/test/flow.dsl.test.js b/test/flow.dsl.test.js index 01e3855..fe0fb3d 100644 --- a/test/flow.dsl.test.js +++ b/test/flow.dsl.test.js @@ -593,4 +593,28 @@ it.describe("Flow dsl", function (it) { }); }); }); + /* + it.describe("extended Fact types", function (it) { + var Person, Student, LongTermStudent, Count, session1Fired = {}, session1; + var flow = nools.compile(resolve(__dirname, "./rules/extends.nools"), { + name: 'extendsTest' + }); + Person = flow.getDefined('Person'); + Student = flow.getDefined('Student'); + LongTermStudent = flow.getDefined('LongTermStudent'); + // + session1 = flow.getSession(new Person('Bob'), new Student('Sue', 'harvard'), new LongTermStudent('Jim', 'princeton', 1)).on('fire', function (name) { + session1Fired[name] = session1Fired[name] || { cnt: 0 }; + session1Fired[name].cnt++; + }); + // + it.should(" fire rule(s) correctly according to type. each rule matching a single type ", function (next) { + return session1.match().then(function () { + assert(session1Fired['PersonTest'].cnt === 3); + assert(session1Fired['StudentTest'].cnt === 2); + assert(session1Fired['LongTermStudentTest'].cnt === 1); + }) + }); + }); + */ }); \ No newline at end of file diff --git a/test/rules/extends.nools b/test/rules/extends.nools new file mode 100644 index 0000000..f25a827 --- /dev/null +++ b/test/rules/extends.nools @@ -0,0 +1,46 @@ + +define Person { + constructor: function(name){ + this.name = name; + } +} + +define Student extends Person { + constructor: function(name, school) { + Person.call(this, name); + this.school = school; + } +} + +define LongTermStudent extends Student { + constructor: function(name, school, years) { + Student.call(this, name, school); + this.years = years; + } +} + + +rule PersonTest { + when { + p: Person; + } + then { + } +} + +rule StudentTest { + when { + s: Student; + } + then { + } +} + + +rule LongTermStudentTest { + when { + s: LongTermStudent; + } + then { + } +} \ No newline at end of file From f672179512c74d4cc792f068a8c4f7eb45caffe9 Mon Sep 17 00:00:00 2001 From: Mark Bjerke Date: Thu, 17 Dec 2015 15:04:50 -0800 Subject: [PATCH 4/5] Revert "Implements extends functionality in the dsl" This reverts commit 1259c3d5c4779e9e425dfb9db219c700bf12e92f. --- lib/compile/common.js | 16 +++---------- lib/compile/transpile.js | 40 ++++++++------------------------- lib/parser/nools/tokens.js | 7 +----- readme.md | 14 +----------- test/flow.dsl.test.js | 24 -------------------- test/rules/extends.nools | 46 -------------------------------------- 6 files changed, 14 insertions(+), 133 deletions(-) delete mode 100644 test/rules/extends.nools diff --git a/lib/compile/common.js b/lib/compile/common.js index 15861da..16f519f 100644 --- a/lib/compile/common.js +++ b/lib/compile/common.js @@ -29,10 +29,7 @@ var createFunction = function (body, defined, scope, scopeNames, definedNames) { var createDefined = (function () { - var _createDefined = function (options, defined, scope) { - var action = options.properties - ,proto, base; - // + var _createDefined = function (action, defined, scope) { if (isString(action)) { var declares = []; extd(defined).keys().forEach(function (i) { @@ -60,14 +57,7 @@ var createDefined = (function () { } } }; - if (options.extend) { - base = defined[options.extend]; - proto = Object.create(base.prototype); - ret.prototype = proto; - } - else { - proto = ret.prototype; - } + var proto = ret.prototype; for (var i in action) { proto[i] = action[i]; } @@ -76,7 +66,7 @@ var createDefined = (function () { }; return function (options, defined, scope) { - return _createDefined(options, defined, scope); + return _createDefined(options.properties, defined, scope); }; })(); diff --git a/lib/compile/transpile.js b/lib/compile/transpile.js index ad9e6f5..f0ae8be 100644 --- a/lib/compile/transpile.js +++ b/lib/compile/transpile.js @@ -7,48 +7,26 @@ var extd = require("../extended"), constraintMatcher = require("../constraintMatcher"), parser = require("../parser"); -function definedToJs(options, extend) { +function definedToJs(options) { /*jshint evil:true*/ options = isString(options) ? new Function("return " + options + ";")() : options; - var ret = ["(function(flow){"], value; - + var ret = ["(function(){"], value; + if (options.hasOwnProperty("constructor") && "function" === typeof options.constructor) { ret.push("var Defined = " + options.constructor.toString() + ";"); } else { ret.push("var Defined = function(opts){ for(var i in opts){if(opts.hasOwnProperty(i)){this[i] = opts[i];}}};"); } - if (extend) { - ret.push("var proto = Object.create(flow.getDefined('" + extend + "').prototype); proto.constructor = Defined; Defined.prototype = proto;"); - } - else { - ret.push("var proto = Defined.prototype;"); - } - + ret.push("var proto = Defined.prototype;"); for (var key in options) { - var str; - if (options.hasOwnProperty(key) && key !== 'constructor') { + if (options.hasOwnProperty(key)) { value = options[key]; - str = ("proto." + key + " = "); - if (extd.isFunction(value)) { - str += value.toString(); - } - else { - if (value instanceof Array) { - str += JSON.stringify(value); - } - else { - str += extd.format("%j", value); - } - str += ";" - } - ret.push(str); + ret.push("proto." + key + " = " + (extd.isFunction(value) ? value.toString() : extd.format("%j", value)) + ";"); } } ret.push("return Defined;"); - ret.push("}(this))"); - var sJoin = ret.join(""); - debugger; - return sJoin; + ret.push("}())"); + return ret.join(""); } @@ -170,7 +148,7 @@ exports.transpile = function (flowObj, options) { ret.push(extd(flowObj.define || []).map(function (defined) { var name = defined.name; defined[name] = {}; - return ["var", name, "= defined." + name, "= this.addDefined('" + name + "',", definedToJs(defined.properties, defined.extend) + ");"].join(" "); + return ["var", name, "= defined." + name, "= this.addDefined('" + name + "',", definedToJs(defined.properties) + ");"].join(" "); }).value().join("\n")); ret.push(extd(flowObj.scope || []).map(function (s) { var name = s.name; diff --git a/lib/parser/nools/tokens.js b/lib/parser/nools/tokens.js index faf4721..23391e2 100644 --- a/lib/parser/nools/tokens.js +++ b/lib/parser/nools/tokens.js @@ -240,17 +240,12 @@ var topLevelTokens = { var name = src.match(/^([a-zA-Z_$][0-9a-zA-Z_$]*)/); if (name) { src = src.replace(name[0], "").replace(/^\s*|\s*$/g, ""); - var extend = src.match(/^extends\s+([a-zA-Z_$][0-9a-zA-Z_$]*)/); - if (extend) { - src = src.replace(extend[0], "").replace(/^\s*|\s*$/g, ""); - extend = extend[1]; - } if (utils.findNextToken(src) === "{") { name = name[1]; var body = utils.getTokensBetween(src, "{", "}", true).join(""); src = src.replace(body, ""); //should - context.define.push({ name: name, extend: extend, properties: "(" + body + ")" }); + context.define.push({name: name, properties: "(" + body + ")"}); return src; } else { throw new Error("unexpected token : expected : '{' found : '" + utils.findNextToken(src) + "'"); diff --git a/readme.md b/readme.md index 4dabbe3..56d58f0 100644 --- a/readme.md +++ b/readme.md @@ -146,19 +146,6 @@ To use the flow var flow = nools.compile(__dirname + "/helloworld.nools"), Message = flow.getDefined("message"); ``` -# Type Declaration 'extends' -Defined types in the DSL no support 'extends' keyword for inheritance. - -Any type present in the flow can be extended. Base types must be defined before extended types. - -``` -define EncodedMessage extends Message { - encoding: 'sha1' - ,constructor: function(message, encoding) { - Message.call(this, message); // call superclass manually - this.encoding = encoding - } -} ### Flow Events @@ -355,6 +342,7 @@ session.getFacts(Number); //[1, 2]; session.getFacts(String); //["A", "B"]; ``` + ## Firing the rules diff --git a/test/flow.dsl.test.js b/test/flow.dsl.test.js index fe0fb3d..01e3855 100644 --- a/test/flow.dsl.test.js +++ b/test/flow.dsl.test.js @@ -593,28 +593,4 @@ it.describe("Flow dsl", function (it) { }); }); }); - /* - it.describe("extended Fact types", function (it) { - var Person, Student, LongTermStudent, Count, session1Fired = {}, session1; - var flow = nools.compile(resolve(__dirname, "./rules/extends.nools"), { - name: 'extendsTest' - }); - Person = flow.getDefined('Person'); - Student = flow.getDefined('Student'); - LongTermStudent = flow.getDefined('LongTermStudent'); - // - session1 = flow.getSession(new Person('Bob'), new Student('Sue', 'harvard'), new LongTermStudent('Jim', 'princeton', 1)).on('fire', function (name) { - session1Fired[name] = session1Fired[name] || { cnt: 0 }; - session1Fired[name].cnt++; - }); - // - it.should(" fire rule(s) correctly according to type. each rule matching a single type ", function (next) { - return session1.match().then(function () { - assert(session1Fired['PersonTest'].cnt === 3); - assert(session1Fired['StudentTest'].cnt === 2); - assert(session1Fired['LongTermStudentTest'].cnt === 1); - }) - }); - }); - */ }); \ No newline at end of file diff --git a/test/rules/extends.nools b/test/rules/extends.nools deleted file mode 100644 index f25a827..0000000 --- a/test/rules/extends.nools +++ /dev/null @@ -1,46 +0,0 @@ - -define Person { - constructor: function(name){ - this.name = name; - } -} - -define Student extends Person { - constructor: function(name, school) { - Person.call(this, name); - this.school = school; - } -} - -define LongTermStudent extends Student { - constructor: function(name, school, years) { - Student.call(this, name, school); - this.years = years; - } -} - - -rule PersonTest { - when { - p: Person; - } - then { - } -} - -rule StudentTest { - when { - s: Student; - } - then { - } -} - - -rule LongTermStudentTest { - when { - s: LongTermStudent; - } - then { - } -} \ No newline at end of file From 64881986e501916bc38626de6e2238d25bd287f9 Mon Sep 17 00:00:00 2001 From: Mark Bjerke Date: Mon, 25 Jan 2016 14:24:09 -0800 Subject: [PATCH 5/5] removed gitattributs/gitignore from branch --- .gitattributes | 17 ----------------- .gitignore | 6 ------ 2 files changed, 23 deletions(-) delete mode 100644 .gitattributes delete mode 100644 .gitignore diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index bdb0cab..0000000 --- a/.gitattributes +++ /dev/null @@ -1,17 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto - -# Custom for Visual Studio -*.cs diff=csharp - -# Standard to msysgit -*.doc diff=astextplain -*.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain -*.PDF diff=astextplain -*.rtf diff=astextplain -*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 44c4a1a..0000000 --- a/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -node_modules -nools.iml -.idea -atlassian-ide-plugin.xml -*.njsproj -*.dat