diff --git a/.gitignore b/.gitignore index fbf0c54..4e57223 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ nimcache/ -src/regex src/regex.js tests/tests tests/tests.js docs/ugh +bin/* +bench/bench diff --git a/.travis.yml b/.travis.yml index 3961415..184aceb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ services: - docker env: - - NIM=0.19.0 - NIM=0.19.6 - NIM=0.20.0 - NIM=0.20.2 diff --git a/CHANGELOG.md b/CHANGELOG.md index b7bf8cf..6b39340 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v0.14 +================== + +* Drop Nim 0.19.0 support (0.19.6 is supported) + v0.13.1 ================== diff --git a/bench/README.md b/bench/README.md new file mode 100644 index 0000000..75e29df --- /dev/null +++ b/bench/README.md @@ -0,0 +1,16 @@ +## Benchmarks + +Run first: + +``` +nimble install nimbench +nimble develop +``` + +Run benchmarks: + +``` +nim c -r -d:release bench/bench.nim +``` + +> Try -d:danger as well, but release is what most users will set diff --git a/bench/bench.nim b/bench/bench.nim new file mode 100644 index 0000000..6700819 --- /dev/null +++ b/bench/bench.nim @@ -0,0 +1,112 @@ +import nimbench +import unicode +from re import nil +from regex import nil + +var text = "" +for _ in 0 .. 100000: + text.add("a") +text.add("sol") +for _ in 0 .. 100000: + text.add("b") +#text.add("ฅ") + +var pattern2 = re.re"^\w*sol\w*$" + +bench(re_sol, m): + var d: bool + for i in 0 ..< m: + d = re.match(text, pattern2) + doNotOptimizeAway(d) + +const pattern4 = regex.re(r"\w*sol\w*") #, {regex.RegexFlag.reAscii}) + +benchRelative(regex_sol, m): + var m2: regex.RegexMatch + for i in 0 ..< m: + discard regex.match(text, pattern4, m2) + doNotOptimizeAway(m2) + +var dummyTextNums = """650-253-0001""" + +var pattern_nums = re.re"^[0-9]+-[0-9]+-[0-9]+$" + +bench(re_nums, m): + var d: bool + for i in 0 ..< m: + d = re.match(dummyTextNums, pattern_nums) + doNotOptimizeAway(d) + +const n_pattern_nums = regex.re"[0-9]+-[0-9]+-[0-9]+" + +benchRelative(regex_nums, m): + var m2: regex.RegexMatch + for i in 0 ..< m: + discard regex.match(dummyTextNums, n_pattern_nums, m2) + doNotOptimizeAway(m2) + +var pattern_nums2 = re.re"^[0-9]+..*$" + +bench(re_nums2, m): + var d: bool + for i in 0 ..< m: + d = re.match(dummyTextNums, pattern_nums2) + doNotOptimizeAway(d) + +const n_pattern_nums2 = regex.re"[0-9]+..*" + +benchRelative(regex_nums2, m): + var m3: regex.RegexMatch + for i in 0 ..< m: + discard regex.match(dummyTextNums, n_pattern_nums2, m3) + doNotOptimizeAway(m3) + +var lits_find_re = re.re"do|re|mi|fa|sol" + +bench(re_lits_find, m): + var d: int + for i in 0 ..< m: + d = re.find(text, lits_find_re) + doNotOptimizeAway(d) + +const lits_find = regex.re"do|re|mi|fa|sol" + +benchRelative(regex_lits_find, m): + var m2: regex.RegexMatch + for i in 0 ..< m: + discard regex.find(text, lits_find, m2) + doNotOptimizeAway(m2) + +const bench_text = staticRead("input-text.txt") + +var email_find_all_re = re.re"[\w\.+-]+@[\w\.-]+\.[\w\.-]+" + +bench(re_email_find_all, m): + var d = 0 + for i in 0 ..< m: + for _ in re.findAll(bench_text, email_find_all_re): + d += 1 + doAssert d == 92 + doNotOptimizeAway(d) + +const email_find_all = regex.re"(?-u)[\w\.+-]+@[\w\.-]+\.[\w\.-]+" + +benchRelative(email_find_all, m): + var d = 0 + for i in 0 ..< m: + for _ in regex.findAll(bench_text, email_find_all): + d += 1 + doAssert d == 92 + doNotOptimizeAway(d) + +when false: + bench(runes, m): + for i in text.runes: + memoryClobber() + +bench(dummy, m): + for i in 0 ..< m: + memoryClobber() + +when isMainModule: + runBenchmarks() diff --git a/bench/input-text.txt b/bench/input-text.txt new file mode 100644 index 0000000..595dd6f --- /dev/null +++ b/bench/input-text.txt @@ -0,0 +1,206215 @@ +This file is a concatenation of [Learn X in Y minutes](https://github.com/adambard/learnxinyminutes-docs) for testing purposes. + +It is published under the original project license ([Creative Commons Attribution-ShareAlike 3.0 Unported](http://creativecommons.org/licenses/by-sa/3.0/deed.en_US)). + +------ +category: tool +tool: amd +contributors: + - ["Frederik Ring", "https://github.com/m90"] +filename: learnamd.js +--- + +## Getting Started with AMD + +The **Asynchronous Module Definition** API specifies a mechanism for defining +JavaScript modules such that the module and its dependencies can be asynchronously +loaded. This is particularly well suited for the browser environment where +synchronous loading of modules incurs performance, usability, debugging, and +cross-domain access problems. + +### Basic concept +```javascript +// The basic AMD API consists of nothing but two methods: `define` and `require` +// and is all about module definition and consumption: +// `define(id?, dependencies?, factory)` defines a module +// `require(dependencies, callback)` imports a set of dependencies and +// consumes them in the passed callback + +// Let's start by using define to define a new named module +// that has no dependencies. We'll do so by passing a name +// and a factory function to define: +define('awesomeAMD', function(){ + var isAMDAwesome = function(){ + return true; + }; + // The return value of a module's factory function is + // what other modules or require calls will receive when + // requiring our `awesomeAMD` module. + // The exported value can be anything, (constructor) functions, + // objects, primitives, even undefined (although that won't help too much). + return isAMDAwesome; +}); + +// Now, let's define another module that depends upon our `awesomeAMD` module. +// Notice that there's an additional argument defining our +// module's dependencies now: +define('loudmouth', ['awesomeAMD'], function(awesomeAMD){ + // dependencies will be passed to the factory's arguments + // in the order they are specified + var tellEveryone = function(){ + if (awesomeAMD()){ + alert('This is sOoOo rad!'); + } else { + alert('Pretty dull, isn\'t it?'); + } + }; + return tellEveryone; +}); + +// As we do know how to use define now, let's use `require` to +// kick off our program. `require`'s signature is `(arrayOfDependencies, callback)`. +require(['loudmouth'], function(loudmouth){ + loudmouth(); +}); + +// To make this tutorial run code, let's implement a very basic +// (non-asynchronous) version of AMD right here on the spot: +function define(name, deps, factory){ + // notice how modules without dependencies are handled + define[name] = require(factory ? deps : [], factory || deps); +} + +function require(deps, callback){ + var args = []; + // first let's retrieve all the dependencies needed + // by the require call + for (var i = 0; i < deps.length; i++){ + args[i] = define[deps[i]]; + } + // satisfy all the callback's dependencies + return callback.apply(null, args); +} +// you can see this code in action here: http://jsfiddle.net/qap949pd/ +``` + +### Real-world usage with require.js + +In contrast to the introductory example, `require.js` (the most popular AMD library) actually implements the **A** in **AMD**, enabling you to load modules and their dependencies asynchronously via XHR: + +```javascript +/* file: app/main.js */ +require(['modules/someClass'], function(SomeClass){ + // the callback is deferred until the dependency is loaded + var thing = new SomeClass(); +}); +console.log('So here we are, waiting!'); // this will run first +``` + +By convention, you usually store one module in one file. `require.js` can resolve module names based on file paths, so you don't have to name your modules, but can simply reference them using their location. In the example `someClass` is assumed to be in the `modules` folder, relative to your configuration's `baseUrl`: + +* app/ + * main.js + * modules/ + * someClass.js + * someHelpers.js + * ... + * daos/ + * things.js + * ... + +This means we can define `someClass` without specifying a module id: + +```javascript +/* file: app/modules/someClass.js */ +define(['daos/things', 'modules/someHelpers'], function(thingsDao, helpers){ + // module definition, of course, will also happen asynchronously + function SomeClass(){ + this.method = function(){/**/}; + // ... + } + return SomeClass; +}); +``` +To alter the default path mapping behavior use `requirejs.config(configObj)` in your `main.js`: + +```javascript +/* file: main.js */ +requirejs.config({ + baseUrl : 'app', + paths : { + // you can also load modules from other locations + jquery : '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min', + coolLibFromBower : '../bower_components/cool-lib/coollib' + } +}); +require(['jquery', 'coolLibFromBower', 'modules/someHelpers'], function($, coolLib, helpers){ + // a `main` file needs to call require at least once, + // otherwise no code will ever run + coolLib.doFancyStuffWith(helpers.transform($('#foo'))); +}); +``` +`require.js`-based apps will usually have a single entry point (`main.js`) that is passed to the `require.js` script tag as a data-attribute. It will be automatically loaded and executed on pageload: + +```html + + +
+Name:
+ + element to the application variable name.
+*/
+
My first expression: {{ 5 + 5 }}
+My first expression: {{ 5 + 5 }}
+Name:
+{{name}}
+Total in dollar: {{ quantity * cost }}
+The name is
+The name is {{ person.lastName }}
+The third result is {{ points[2] }}
+Name:
+You wrote: {{ firstName }}
+The name is {{ lastName | uppercase }}
+ +The name is {{ lastName | lowercase }}
+ +Total = {{ (quantity * price) | currency }}
+ +{{ x.Name }} | +{{ x.Country }} | +
{{ x.Name }} | +{{ x.Country }} | +
{{ $index + 1 }} | +{{ x.Name }} | +{{ x.Country }} | +
{{ x.Name }} | +{{ x.Name }} | +{{ x.Country }} | +{{ x.Country }} | +
+ +
+ ++Button +
+ ++ +
+ +// If the value of mySwitch evaluates to false, the button will not be disabled: ++ +
+ +// The ng-show directive shows or hides an HTML element. + +I am visible.
+ +I am not visible.
+ +I am visible.
+{{ count }}
+ +
+First Name:
+Last Name:
+
+Full Name: {{firstName + " " + lastName}}
+
element with two input fields, +// according to the value (true or false) of myVar. +// The function toggle() toggles myVar between true and false. +// The value ng-hide="true" makes the element invisible. + + +// The ng-show directive can also be used to set the visibility of a part of an application. +// The value ng-show="false" makes an HTML element invisible. +// The value ng-show="true" makes the element visible. +// Here is the same example as above, using ng-show instead of ng-hide: +
+First Name:
+Last Name:
+
+Full Name: {{firstName + " " + lastName}}
+
هذه فقرة.
+هذه فقرة أخرى.
+هذه فقرة.
+هذه فقرة أخرى.
+العنوان الأول | +العنوان الثاني | +
---|---|
الصف الأول، العمود الأول | +الصف الأول، العمود الثاني | +
الصف الثاني، العمود الأول | +الصف الثاني، العمود الأول | +
Set myVariable to "myValue"
+Set myNumber to 3.14
+Display myVariable:
Display myNumber:
Set myArray1 to an array of 1 dimension using literal or bracket notation
+Set myArray2 to an array of 1 dimension using function notation
+Contents of myArray1
+Contents of myArray2
+1 + 1 =
10 - 7 =
15 * 10 =
100 / 5 =
120 % 5 =
120 mod 5 =
Is 1 eq 1?
Is 15 neq 1?
Is 10 gt 8?
Is 1 lt 2?
Is 10 gte 5?
Is 1 lte 5?
Is 1 == 1?
Is 15 != 1?
Is 10 > 8?
Is 1 < 2?
Is 10 >= 5?
Is 1 <= 5?
Condition to test for: "
Index equals
Set myArray3 to [5, 15, 99, 45, 100]
+ +Index equals
Set myArray4 to ["Alpha", "Bravo", "Charlie", "Delta", "Echo"]
+ +Index equals
Set myArray5 to [5, 15, 99, 45, 100]
+ +Value | +As Boolean | +As number | +As date-time | +As string | +
---|---|---|---|---|
"Yes" | +TRUE | +1 | +Error | +"Yes" | +
"No" | +FALSE | +0 | +Error | +"No" | +
TRUE | +TRUE | +1 | +Error | +"Yes" | +
FALSE | +FALSE | +0 | +Error | +"No" | +
Number | +True if Number is not 0; False otherwise. | +Number | +See "Date-time values" earlier in this chapter. | +String representation of the number (for example, "8"). | +
String | +If "Yes", True If "No", False If it can be converted to 0, False If it can be converted to any other number, True |
+ If it represents a number (for example, "1,000" or "12.36E-12"), it is converted to the corresponding number. | +If it represents a date-time (see next column), it is converted to the numeric value of the corresponding date-time object. If it is an ODBC date, time, or timestamp (for example "{ts '2001-06-14 11:30:13'}", or if it is expressed in a standard U.S. date or time format, including the use of full or abbreviated month names, it is converted to the corresponding date-time value. Days of the week or unusual punctuation result in an error. Dashes, forward-slashes, and spaces are generally allowed. |
+ String | +
Date | +Error | +The numeric value of the date-time object. | +Date | +An ODBC timestamp. | +
#sayHello()#
#getHello()#
#getWorld()#
#setHello("Hola")#
#setWorld("mundo")#
#sayHello()#
#getHello()#
#getWorld()#