Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

merge

  • Loading branch information...
commit 46e4ca3e545a03cccec11fc5732ecf3f387d0397 2 parents 192a719 + e701b0d
Andrey Sitnik authored

Showing 27 changed files with 597 additions and 2,883 deletions. Show diff stats Hide diff stats

  1. 0  {js → }/LICENSE
  2. +129 15 README.md
  3. +3 0  Rakefile
  4. +0 2  evolu.org/.gitignore
  5. +0 3  evolu.org/content/index.html.haml
  6. +0 14 evolu.org/content/js.html.haml
  7. BIN  evolu.org/layout/arrow.png
  8. BIN  evolu.org/layout/favicon.ico
  9. BIN  evolu.org/layout/hatching.png
  10. +0 32 evolu.org/layout/layout.html.haml
  11. BIN  evolu.org/layout/logo.png
  12. +0 134 evolu.org/layout/style.sass
  13. +0 71 evolu.org/script/build
  14. +0 40 evolu.org/script/public
  15. +0 11 evolu.org/script/watch
  16. +0 102 js/README.md
  17. +0 219 js/spec/browser.html
  18. +0 1,893 js/spec/jspec.js
  19. +0 12 js/spec/node.js
  20. +0 137 js/spec/tests/standard.js
  21. +153 71 js/lib/evolu.js → lib/evolu-lang.js
  22. +64 64 js/spec/tests/code.js → spec/codeSpec.js
  23. +9 9 js/spec/tests/integration.js → spec/integrationSpec.js
  24. +13 0 spec/javascripts/support/jasmine.yml
  25. +32 0 spec/javascripts/support/jasmine_runner.rb
  26. +57 54 js/spec/tests/language.js → spec/languageSpec.js
  27. +137 0 spec/standardSpec.js
0  js/LICENSE → LICENSE
File renamed without changes
144 README.md
Source Rendered
... ... @@ -1,11 +1,9 @@
1   -# Evolu
  1 +# Evolu Lang
2 2
3   -*Project is moved to <https://github.com/ai/evolu-lang>.*
4   -
5   -Evolu is a programming language to automatically generate programs by evolution
6   -(genetic programming). Generator (genetic algorithm, particle swarm optimization
7   -or other) will use Evolu to compile bytes with random mutations (gene) to
8   -program, run and test it.
  3 +Evolu Lang is a programming language to automatically generate programs by
  4 +evolution (genetic programming). Generator (genetic algorithm, particle swarm
  5 +optimization or other) will use Evolu Lang to compile bytes with random
  6 +mutations (gene) to program, run and test it.
9 7
10 8 It is created to be readable by human beings (instead of
11 9 artificial neural networks) and easily editable and mixable for genetic
@@ -13,8 +11,8 @@ algorithm (instead of tree structure and modern production languages).
13 11
14 12 ## How It Works
15 13
16   -A developer defines commands by Evolu to create a business specific language
17   -(or uses the standard commands pack) and defines tests (*fitness*),
  14 +A developer defines commands by Evolu Lang to create a business specific
  15 +language (or uses the standard commands pack) and defines tests (*fitness*),
18 16 to determine what program he or she wants to create.
19 17
20 18 In the next step he or she uses a generator, which uses a genetic algorithm,
@@ -22,7 +20,7 @@ particle swarm optimization or other evolutionary algorithms.
22 20 In the simplest case:
23 21 1. Generator creates an array (*population*) with random bytes (*genes*).
24 22 2. It adds random changes (*mutation*) to each byte stream in this array.
25   -3. It compiles each of these random byte streams by Evolu language and runs
  23 +3. It compiles each of these random byte streams by Evolu Lang and runs
26 24 obtained programs with tests.
27 25 4. Bad programs will be deleted and best programs will be copied to the
28 26 population.
@@ -64,9 +62,10 @@ In the simplest case:
64 62 Each Evolu program starts with an `EVOLU:` prefix to check, that the file or
65 63 stream contains a program.
66 64
67   -Like XML, Evolu is just a syntax format. So you need to have business-specific
68   -languages and mark, what language is used in this Evolu program. So, after
69   -the `EVOLU:` prefix, stream must contain language name and a colon.
  65 +Like XML, Evolu Lang is just a syntax format. So you need to have
  66 +business-specific languages and mark, what language is used in this Evolu
  67 +program. So, after the `EVOLU:` prefix, stream must contain language name and a
  68 +colon.
70 69
71 70 <program> ::= "EVOLU:" <language> ":" <rules>
72 71
@@ -98,7 +97,7 @@ bytes (beginning with `1`) after command encode parameter number. For example,
98 97 <parameter> ::= ( 1xxxxxxx )*
99 98
100 99 There are 127 different commands number in one command byte, but language may
101   -have less commands. A mutation can generate any bytes and Evolu must try to
  100 +have less commands. A mutation can generate any bytes and Evolu Lang must try to
102 101 decode any of them. So, commands are marked numbers in a circle: if language
103 102 have 3 commands (`separator`, `a`, `b`), 0 will be encode `separator`, 1 – `a`,
104 103 2 – `b`, but 3 will encode `separator` again, 4 – `a`, etc.
@@ -116,7 +115,7 @@ If a rule doesn’t have any conditions it will run once at start as constructor
116 115
117 116 ### Standard Commands Pack
118 117
119   -You can create your own language with Evolu, but for common tasks Evolu has
  118 +You can create your own language with Evolu Lang, but for common tasks it has
120 119 the standard commands pack to create Turing completeness languages.
121 120
122 121 Conditions:
@@ -136,3 +135,118 @@ Commands:
136 135
137 136 The developer must define, what input and output signals will be in the
138 137 language, but variables can be added dynamically by mutation.
  138 +
  139 +## How To
  140 +
  141 +For example, we will generate program (by genetic programming), which calculates
  142 +`tick` signals and on `result` signal it sends whether an `even` or an `odd`
  143 +tick count it received.
  144 +
  145 +### Language
  146 +
  147 +Like XML, Evolu Lang is just a syntax format. So you need to define a language
  148 +for your task using the `evolu.lang.add(name, initializer)` function.
  149 +It receives a language name (to use it as a prefix in the source code for
  150 +storing and transferring the program) and function (which adds the language
  151 +commands to `this`), and returns a new language.
  152 +
  153 +For the common cases you can use the standard commands pack, and you only need
  154 +to define the input/output signals.
  155 +
  156 + var lang = evolu.lang.add('EVEN-ODD', function() {
  157 + this.add(evolu.lang.standard.input('tick', 'result'))
  158 + this.add(evolu.lang.standard.output('even', 'odd'))
  159 + lang.add(evolu.lang.standard.variables)
  160 + })
  161 +
  162 +### Population
  163 +
  164 +Get any genetic algorithm library or write it by yourself. Use a byte array
  165 +(array of integers from `0` to `255`, for example `[0, 255, 13, 68, 145]`) as
  166 +genes.
  167 +
  168 + var population = []
  169 + // Add 100 genes to the first population
  170 + for (var i = 0; i < 100; i++) {
  171 + var gene = []
  172 + // Each gene will have random length
  173 + while (Math.random < 0.9) {
  174 + // Add a random byte to the current gene
  175 + gene.push(Math.round(255 * Math.random()))
  176 + }
  177 + }
  178 +
  179 +### Mutation
  180 +
  181 +*Note that the integers in an array must be from `0` to `255`.*
  182 +
  183 +In the genetic algorithm you can use any types of mutation for a byte stream
  184 +(a lot of libraries contain them). You can add, change, delete and
  185 +move bytes in the array.
  186 +
  187 +You can use crossover to mix arrays or just move a part of bytes from one array
  188 +to another (like horizontal gene transfer).
  189 +
  190 +### Selection
  191 +
  192 +To calculate fitness for each gene in the population, you need to compile
  193 +each byte array:
  194 +
  195 + var program = lang.compile(population[i])
  196 +
  197 +Send the data to the program and check its output data to calculate fitness.
  198 +It’s like automatic unit testing, but your test must return a score,
  199 +not just a pass/fail result.
  200 +
  201 +If you use the standard commands pack, you can use the `receive_signal` event
  202 +to listen output signals and the `signal` function to send input signals:
  203 +
  204 + output = []
  205 + program.listen('receive_signal', function(signal) {
  206 + output.push(signal)
  207 + })
  208 +
  209 + program.signal('tick').signal('tick').signal('result')
  210 + // Some hypothetical API
  211 + check(output).to_contain('even')
  212 +
  213 + output = []
  214 + program.signal('tick').signal('result')
  215 + check(output).to_contain('odd')
  216 +
  217 +### Saving
  218 +
  219 +When you generate a program for your demands, you can save it to a disk or send
  220 +to a server:
  221 +
  222 + var source = bestProgram.toSource()
  223 +
  224 +Source is a string with `EVOLU:` and a language name in prefix. For example,
  225 +`"EVOLU:EVEN-ODD:\x04\x80\x00\x01\x80\x03\x80\x05…"`.
  226 +
  227 +Use `evolu.lang.compile(string)` to automatically find a language (using the source
  228 +prefix) and compile the bytes into a program:
  229 +
  230 + bestProgram == evolu.lang.compile(bestProgram.toSource())
  231 +
  232 +## Testing
  233 +
  234 +1. Install Rake (Ruby make) and RubyGems (Ruby package manager).
  235 + For example, on Ubuntu:
  236 +
  237 + sudo apt-get install rake rubygems
  238 +
  239 +2. Install `jasmin` gem:
  240 +
  241 + gem install jasmin
  242 +
  243 +3. Run test server:
  244 +
  245 + rake jamsin
  246 +
  247 +4. Open <http://localhost:8888>.
  248 +
  249 +## License
  250 +
  251 +Evolu Lang is licensed under the GNU Lesser General Public License version 3.
  252 +See the LICENSE file or http://www.gnu.org/licenses/lgpl.html.
3  Rakefile
... ... @@ -0,0 +1,3 @@
  1 +
  2 +require 'jasmine'
  3 +load 'jasmine/tasks/jasmine.rake'
2  evolu.org/.gitignore
... ... @@ -1,2 +0,0 @@
1   -public/
2   -script/.sass-cache/
3  evolu.org/content/index.html.haml
... ... @@ -1,3 +0,0 @@
1   -- @title = 'Evolu - language for genetic programming'
2   -%article
3   - = readme('/')
14 evolu.org/content/js.html.haml
... ... @@ -1,14 +0,0 @@
1   -- @title = 'Evolu.js - genetic programming for JavaScript'
2   -%article
3   - - html = readme('/js/')
4   - - html.gsub! 'Evolu.js</h1>', 'Evolu.<span>js</span></h1>'
5   - - html.gsub! /License<\/h2>[\w\W]+$/, ''
6   - = html
7   -
8   - :markdown
9   - ## License
10   -
11   - Evolu.js is licensed under the
12   - [GNU Lesser General Public License version 3][lgpl].
13   -
14   - [lgpl]: http://www.gnu.org/licenses/lgpl.html
BIN  evolu.org/layout/arrow.png
BIN  evolu.org/layout/favicon.ico
Binary file not shown
BIN  evolu.org/layout/hatching.png
32 evolu.org/layout/layout.html.haml
... ... @@ -1,32 +0,0 @@
1   -!!! 5
2   -%head
3   - %meta( charset="UTF-8" )/
4   - %title= @title
5   - %meta( name="keywords" content="evolu, genetic programming, genetic algorithm, programming language, evolution, javascript" )/
6   - %meta( name="description" content="Evolu is a programming language to genetic programming (automatically generate programs by evolution)" )/
7   - %link( rel="stylesheet" href="style.css" )/
8   - %link( href="favicon.ico" rel="icon" type="image/x-icon" )/
9   - %meta( content="width=device-width; initial-scale=1.0; maximum-scale=1.0" name="viewport" )/
10   - /[if IE]
11   - %script( src="http://html5shiv.googlecode.com/svn/trunk/html5.js" )
12   - - if production?
13   - :javascript
14   - var _gaq = _gaq || [];
15   - _gaq.push(['_setAccount', 'UA-18068035-1']);
16   - _gaq.push(['_trackPageview']);
17   - (function() {
18   - var ga = document.createElement('script'); ga.async = true;
19   - ga.src = ('https:' == document.location.protocol ?
20   - 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
21   - var s = document.getElementsByTagName('script')[0];
22   - s.parentNode.insertBefore(ga, s);
23   - })();
24   -%body
25   - %header
26   - #logo
27   - %nav
28   - = menu('Language', 'index.html')
29   - = menu('<abbr title="JavaScript">JS</abbr> interpreter', 'js.html')
30   - %a( href="http://github.com/ai/evolu" ) Sources
31   - %a( href="http://github.com/ai/evolu/issues" ) Issues
32   - = yield
BIN  evolu.org/layout/logo.png
134 evolu.org/layout/style.sass
... ... @@ -1,134 +0,0 @@
1   -*
2   - margin: 0
3   - padding: 0
4   -
5   -body
6   - background: white url(hatching.png) repeat-x 0 0
7   - color: black
8   - margin: 0 0.5em 2em 0.5em
9   - line-height: 1.7
10   - font-family: Georgia, serif
11   -
12   -header, article
13   - display: block
14   - width: 34em
15   - max-width: 100%
16   - margin: 0 auto
17   - position: relative
18   -
19   -a
20   - text-decoration: none
21   - color: black
22   - border-bottom: 1px solid #999
23   - &:hover
24   - border-color: black
25   -
26   -header
27   - line-height: 1
28   - #logo
29   - position: absolute
30   - top: 0
31   - left: 0
32   - width: 72px
33   - height: 72px
34   - margin: 3.6em 0 0 -100px
35   - background: url(logo.png) no-repeat 0 0
36   - a
37   - padding: 0.7em
38   - margin: 9px 1px 10px 0
39   - font-family: "Times New Roman", serif
40   - letter-spacing: 1px
41   - text-transform: uppercase
42   - position: relative
43   - background: white
44   - color: black
45   - float: left
46   - border: none
47   - &:last-child
48   - margin-right: 0
49   - &.open, &:hover, &:active
50   - background: black
51   - color: white
52   - text-shadow: #ccc 0 0 1px
53   - &:active
54   - border: 3px solid black
55   - outline: 3px solid white
56   - margin: 6px -2px 0 -3px
57   - z-index: 2
58   - div
59   - margin-right: 1px
60   - position: absolute
61   - left: 0
62   - top: 100%
63   - height: 7px
64   - width: 100%
65   - background: url(arrow.png) no-repeat 50% 100%
66   -
67   -article
68   - clear: both
69   -
70   -h1, h2, h3
71   - margin: 1em 0 0.5em 0
72   - font-weight: normal
73   - font-family: Georgia, serif
74   - line-height: 1.1
75   - text-shadow: #ccc 1px 1px 1px
76   -h1
77   - margin: 0 0 0.4em 0
78   - padding-top: 0.3em
79   - font-size: 340%
80   - span
81   - color: #666
82   -h2
83   - font-size: 190%
84   -h3
85   - font-size: 160%
86   -abbr
87   - border: none
88   -
89   -p, ul, ol, pre
90   - margin-bottom: 1em
91   -p + ul, p + ol
92   - margin-top: -1em
93   -
94   -@media handheld, screen and (max-device-width: 481px), screen and (max-width: 30em)
95   - header
96   - #logo
97   - position: absolute
98   - margin: 15px 0 0.5em -0.5em
99   - nav
100   - margin-left: 75px
101   - float: left
102   - a
103   - margin-bottom: 0
104   - text-shadow: white 0 0 0
105   - &:hover
106   - background: white
107   - color: black
108   - &.open, &:active
109   - background: black
110   - color: white
111   - &:active
112   - border: none
113   - outline: none
114   - margin: 9px 1px 0 0
115   - div
116   - display: none
117   - ul, ol
118   - margin-left: 1.5em
119   -
120   -@media print
121   - body
122   - background: none
123   - margin: 0
124   - header
125   - display: none
126   - article
127   - margin: 0
128   - width: auto
129   - h1, h2, h3
130   - text-shadow: white 0 0 0
131   - h1
132   - margin-top: 0
133   - ul, ol
134   - margin-left: 1.5em
71 evolu.org/script/build
... ... @@ -1,71 +0,0 @@
1   -#!/usr/bin/env ruby
2   -# Compile HAML and SASS and copy all files to public/
3   -
4   -require 'pathname'
5   -require 'yaml'
6   -require 'rubygems'
7   -require 'haml'
8   -require 'sass'
9   -require 'maruku'
10   -
11   -ROOT = Pathname.new(__FILE__).dirname.parent.realpath
12   -PROJECT = ROOT.parent
13   -CONTENT = ROOT.join('content')
14   -LAYOUT = ROOT.join('layout')
15   -PUBLIC = ROOT.join('public')
16   -
17   -def production?
18   - 'production' == ARGV.first
19   -end
20   -
21   -def readme(path)
22   - path = path[1..-1] + 'README.md'
23   - Maruku.new(File.read(PROJECT.join(path))).to_html
24   -end
25   -
26   -def menu(title, link)
27   - options = ''
28   - if link == @page
29   - title += '<div></div>'
30   - options = ' class="open"'
31   - end
32   - '<a href="' + link + '"' + options + '>' + title + '</a>'
33   -end
34   -
35   -def build
36   - PUBLIC.rmtree if PUBLIC.exist?
37   - PUBLIC.mkpath
38   -
39   - path = LAYOUT + 'layout.html.haml'
40   - layout = Haml::Engine.new(File.read(path), :ugly => true)
41   -
42   - Pathname.glob(CONTENT.join('**/*.haml').to_s) do |haml|
43   - @page = haml.basename('.haml').to_s
44   - file = PUBLIC + haml.relative_path_from(CONTENT).dirname + @page
45   - file.dirname.mkpath
46   - File.open(file, 'w') do |io|
47   - content = Haml::Engine.new(File.read(haml), :ugly => true).render(self)
48   - io.write(layout.render(self) { content })
49   - end
50   - end
51   -
52   - Pathname.glob(LAYOUT.join('**/*.sass').to_s) do |sass|
53   - content = File.read(sass)
54   - css = PUBLIC + sass.relative_path_from(LAYOUT).dirname +
55   - (sass.basename('.sass').to_s + '.css')
56   - css.dirname.mkpath
57   - File.open(css, 'w') do |io|
58   - io.write Sass::Engine.new(content).render
59   - end
60   - end
61   -
62   - Pathname.glob(LAYOUT.join('**/*').to_s, File::FNM_DOTMATCH) do |from|
63   - next if from.directory?
64   - next if '.sass' == from.extname or '.haml' == from.extname
65   - to = PUBLIC + from.relative_path_from(LAYOUT)
66   - to.dirname.mkpath
67   - to.make_link(from)
68   - end
69   -end
70   -
71   -build
40 evolu.org/script/public
... ... @@ -1,40 +0,0 @@
1   -#!/bin/sh
2   -# Build site, copy generated files to gh-pages branch and push it to GitHub.
3   -
4   -cd `dirname $0`
5   -
6   -if [ "`git status -s`" ]; then
7   - echo "You have uncommitted changes:"
8   - git status -s
9   - exit 0
10   -fi
11   -
12   -./build production
13   -cd ../..
14   -
15   -git checkout gh-pages > /dev/null 2>&1
16   -
17   -for file in `ls --ignore=evolu.org --ignore=CNAME`; do
18   - rm -R $file
19   -done
20   -
21   -for file in `ls evolu.org/public`; do
22   - cp evolu.org/public/$file ./
23   -done
24   -
25   -rm -R evolu.org/
26   -
27   -if [ -z "`git status -s`" ]; then
28   - echo "You haven't any new changes to update site"
29   - git checkout master > /dev/null 2>&1
30   - exit 0
31   -fi
32   -
33   -if [ "`git status | grep deleted:`" ]; then
34   - git status | grep deleted: | cut -f 2 -d : | xargs git rm
35   -fi
36   -git add .
37   -
38   -git commit -m "Update generated files from evolu.org/ in master branch"
39   -
40   -git push origin gh-pages && git checkout master > /dev/null 2>&1
11 evolu.org/script/watch
... ... @@ -1,11 +0,0 @@
1   -#!/bin/sh
2   -# Run script/build automatically on any changes in content/ or layout/.
3   -# It work only on Linux and require inotifywait (in Ubuntu you can install it by
4   -# `sudo apt-get install inotify-tools`).
5   -
6   -cd `dirname $0`
7   -while true; do
8   - ./build
9   - inotifywait -re MOVE_SELF,MODIFY,CLOSE_WRITE ../../
10   - sleep 1
11   -done
102 js/README.md
Source Rendered
... ... @@ -1,102 +0,0 @@
1   -# Evolu.js
2   -
3   -Evolu.js is a JavaScript implementation of virtual machine to execute programs
4   -in Evolu programming language.
5   -
6   -## How To
7   -
8   -For example, we will generate program (by genetic programming), which calculates
9   -`tick` signals and on `result` signal it sends whether an `even` or an `odd`
10   -tick count it received.
11   -
12   -### Language
13   -
14   -Like XML, Evolu is just a syntax format. So you need to define a language for
15   -your task using the `evolu.lang(name, initializer)` function. It receives
16   -a language name (to use it as a prefix in the source code for storing and
17   -transferring the program) and function (which adds the language commands to
18   -`this`), and returns a new language.
19   -
20   -For the common cases you can use the standard commands pack, and you only need
21   -to define the input/output signals.
22   -
23   - var lang = evolu.lang('EVEN-ODD', function() {
24   - this.add(evolu.standard.input('tick', 'result'))
25   - this.add(evolu.standard.output('even', 'odd'))
26   - lang.add(evolu.standard.variables)
27   - })
28   -
29   -### Population
30   -
31   -Get any genetic algorithm library or write it by yourself. Use a byte array
32   -(array of integers from `0` to `255`, for example `[0, 255, 13, 68, 145]`) as
33   -genes.
34   -
35   - var population = []
36   - // Add 100 genes to the first population
37   - for (var i = 0; i < 100; i++) {
38   - var gene = []
39   - // Each gene will have random length
40   - while (Math.random < 0.9) {
41   - // Add a random byte to the current gene
42   - gene.push(Math.round(255 * Math.random()))
43   - }
44   - }
45   -
46   -### Mutation
47   -
48   -*Note that the integers in an array must be from `0` to `255`.*
49   -
50   -In the genetic algorithm you can use any types of mutation for a byte stream
51   -(a lot of libraries contain them). You can add, change, delete and
52   -move bytes in the array.
53   -
54   -You can use crossover to mix arrays or just move a part of bytes from one array
55   -to another (like horizontal gene transfer).
56   -
57   -### Selection
58   -
59   -To calculate fitness for each gene in the population, you need to compile
60   -each byte array:
61   -
62   - var program = lang.compile(population[i])
63   -
64   -Send the data to the program and check its output data to calculate fitness.
65   -It’s like automatic unit testing, but your test must return a score,
66   -not just a pass/fail result.
67   -
68   -If you use the standard commands pack, you can use the `receive_signal` event
69   -to listen output signals and the `signal` function to send input signals:
70   -
71   - output = []
72   - program.listen('receive_signal', function(signal) {
73   - output.push(signal)
74   - })
75   -
76   - program.signal('tick').signal('tick').signal('result')
77   - // Some hypothetical API
78   - check(output).to_contain('even')
79   -
80   - output = []
81   - program.signal('tick').signal('result')
82   - check(output).to_contain('odd')
83   -
84   -### Saving
85   -
86   -When you generate a program for your demands, you can save it to a disk or send
87   -to a server:
88   -
89   - var source = bestProgram.toSource()
90   -
91   -Source is a string with `EVOLU:` and a language name in prefix. For example,
92   -`"EVOLU:EVEN-ODD:\x04\x80\x00\x01\x80\x03\x80\x05…"`.
93   -
94   -Use `evolu.compile(string)` to automatically find a language (using the source
95   -prefix) and compile the bytes into a program:
96   -
97   - bestProgram == evolu.compile(bestProgram.toSource())
98   -
99   -## License
100   -
101   -Evolu.js is licensed under the GNU Lesser General Public License version 3.
102   -See the LICENSE file or http://www.gnu.org/licenses/lgpl.html.
219 js/spec/browser.html
... ... @@ -1,219 +0,0 @@
1   -<!DOCTYPE html>
2   -<html>
3   - <head>
4   - <meta charset='UTF-8' />
5   - <title>Darwin.js specs</title>
6   - <script type="text/javascript" src="../lib/evolu.js"></script>
7   - <script type="text/javascript" src="./jspec.js"></script>
8   -
9   - <script type="text/javascript" src="./tests/language.js"></script>
10   - <script type="text/javascript" src="./tests/code.js"></script>
11   - <script type="text/javascript" src="./tests/standard.js"></script>
12   - <script type="text/javascript" src="./tests/integration.js"></script>
13   -
14   - <script>
15   - JSpec.include({
16   - reporters: {
17   - Darwin: function(results) {
18   - if (results.stats.failures)
19   - document.body.className = 'has-failures'
20   - var set = {
21   - 'jspec-version': JSpec.version,
22   - 'result': (results.stats.failures ? 'Fail' : 'OK'),
23   - 'passed-count': results.stats.passes,
24   - 'failures-count': results.stats.failures,
25   - 'duration': results.duration,
26   - 'suites': JSpec.map(results.allSuites, function(suite) {
27   - return '' +
28   - '<li>' +
29   - '<h2>' + JSpec.escape(suite.description) + '</h2>' +
30   - '<ul>' +
31   - JSpec.map(suite.specs, function(i, spec) {
32   - var cls = spec.passed() ? 'pass' : 'fail'
33   - return '' +
34   - '<li class="' + cls + '">' +
35   - '<div class="assertions">' +
36   - spec.assertionsGraph() +
37   - '</div>' +
38   - '<p>' + JSpec.escape(spec.description) + '</p>' +
39   - '<ol>' +
40   - JSpec.map(spec.failures(), function(a) {
41   - return '' +
42   - '<li>' + JSpec.escape(a.message) + '</li>'
43   - }).join('') +
44   - '</ol>' +
45   - '</li>'
46   - }).join('') +
47   - '</ul>' +
48   - '</li>'
49   - }).join('')
50   - }
51   - for (id in set) {
52   - document.getElementById(id).innerHTML = set[id]
53   - }
54   - }
55   - }
56   - })
57   - </script>
58   - <style>
59   - * {
60   - margin: 0;
61   - padding: 0;
62   - }
63   - body {
64   - font-family: "Droid Sans", "Trebuchet MS", sans-serif;
65   - line-height: 1.5;
66   - width: 40em;
67   - max-width: 100%;
68   - margin: 0 auto;
69   - background: #f4f4f4;
70   - }
71   - .content {
72   - padding: 0.7em 1.7em 1.2em 1.7em;
73   - background: white;
74   - border: 1px solid #d8d8d8;
75   - border-width: 0 1px;
76   - box-shadow: #bbb 0 0 0.5em;
77   - -webkit-box-shadow: #bbb 0 0 0.5em;
78   - -moz-box-shadow: #bbb 0 0 0.5em;
79   - }
80   - .jspec {
81   - font-size: 130%;
82   - color: #ccc;
83   - font-weight: normal;
84   - margin-top: 1.1em;
85   - float: right;
86   - }
87   - h1 {
88   - font: italic 300% Georgia, serif;
89   - margin-bottom: 0.4em;
90   - }
91   - h1 span {
92   - color: #358c23;
93   - }
94   - .has-failures h1 span {
95   - color: #8c3523;
96   - }
97   -
98   - .header .summary {
99   - clear: both;
100   - margin: 0 -1.82em 1.5em -1.82em;
101   - padding: 0 1.7em;
102   - background: #3da329;
103   - background: -webkit-gradient(linear, left top, left bottom,
104   - color-stop(0%, #3da329), color-stop(100%, #369124));
105   - background: -moz-linear-gradient(top, #3da329, #369124);
106   - border-top: 0.1em solid #56bc42;
107   - border-bottom: 0.1em solid #318420;
108   - color: white;
109   - box-shadow: #ccc 0 0.1em 0.3em;
110   - -moz-box-shadow: #ccc 0 0.1em 0.3em;
111   - -webkit-box-shadow: #aaa 0 0.1em 0.3em;
112   - }
113   - .has-failures .header .summary {
114   - background: #a33d29;
115   - background: -webkit-gradient(linear, left top, left bottom,
116   - color-stop(0%, #a33d29), color-stop(100%, #913624));
117   - background: -moz-linear-gradient(top, #a33d29, #913624);
118   - border-top: 0.1em solid #bc5642;
119   - border-bottom: 0.1em solid #843120;
120   - }
121   - .header .summary * {
122   - display: inline-block;
123   - }
124   - .header .summary h2 {
125   - font-weight: bold;
126   - color: white;
127   - width: 3em;
128   - }
129   - .header .summary dl {
130   - margin-right: 1.5em;
131   - }
132   - .header .summary dd {
133   - margin-left: 0.4em;
134   - font-weight: bold;
135   - }
136   - .header .summary .time {
137   - float: right;
138   - margin-top: 0.5em;
139   - }
140   -
141   - #suites {
142   - font-size: 90%;
143   - }
144   - ul h2 {
145   - font-size: 120%;
146   - font-weight: normal;
147   - margin: 0.7em 0 0.2em 0;
148   - }
149   - ul h3 {
150   - font-size: 100%;
151   - font-weight: normal;
152   - display: inline-block;
153   - padding-right: 1em;
154   - }
155   - ul li {
156   - list-style: none;
157   - }
158   - ul li li.fail {
159   - color: #8c3523;
160   - font-weight: bold;
161   - }
162   - ul li li.pass:before, ul li li.fail:before {
163   - content: '✓';
164   - float: left;
165   - margin-left: -1.3em;
166   - color: #3da329;
167   - }
168   - ul li li.fail:before {
169   - content: '×';
170   - color: #8c3523;
171   - }
172   - ul li li .assertions {
173   - float: right;
174   - }
175   - ul li li span:after {
176   - content: '·';
177   - color: #999;
178   - }
179   - ul li li span.failed:after {
180   - color: #8c3523;
181   - }
182   - ul li li li {
183   - margin: 0 0 0.4em 2em;
184   - font-size: 90%;
185   - list-style-type: decimal;
186   - }
187   - </style>
188   - </head>
189   - <body>
190   - <div class="content">
191   - <div class="header">
192   - <div class="jspec">JSpec <span id="jspec-version"></span></div>
193   - <h1>
194   - Evolu.<span>js</span> specs
195   - </h1>
196   - <div class="summary">
197   - <h2 id="result"></h2>
198   - <dl>
199   - <dt>Passed:</dt>
200   - <dd id="passed-count"></dd>
201   - </dl>
202   - <dl>
203   - <dt>Failures:</dt>
204   - <dd id="failures-count"></dd>
205   - </dl>
206   - <span class="time">
207   - <span id="duration"></span> ms
208   - </span>
209   - </div>
210   - </div>
211   - <ul id="suites">
212   -
213   - </ul>
214   - </div>
215   - <script type="text/javascript">
216   - JSpec.run({ reporter: JSpec.reporters.Darwin }).report()
217   - </script>
218   - </body>
219   -</html>
1,893 js/spec/jspec.js
... ... @@ -1,1893 +0,0 @@
1   -
2   -// JSpec - Core - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
3   -
4   -;(function(){
5   -
6   - JSpec = {
7   - version : '4.3.2',
8   - assert : true,
9   - cache : {},
10   - suites : [],
11   - modules : [],
12   - allSuites : [],
13   - sharedBehaviors: [],
14   - matchers : {},
15   - stubbed : [],
16   - options : {},
17   - request : 'XMLHttpRequest' in this ? XMLHttpRequest : null,
18   - stats : { specs: 0, assertions: 0, failures: 0, passes: 0, specsFinished: 0, suitesFinished: 0 },
19   -
20   - /**
21   - * Default context in which bodies are evaluated.
22   - *
23   - * Replace context simply by setting JSpec.context
24   - * to your own like below:
25   - *
26   - * JSpec.context = { foo : 'bar' }
27   - *
28   - * Contexts can be changed within any body, this can be useful
29   - * in order to provide specific helper methods to specific suites.
30   - *
31   - * To reset (usually in after hook) simply set to null like below:
32   - *
33   - * JSpec.context = null
34   - *
35   - */
36   -
37   - defaultContext : {
38   -
39   - /**
40   - * Return an object used for proxy assertions.
41   - * This object is used to indicate that an object
42   - * should be an instance of _object_, not the constructor
43   - * itself.
44   - *
45   - * @param {function} constructor
46   - * @return {hash}
47   - * @api public
48   - */
49   -
50   - an_instance_of : function(constructor) {
51   - return { an_instance_of : constructor }
52   - },
53   -
54   - /**
55   - * Load fixture at _path_.
56   - *
57   - * Fixtures are resolved as:
58   - *
59   - * - <path>
60   - * - <path>.html
61   - *
62   - * @param {string} path
63   - * @return {string}
64   - * @api public
65   - */
66   -
67   - fixture : function(path) {
68   - if (JSpec.cache[path]) return JSpec.cache[path]
69   - return JSpec.cache[path] =
70   - JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) ||
71   - JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.html')
72   - },
73   -
74   - /**
75   - * Load json fixture at _path_.
76   - *
77   - * JSON fixtures are resolved as:
78   - *
79   - * - <path>
80   - * - <path>.json
81   - *
82   - * @param {string} path
83   - * @return {object}
84   - * @api public
85   - */
86   -
87   - json_fixture: function(path) {
88   - if (!JSpec.cache['json:' + path])
89   - JSpec.cache['json:' + path] =
90   - JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) ||
91   - JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.json')
92   - try {
93   - return eval('(' + JSpec.cache['json:' + path] + ')')
94   - } catch (e) {
95   - throw 'json_fixture("' + path + '"): ' + e
96   - }
97   - }
98   - },
99   -
100   - // --- Objects
101   -
102   - reporters : {
103   -
104   - /**
105   - * Report to server.
106   - *
107   - * Options:
108   - * - uri specific uri to report to.
109   - * - verbose weither or not to output messages
110   - * - failuresOnly output failure messages only
111   - *
112   - * @api public
113   - */
114   -
115   - Server : function(results, options) {
116   - var uri = options.uri || 'http://' + window.location.host + '/results'
117   - JSpec.post(uri, {
118   - stats: JSpec.stats,
119   - options: options,
120   - results: map(results.allSuites, function(suite) {
121   - if (suite.isExecutable())
122   - return {
123   - description: suite.description,
124   - specs: map(suite.specs, function(spec) {
125   - return {
126   - description: spec.description,
127   - message: !spec.passed() ? spec.failure().message : null,
128   - status: spec.requiresImplementation() ? 'pending' :
129   - spec.passed() ? 'pass' :
130   - 'fail',
131   - assertions: map(spec.assertions, function(assertion){
132   - return {
133   - passed: assertion.passed
134   - }
135   - })
136   - }
137   - })
138   - }
139   - })
140   - })
141   - if ('close' in main) main.close()
142   - },
143   -
144   - /**
145   - * Default reporter, outputting to the DOM.
146   - *
147   - * Options:
148   - * - reportToId id of element to output reports to, defaults to 'jspec'
149   - * - failuresOnly displays only suites with failing specs
150   - *
151   - * @api public
152   - */
153   -
154   - DOM : function(results, options) {
155   - var id = option('reportToId') || 'jspec',
156   - report = document.getElementById(id),
157   - failuresOnly = option('failuresOnly'),
158   - classes = results.stats.failures ? 'has-failures' : ''
159   - if (!report) throw 'JSpec requires the element #' + id + ' to output its reports'
160   -
161   - function bodyContents(body) {
162   - return JSpec.
163   - escape(JSpec.contentsOf(body)).
164   - replace(/^ */gm, function(a){ return (new Array(Math.round(a.length / 3))).join(' ') }).
165   - replace(/\r\n|\r|\n/gm, '<br/>')
166   - }
167   -
168   - report.innerHTML = '<div id="jspec-report" class="' + classes + '"><div class="heading"> \
169   - <span class="passes">Passes: <em>' + results.stats.passes + '</em></span> \
170   - <span class="failures">Failures: <em>' + results.stats.failures + '</em></span> \
171   - <span class="passes">Duration: <em>' + results.duration + '</em> ms</span> \
172   - </div><table class="suites">' + map(results.allSuites, function(suite) {
173   - var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran
174   - if (displaySuite && suite.isExecutable())
175   - return '<tr class="description"><td colspan="2">' + escape(suite.description) + '</td></tr>' +
176   - map(suite.specs, function(i, spec) {
177   - return '<tr class="' + (i % 2 ? 'odd' : 'even') + '">' +
178   - (spec.requiresImplementation() ?
179   - '<td class="requires-implementation" colspan="2">' + escape(spec.description) + '</td>' :
180   - (spec.passed() && !failuresOnly) ?
181   - '<td class="pass">' + escape(spec.description)+ '</td><td>' + spec.assertionsGraph() + '</td>' :
182   - !spec.passed() ?
183   - '<td class="fail">' + escape(spec.description) +
184   - map(spec.failures(), function(a){ return '<em>' + escape(a.message) + '</em>' }).join('') +
185   - '</td><td>' + spec.assertionsGraph() + '</td>' :
186   - '') +
187   - '<tr class="body"><td colspan="2"><pre>' + bodyContents(spec.body) + '</pre></td></tr>'
188   - }).join('') + '</tr>'
189   - }).join('') + '</table></div>'
190   - },
191   -
192   - /**
193   - * Terminal reporter.
194   - *
195   - * @api public
196   - */
197   -
198   - Terminal : function(results, options) {
199   - var failuresOnly = option('failuresOnly')
200   - print(color("\n Passes: ", 'bold') + color(results.stats.passes, 'green') +
201   - color(" Failures: ", 'bold') + color(results.stats.failures, 'red') +
202   - color(" Duration: ", 'bold') + color(results.duration, 'green') + " ms \n")
203   -
204   - function indent(string) {
205   - return string.replace(/^(.)/gm, ' $1')
206   - }
207   -
208   - each(results.allSuites, function(suite) {
209   - var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran
210   - if (displaySuite && suite.isExecutable()) {
211   - print(color(' ' + suite.description, 'bold'))
212   - each(suite.specs, function(spec){
213   - var assertionsGraph = inject(spec.assertions, '', function(graph, assertion){
214   - return graph + color('.', assertion.passed ? 'green' : 'red')
215   - })
216   - if (spec.requiresImplementation())
217   - print(color(' ' + spec.description, 'blue') + assertionsGraph)
218   - else if (spec.passed() && !failuresOnly)
219   - print(color(' ' + spec.description, 'green') + assertionsGraph)
220   - else if (!spec.passed())
221   - print(color(' ' + spec.description, 'red') + assertionsGraph +
222   - "\n" + indent(map(spec.failures(), function(a){ return a.message }).join("\n")) + "\n")
223   - })
224   - print("")
225   - }
226   - })
227   -
228   - quit(results.stats.failures)
229   - }
230   - },
231   -
232   - Assertion : function(matcher, actual, expected, negate) {
233   - extend(this, {
234   - message: '',
235   - passed: false,
236   - actual: actual,
237   - negate: negate,
238   - matcher: matcher,
239   - expected: expected,
240   -
241   - // Report assertion results
242   -
243   - report : function() {
244   - if (JSpec.assert)
245   - this.passed ? JSpec.stats.passes++ : JSpec.stats.failures++
246   - return this
247   - },
248   -
249   - // Run the assertion
250   -
251   - run : function() {
252   - // TODO: remove unshifting
253   - expected.unshift(actual)
254   - this.result = matcher.match.apply(this, expected)
255   - this.passed = negate ? !this.result : this.result
256   - if (!this.passed) this.message = matcher.message.call(this, actual, expected, negate, matcher.name)
257   - return this
258   - }
259   - })
260   - },
261   -
262   - ProxyAssertion : function(object, method, times, negate) {
263   - var self = this,
264   - old = object[method]
265   -
266   - // Proxy
267   -
268   - object[method] = function(){
269   - var args = toArray(arguments),
270   - result = old.apply(object, args)
271   - self.calls.push({ args : args, result : result })
272   - return result
273   - }
274   -
275   - // Times
276   -
277   - this.times = {
278   - once : 1,
279   - twice : 2
280   - }[times] || times || 1
281   -
282   - extend(this, {
283   - calls: [],
284   - message: '',
285   - defer: true,
286   - passed: false,
287   - negate: negate,
288   - object: object,
289   - method: method,
290   -
291   - // Proxy return value
292   -
293   - and_return : function(result) {
294   - this.expectedResult = result
295   - return this
296   - },
297   -
298   - // Proxy arguments passed
299   -
300   - with_args : function() {
301   - this.expectedArgs = toArray(arguments)
302   - return this
303   - },
304   -
305   - // Check if any calls have failing results
306   -
307   - anyResultsFail : function() {
308   - return any(this.calls, function(call){
309   - return self.expectedResult.an_instance_of ?
310   - call.result.constructor != self.expectedResult.an_instance_of:
311   - !equal(self.expectedResult, call.result)
312   - })
313   - },
314   -
315   - // Check if any calls have passing results
316   -
317   - anyResultsPass : function() {
318   - return any(this.calls, function(call){
319   - return self.expectedResult.an_instance_of ?
320   - call.result.constructor == self.expectedResult.an_instance_of:
321   - equal(self.expectedResult, call.result)
322   - })
323   - },
324   -
325   - // Return the passing result
326   -
327   - passingResult : function() {
328   - return this.anyResultsPass().result
329   - },
330   -
331   - // Return the failing result
332   -
333   - failingResult : function() {
334   - return this.anyResultsFail().result
335   - },
336   -
337   - // Check if any arguments fail
338   -
339   - anyArgsFail : function() {
340   - return any(this.calls, function(call){
341   - return any(self.expectedArgs, function(i, arg){
342   - if (arg == null) return call.args[i] == null
343   - return arg.an_instance_of ?
344   - call.args[i].constructor != arg.an_instance_of:
345   - !equal(arg, call.args[i])
346   -
347   - })
348   - })
349   - },
350   -
351   - // Check if any arguments pass
352   -
353   - anyArgsPass : function() {
354   - return any(this.calls, function(call){
355   - return any(self.expectedArgs, function(i, arg){
356   - return arg.an_instance_of ?
357   - call.args[i].constructor == arg.an_instance_of:
358   - equal(arg, call.args[i])
359   -
360   - })
361   - })
362   - },
363   -
364   - // Return the passing args
365   -
366   - passingArgs : function() {
367   - return this.anyArgsPass().args
368   - },
369   -