trxl 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/README +143 -0
- data/Rakefile +41 -0
- data/VERSION +1 -0
- data/lib/trxl.rb +5 -0
- data/lib/trxl/trxl.rb +585 -0
- data/lib/trxl/trxl_grammar.rb +8583 -0
- data/lib/trxl/trxl_grammar.treetop +1394 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/trxl/arithmetics_spec.rb +391 -0
- data/spec/trxl/arrays_spec.rb +163 -0
- data/spec/trxl/booleans_spec.rb +138 -0
- data/spec/trxl/builtins_spec.rb +268 -0
- data/spec/trxl/closures_spec.rb +244 -0
- data/spec/trxl/comments_spec.rb +35 -0
- data/spec/trxl/common_spec.rb +22 -0
- data/spec/trxl/conditionals_spec.rb +454 -0
- data/spec/trxl/constants_spec.rb +23 -0
- data/spec/trxl/environment_spec.rb +117 -0
- data/spec/trxl/hashes_spec.rb +62 -0
- data/spec/trxl/numbers_spec.rb +27 -0
- data/spec/trxl/ranges_spec.rb +81 -0
- data/spec/trxl/require_spec.rb +50 -0
- data/spec/trxl/stdlib_spec.rb +370 -0
- data/spec/trxl/strings_spec.rb +1 -0
- data/spec/trxl/variables_spec.rb +45 -0
- data/trxl.gemspec +90 -0
- metadata +119 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "The language" do
|
4
|
+
|
5
|
+
include Trxl::SpecHelper
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@parser = Trxl::Calculator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should evaluate the constant 'NULL' to nil" do
|
12
|
+
eval("NULL").should be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should evaluate the constant 'TRUE' to true" do
|
16
|
+
eval("TRUE").should be_true
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should evaluate the constant 'FALSE' to false" do
|
20
|
+
eval("FALSE").should be_false
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "A newly created environment" do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@env = Trxl::Environment.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be empty" do
|
10
|
+
@env.should be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have a depth of 1 (one)" do
|
14
|
+
@env.depth.should == 1
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "For storing variables" do
|
20
|
+
|
21
|
+
before :each do
|
22
|
+
@env = Trxl::Environment.new
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should allow to bind variables to any given value" do
|
26
|
+
@env[:a] = "foo"
|
27
|
+
@env[:a].should == "foo"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should allow to test if it's empty" do
|
31
|
+
@env.should be_empty
|
32
|
+
@env[:a] = "foo"
|
33
|
+
@env.should_not be_empty
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should allow to assign new values to already initialized variables" do
|
37
|
+
@env[:a] = "foo"
|
38
|
+
@env[:a].should == "foo"
|
39
|
+
@env[:a] = "bar"
|
40
|
+
@env[:a].should == "bar"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "For scoping variables" do
|
46
|
+
|
47
|
+
before :each do
|
48
|
+
@env = Trxl::Environment.new({
|
49
|
+
:a => "foo",
|
50
|
+
:b => "bar"
|
51
|
+
})
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should allow to enter a new scope" do
|
55
|
+
@env.enter_scope
|
56
|
+
@env.depth.should == 2
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should allow to pop any nested scope" do
|
60
|
+
@env.enter_scope
|
61
|
+
@env.exit_scope
|
62
|
+
@env.depth.should == 1
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should not allow to pop the toplevel scope" do
|
66
|
+
lambda { @env.exit_scope }.should raise_error
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should override any existing variable in a new scope" do
|
70
|
+
@env.enter_scope
|
71
|
+
@env[:a] = "bam"
|
72
|
+
@env[:a].should == "bam"
|
73
|
+
@env.exit_scope
|
74
|
+
@env[:a].should == "foo"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should allow to merge an existing environment into the current local one" do
|
78
|
+
other_env = { :c => "c", :d => "d" }
|
79
|
+
@env.merge!(other_env)
|
80
|
+
@env.local[:c].should == "c"
|
81
|
+
@env.local[:a].should == "foo"
|
82
|
+
@env.local[:b].should == "bar"
|
83
|
+
@env[:c].should == "c"
|
84
|
+
@env[:a].should == "foo"
|
85
|
+
@env[:b].should == "bar"
|
86
|
+
|
87
|
+
other_env = { :a => "a", :c => "c" }
|
88
|
+
@env.merge!(other_env)
|
89
|
+
@env.local[:a].should == "a"
|
90
|
+
@env.local[:b].should == "bar"
|
91
|
+
@env.local[:c].should == "c"
|
92
|
+
@env[:a].should == "a"
|
93
|
+
@env[:b].should == "bar"
|
94
|
+
@env[:c].should == "c"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should allow to return a new merged environment leaving the original intact" do
|
98
|
+
other_env = { :c => "c", :d => "d" }
|
99
|
+
env = @env.merge(other_env)
|
100
|
+
env.local[:c].should == "c"
|
101
|
+
env.local[:a].should == "foo"
|
102
|
+
env.local[:b].should == "bar"
|
103
|
+
env[:c].should == "c"
|
104
|
+
env[:a].should == "foo"
|
105
|
+
env[:b].should == "bar"
|
106
|
+
|
107
|
+
other_env = { :a => "a", :c => "c" }
|
108
|
+
env = @env.merge(other_env)
|
109
|
+
env.local[:a].should == "a"
|
110
|
+
env.local[:b].should == "bar"
|
111
|
+
env.local[:c].should == "c"
|
112
|
+
env[:a].should == "a"
|
113
|
+
env[:b].should == "bar"
|
114
|
+
env[:c].should == "c"
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "For working with Hashes, the Trxl::Calculator" do
|
4
|
+
|
5
|
+
include Trxl::SpecHelper
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@parser = Trxl::Calculator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
it "should evaluate hash literal expressions" do
|
13
|
+
eval("{}").should == {}
|
14
|
+
eval("{ 1 => 2 }").should == { 1 => 2 }
|
15
|
+
eval("{ 1 => 2, 3 => 4 }").should == { 1 => 2, 3 => 4 }
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should allow hash variable definitions" do
|
19
|
+
eval("a = {}").should == {}
|
20
|
+
eval("a = {}; a;").should == {}
|
21
|
+
eval("a = { 1 => 2 }").should == { 1 => 2 }
|
22
|
+
eval("a = { 1 => 2 }; a;").should == { 1 => 2 }
|
23
|
+
eval("a = { 1 => 2, 3 => 4 }; a;").should == { 1 => 2, 3 => 4 }
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should allow nested hash variable definitions" do
|
27
|
+
eval("a = { 1 => { 2 => 3 } }").should == { 1 => { 2 => 3 } }
|
28
|
+
eval("a = { 1 => { 2 => 3 }, 4 => 5 }").should == { 1 => { 2 => 3 }, 4 => 5 }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should allow arbitrary expressions in hash literal" do
|
32
|
+
eval("x = 1; foo = fun(x) {x}; h = { fun(){2}() => foo(3) }").should == { 2 => 3 }
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be able to index hashes by their keys" do
|
36
|
+
eval("h = { 1 => 2 }; h[0]").should == nil
|
37
|
+
eval("h = { 1 => 2 }; h[1]").should == 2
|
38
|
+
eval("h = { 1 => 2 }; h[2]").should == nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should recognize primary expressions as hash offset specifiers" do
|
42
|
+
eval("h = { 1 => 2 }; h[fun(x){x}(0)]").should == nil
|
43
|
+
eval("h = { 1 => 2 }; h[fun(x){x}(1)]").should == 2
|
44
|
+
eval("h = { 1 => 2 }; h[fun(x){x}(2)]").should == nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should resolve exact matching expressions" do
|
48
|
+
env = { :foo => { :a => "bar", :b => "bar", :c => "baz" } }
|
49
|
+
eval("foo[='bar']", env).should == [ [:a, "bar"], [:b, "bar"] ]
|
50
|
+
eval("foo[='baz']", env).should == [ [:c, "baz"] ]
|
51
|
+
eval("foo[='bam']", env).should == []
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should resolve exact matching expressions followed by offset access expressions" do
|
55
|
+
env = { :foo => { :a => "bar", :b => "bar", :c => "baz" } }
|
56
|
+
eval("foo[='bar'][0]", env).should == [ :a, "bar" ]
|
57
|
+
eval("foo[='bar'][1]", env).should == [ :b, "bar" ]
|
58
|
+
eval("foo[='baz'][0]", env).should == [ :c, "baz" ]
|
59
|
+
eval("foo[='bam'][0]", env).should be_nil
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "The calculation grammar" do
|
4
|
+
|
5
|
+
include Trxl::SpecHelper
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@parser = Trxl::Calculator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should evaluate a given positive integer number to itself" do
|
12
|
+
eval("7").should == 7
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should evaluate a given negative integer number to itself" do
|
16
|
+
eval("-7").should == -7
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should evaluate a given positive real number to itself" do
|
20
|
+
eval("7.0").should == 7.0
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should evaluate a given negative real number to itself" do
|
24
|
+
eval("-7.0").should == -7.0
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "When working with Ranges, the Trxl::Calculator" do
|
4
|
+
|
5
|
+
include Trxl::SpecHelper
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@parser = Trxl::Calculator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return arrays for range literal expressions" do
|
12
|
+
eval("0..0").should == [ 0 ]
|
13
|
+
eval("0..-1").should == [ ]
|
14
|
+
eval("0...0").should == [ ]
|
15
|
+
eval("0...-1").should == [ ]
|
16
|
+
|
17
|
+
eval("1..5").should == [ 1, 2, 3, 4, 5 ]
|
18
|
+
eval("1 .. 5").should == [ 1, 2, 3, 4, 5 ]
|
19
|
+
eval("a = 1; b = 5; a..b").should == [ 1, 2, 3, 4, 5 ]
|
20
|
+
eval("1...5").should == [ 1, 2, 3, 4 ]
|
21
|
+
eval("1 ... 5").should == [ 1, 2, 3, 4 ]
|
22
|
+
eval("a = 1; b = 5; a...b").should == [ 1, 2, 3, 4 ]
|
23
|
+
|
24
|
+
eval("\"a\"..\"a\"").should == [ "a" ]
|
25
|
+
eval("\"a\"..\"c\"").should == [ "a", "b", "c" ]
|
26
|
+
eval("\"a\" .. \"c\"").should == [ "a", "b", "c" ]
|
27
|
+
eval("\"a\"...\"c\"").should == [ "a", "b" ]
|
28
|
+
eval("\"a\" ... \"c\"").should == [ "a", "b" ]
|
29
|
+
|
30
|
+
eval("'a'..'a'").should == [ "a" ]
|
31
|
+
eval("'a'..'c'").should == [ "a", "b", "c" ]
|
32
|
+
eval("'a' .. 'c'").should == [ "a", "b", "c" ]
|
33
|
+
eval("'a'...'c'").should == [ "a", "b" ]
|
34
|
+
eval("'a' ... 'c'").should == [ "a", "b" ]
|
35
|
+
|
36
|
+
eval("'aa'..'aa'").should == [ "aa" ]
|
37
|
+
eval("'aa'..'ac'").should == [ "aa", "ab", "ac" ]
|
38
|
+
eval("'aa'...'ac'").should == [ "aa", "ab" ]
|
39
|
+
|
40
|
+
eval("1..5 == [ 1, 2, 3, 4, 5 ]").should be_true
|
41
|
+
eval("1...5 == [ 1, 2, 3, 4 ]").should be_true
|
42
|
+
|
43
|
+
eval("SIZE(1..5)").should == 5
|
44
|
+
|
45
|
+
eval("a..b == [ 1, 2 ]", { :a => 1, :b => 2 }).should be_true
|
46
|
+
eval("a..c", { :a => 1, :b => nil, :c => 2 }).should == [ 1, 2]
|
47
|
+
|
48
|
+
lambda { eval("a..b", { :a => nil, :b => nil }) }.should raise_error
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should store ranges as arrays" do
|
53
|
+
eval("a = 1..5; a;").should == [ 1, 2, 3, 4, 5 ]
|
54
|
+
eval("a = 1 .. 5; a;").should == [ 1, 2, 3, 4, 5 ]
|
55
|
+
eval("a = 1; b = 5; c = a..b; c;").should == [ 1, 2, 3, 4, 5 ]
|
56
|
+
eval("a = 1...5; a;").should == [ 1, 2, 3, 4 ]
|
57
|
+
eval("a = 1 ... 5; a;").should == [ 1, 2, 3, 4 ]
|
58
|
+
eval("a = 1; b = 5; c = a...b; c;").should == [ 1, 2, 3, 4 ]
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "When working with Strings, the Trxl::Calculator" do
|
64
|
+
|
65
|
+
include Trxl::SpecHelper
|
66
|
+
|
67
|
+
before(:each) do
|
68
|
+
@parser = Trxl::Calculator.new
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should evaluate string literals to strings using double quotes (\"\")" do
|
72
|
+
eval("\"Test String\"").should == "Test String"
|
73
|
+
eval("s = \"Test String\"; s;").should == "Test String"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should evaluate string literals to strings using single quotes ('')" do
|
77
|
+
eval("'Test String'").should == "Test String"
|
78
|
+
eval("s = 'Test String'; s;").should == "Test String"
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "For defining Trxl::StdLib, the Trxl::Calculator" do
|
4
|
+
|
5
|
+
include Trxl::SpecHelper
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@parser = Trxl::Calculator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be able to require trxl code snippets and merge them into the current env" do
|
12
|
+
program = "require 'stdlib'"
|
13
|
+
env_after_require = eval(program)
|
14
|
+
env_after_require.should have_key(:foreach_in)
|
15
|
+
env_after_require.should have_key(:_foreach_in_)
|
16
|
+
env_after_require.should have_key(:inject)
|
17
|
+
env_after_require.should have_key(:_inject_)
|
18
|
+
env_after_require.should have_key(:map)
|
19
|
+
env_after_require.should have_key(:ratio)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be able to require scoped trxl code snippets and merge them into the current env" do
|
23
|
+
program = "require 'stdlib/foreach_in'"
|
24
|
+
env_after_require = eval(program)
|
25
|
+
env_after_require.should have_key(:foreach_in)
|
26
|
+
|
27
|
+
program = "require 'stdlib/inject'"
|
28
|
+
env_after_require = eval(program)
|
29
|
+
env_after_require.should have_key(:inject)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should be able to require scoped trxl code snippets and merge them into the current env" do
|
33
|
+
program = "require 'stdlib/foreach_in'"
|
34
|
+
env_after_require = eval(program)
|
35
|
+
env_after_require.should have_key(:foreach_in)
|
36
|
+
|
37
|
+
program = "require 'stdlib/inject'"
|
38
|
+
env_after_require = eval(program)
|
39
|
+
env_after_require.should have_key(:inject)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should ignore a require statement if the library has already been loaded" do
|
43
|
+
program = "require 'stdlib/inject'"
|
44
|
+
program = "require 'stdlib/map'"
|
45
|
+
env_after_require = eval(program)
|
46
|
+
env_after_require.should have_key(:inject)
|
47
|
+
env_after_require.should have_key(:map)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,370 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "The Trxl::StdLib" do
|
4
|
+
|
5
|
+
include Trxl::SpecHelper
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@parser = Trxl::Calculator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be able to parse the whole Trxl::StdLib code" do
|
12
|
+
lambda { parse(Trxl::Calculator.stdlib) }.should_not raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should define a foreach function with read access to the outer env" do
|
16
|
+
program = <<-PROGRAM
|
17
|
+
require 'stdlib/foreach_in';
|
18
|
+
foreach_in(1..3, fun(c) { c });
|
19
|
+
PROGRAM
|
20
|
+
eval(program).should == 3
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should define a foreach function with write access to the outer env" do
|
24
|
+
program = <<-PROGRAM
|
25
|
+
require 'stdlib/foreach_in';
|
26
|
+
sum = 0;
|
27
|
+
a = 1..10;
|
28
|
+
foreach_in(a, fun(e) {
|
29
|
+
sum = sum + e
|
30
|
+
});
|
31
|
+
sum;
|
32
|
+
PROGRAM
|
33
|
+
eval(program).should == 55
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should define an inject function with read access to the outer env" do
|
37
|
+
program = <<-PROGRAM
|
38
|
+
require 'stdlib/inject';
|
39
|
+
inject(0, 1..6, fun(memo, val) { memo + val });
|
40
|
+
PROGRAM
|
41
|
+
eval(program).should == 21
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should define an inject function with write access to the outer env" do
|
45
|
+
program = <<-PROGRAM
|
46
|
+
require 'stdlib/inject';
|
47
|
+
ratio = fun(values) {
|
48
|
+
base = 0;
|
49
|
+
positives = inject(0, values, fun(memo, val) {
|
50
|
+
if(ENV[val] == "yes")
|
51
|
+
base = base + 1;
|
52
|
+
memo + 1
|
53
|
+
elsif(ENV[val] == "no")
|
54
|
+
base = base + 1;
|
55
|
+
memo
|
56
|
+
else
|
57
|
+
memo
|
58
|
+
end
|
59
|
+
});
|
60
|
+
if(base > 0)
|
61
|
+
ROUND((ROUND(positives, 10) / base) * 100, 2)
|
62
|
+
else
|
63
|
+
0
|
64
|
+
end
|
65
|
+
};
|
66
|
+
ratio('a'..'c');
|
67
|
+
PROGRAM
|
68
|
+
eval(program, { :a => 'yes', :b => 'no', :c => 'n/a' }).should == 50
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should define a map function with read access to the outer env" do
|
72
|
+
program = <<-PROGRAM
|
73
|
+
require 'stdlib/map';
|
74
|
+
map([[1,2],[3,4],[5,6]], fun(a) { a[1]; });
|
75
|
+
PROGRAM
|
76
|
+
eval(program).should == [2,4,6]
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should define a map function with write access to the outer env" do
|
80
|
+
program = <<-PROGRAM
|
81
|
+
require 'stdlib/map';
|
82
|
+
a = [];
|
83
|
+
map([[1,2],[3,4],[5,6]], fun(x) { a << x[1]; });
|
84
|
+
a;
|
85
|
+
PROGRAM
|
86
|
+
eval(program).should == [2,4,6]
|
87
|
+
|
88
|
+
program = <<-PROGRAM
|
89
|
+
require 'stdlib/map';
|
90
|
+
sum = 0;
|
91
|
+
map([[1,2],[3,4],[5,6]], fun(x) { sum = sum + x[1]; });
|
92
|
+
sum;
|
93
|
+
PROGRAM
|
94
|
+
eval(program).should == 12
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should define a 'select' function for any enumerable collection" do
|
98
|
+
program = <<-PROGRAM
|
99
|
+
require 'stdlib/select';
|
100
|
+
select([ 1, 2, 3, 4 ], fun(e) { e % 2 == 0 });
|
101
|
+
PROGRAM
|
102
|
+
eval(program).should == [ 2, 4 ]
|
103
|
+
|
104
|
+
program = <<-PROGRAM
|
105
|
+
require 'stdlib/select';
|
106
|
+
select(1..4, fun(e) { e % 2 == 0 });
|
107
|
+
PROGRAM
|
108
|
+
eval(program).should == [ 2, 4 ]
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should define a 'reject' function for any enumerable collection" do
|
112
|
+
program = <<-PROGRAM
|
113
|
+
require 'stdlib/reject';
|
114
|
+
reject([ 1, 2, 3, 4 ], fun(e) { e % 2 == 0 });
|
115
|
+
PROGRAM
|
116
|
+
eval(program).should == [ 1, 3 ]
|
117
|
+
|
118
|
+
program = <<-PROGRAM
|
119
|
+
require 'stdlib/reject';
|
120
|
+
reject(1..4, fun(e) { e % 2 == 0 });
|
121
|
+
PROGRAM
|
122
|
+
eval(program).should == [ 1, 3 ]
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should define a 'ratio' function for any enumerable collection" do
|
126
|
+
env = {
|
127
|
+
:a => "Ja",
|
128
|
+
:b => "Ja",
|
129
|
+
:c => "Ja",
|
130
|
+
:d => "Ja"
|
131
|
+
}
|
132
|
+
req_stmt = "require 'stdlib/ratio';"
|
133
|
+
eval("#{req_stmt} ratio('a'..'d', 'Ja', 'keine Angabe');", env).should == 100
|
134
|
+
|
135
|
+
env = {
|
136
|
+
:a => "Ja",
|
137
|
+
:b => "Ja",
|
138
|
+
:c => "Nein",
|
139
|
+
:d => "Nein"
|
140
|
+
}
|
141
|
+
req_stmt = "require 'stdlib/ratio';"
|
142
|
+
eval("#{req_stmt} ratio('a'..'d', 'Ja', 'keine Angabe');", env).should == 50
|
143
|
+
|
144
|
+
env = {
|
145
|
+
:a => "Nein",
|
146
|
+
:b => "Nein",
|
147
|
+
:c => "Nein",
|
148
|
+
:d => "Nein"
|
149
|
+
}
|
150
|
+
req_stmt = "require 'stdlib/ratio';"
|
151
|
+
eval("#{req_stmt} ratio('a'..'d', 'Ja', 'keine Angabe');", env).should == 0
|
152
|
+
|
153
|
+
env = {
|
154
|
+
:a => "Ja",
|
155
|
+
:b => "Nein",
|
156
|
+
:c => "Nein",
|
157
|
+
:d => "Nein",
|
158
|
+
:e => "keine Angabe"
|
159
|
+
}
|
160
|
+
req_stmt = "require 'stdlib/ratio';"
|
161
|
+
eval("#{req_stmt} ratio('a'..'e', 'Ja', 'keine Angabe');", env).should == 25
|
162
|
+
|
163
|
+
env = {
|
164
|
+
:a => "keine Angabe"
|
165
|
+
}
|
166
|
+
req_stmt = "require 'stdlib/ratio';"
|
167
|
+
eval("#{req_stmt} ratio(['a'], 'Ja', 'keine Angabe');", env).should be_nil
|
168
|
+
|
169
|
+
env = {
|
170
|
+
:a => "keine Angabe",
|
171
|
+
:b => "keine Angabe",
|
172
|
+
:c => "keine Angabe"
|
173
|
+
}
|
174
|
+
req_stmt = "require 'stdlib/ratio';"
|
175
|
+
eval("#{req_stmt} ratio('a'..'c', 'Ja', 'keine Angabe');", env).should be_nil
|
176
|
+
|
177
|
+
env = {
|
178
|
+
:a => "Ja",
|
179
|
+
:b => "keine Angabe"
|
180
|
+
}
|
181
|
+
req_stmt = "require 'stdlib/ratio';"
|
182
|
+
eval("#{req_stmt} ratio('a'..'b', 'Ja', 'keine Angabe');", env).should == 100
|
183
|
+
|
184
|
+
env = {
|
185
|
+
:a => "Nein",
|
186
|
+
:b => "keine Angabe"
|
187
|
+
}
|
188
|
+
req_stmt = "require 'stdlib/ratio';"
|
189
|
+
eval("#{req_stmt} ratio('a'..'b', 'Ja', 'keine Angabe');", env).should == 0
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should define a 'in_groups_of' function for any enumerable collection" do
|
193
|
+
program = <<-PROGRAM
|
194
|
+
require 'stdlib/in_groups_of';
|
195
|
+
in_groups_of(2, [ 1, 2, 3, 4 ], fun(group) { group });
|
196
|
+
PROGRAM
|
197
|
+
eval(program).should == [ [ 1, 2 ], [ 3, 4 ] ]
|
198
|
+
|
199
|
+
program = <<-PROGRAM
|
200
|
+
require 'stdlib/in_groups_of';
|
201
|
+
in_groups_of(2, 1..4, fun(group) { group });
|
202
|
+
PROGRAM
|
203
|
+
eval(program).should == [ [ 1, 2 ], [ 3, 4 ] ]
|
204
|
+
|
205
|
+
program = <<-PROGRAM
|
206
|
+
require 'stdlib/inject';
|
207
|
+
require 'stdlib/in_groups_of';
|
208
|
+
in_groups_of(2, 1..4, fun(group) { SUM(group) });
|
209
|
+
PROGRAM
|
210
|
+
eval(program).should == [ 3, 7 ]
|
211
|
+
|
212
|
+
program = <<-PROGRAM
|
213
|
+
require 'stdlib/in_groups_of';
|
214
|
+
in_groups_of(2, 'a'..'d', fun(group) { group });
|
215
|
+
PROGRAM
|
216
|
+
eval(program).should == [ [ 'a', 'b' ], [ 'c', 'd' ] ]
|
217
|
+
|
218
|
+
env = Trxl::Environment.new({
|
219
|
+
:a => {
|
220
|
+
1 => "Building 1",
|
221
|
+
2 => "Building 2",
|
222
|
+
3 => "Building 3"
|
223
|
+
},
|
224
|
+
:b => {
|
225
|
+
1 => "Feuerwehrgebäude",
|
226
|
+
2 => "Schulgebäude",
|
227
|
+
3 => "Wohngebäude"
|
228
|
+
},
|
229
|
+
:c => { 1 => 100, 2 => 200, 3 => 300 },
|
230
|
+
:d => { 1 => 100, 2 => 200, 3 => 300 },
|
231
|
+
:e => { 1 => 100, 2 => 200, 3 => 300 },
|
232
|
+
:f => { 1 => 100, 2 => 200, 3 => 300 },
|
233
|
+
:g => { 1 => 100, 2 => 200, 3 => 300 },
|
234
|
+
:h => { 1 => 100, 2 => 200, 3 => 300 },
|
235
|
+
:i => { 1 => 100, 2 => 200, 3 => 300 },
|
236
|
+
:j => { 1 => 100, 2 => 200, 3 => 300 },
|
237
|
+
:k => { 1 => 100, 2 => 200, 3 => 300 },
|
238
|
+
:l => { 1 => 100, 2 => 200, 3 => 300 },
|
239
|
+
:m => { 1 => 100, 2 => 200, 3 => 300 },
|
240
|
+
:n => { 1 => 100, 2 => 200, 3 => 300 },
|
241
|
+
:o => { 1 => 100, 2 => 200, 3 => 300 },
|
242
|
+
:p => { 1 => 100, 2 => 200, 3 => 300 },
|
243
|
+
:q => { 1 => 100, 2 => 200, 3 => 300 },
|
244
|
+
:r => { 1 => 100, 2 => 200, 3 => 300 },
|
245
|
+
:s => { 1 => 100, 2 => 200, 3 => 300 },
|
246
|
+
:t => { 1 => 100, 2 => 200, 3 => 300 },
|
247
|
+
:u => {
|
248
|
+
1 => [ 15, 15, 15 ],
|
249
|
+
1 => [ 20, 20, 20 ],
|
250
|
+
1 => [ 30, 30, 30 ]
|
251
|
+
}
|
252
|
+
})
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should allow recursive functions as accumulator in 'in_groups_of' function calls" do
|
256
|
+
program = <<-PROGRAM
|
257
|
+
require 'stdlib/inject';
|
258
|
+
require 'stdlib/in_groups_of';
|
259
|
+
in_groups_of(2, 1..4, fun(group) {
|
260
|
+
inject(0, group, fun(sum, e) {
|
261
|
+
sum + e
|
262
|
+
});
|
263
|
+
});
|
264
|
+
PROGRAM
|
265
|
+
eval(program).should == [ 3, 7 ]
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should define a 'sum_of_type' function" do
|
269
|
+
env = {
|
270
|
+
:types => {
|
271
|
+
1 => "Feuerwehrgebäude",
|
272
|
+
2 => "Schulgebäude",
|
273
|
+
3 => "Sonstige",
|
274
|
+
},
|
275
|
+
:values => {
|
276
|
+
1 => [ 100, 100, 100 ],
|
277
|
+
2 => [ 200, 200, 200 ],
|
278
|
+
3 => [ 300, 300, 300 ]
|
279
|
+
}
|
280
|
+
}
|
281
|
+
req_stmt = "require 'stdlib/sum_of_type';"
|
282
|
+
eval("#{req_stmt} sum_of_type('Feuerwehrgebäude', types, values);", env).should == 300
|
283
|
+
eval("#{req_stmt} sum_of_type('Schulgebäude', types, values);", env).should == 600
|
284
|
+
eval("#{req_stmt} sum_of_type('Sonstige', types, values);", env).should == 900
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should define a 'avg_sum_of_type' function" do
|
288
|
+
env = {
|
289
|
+
:types => {
|
290
|
+
1 => "Feuerwehrgebäude",
|
291
|
+
2 => "Schulgebäude",
|
292
|
+
3 => "Sonstige",
|
293
|
+
},
|
294
|
+
:values => {
|
295
|
+
1 => [ 100, 100, 100 ],
|
296
|
+
2 => [ 200, 200, 200 ],
|
297
|
+
3 => [ 300, 300, 300 ]
|
298
|
+
}
|
299
|
+
}
|
300
|
+
req_stmt = "require 'stdlib/avg_sum_of_type';"
|
301
|
+
eval("#{req_stmt} avg_sum_of_type('Feuerwehrgebäude', types, values);", env).should == 100
|
302
|
+
eval("#{req_stmt} avg_sum_of_type('Schulgebäude', types, values);", env).should == 200
|
303
|
+
eval("#{req_stmt} avg_sum_of_type('Sonstige', types, values);", env).should == 300
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should define a 'total_range_sum_of_type' function" do
|
307
|
+
env = {
|
308
|
+
:types => {
|
309
|
+
1 => "Feuerwehrgebäude",
|
310
|
+
2 => "Schulgebäude",
|
311
|
+
3 => "Sonstige",
|
312
|
+
},
|
313
|
+
:a => {
|
314
|
+
1 => [ 100, 100, 100 ],
|
315
|
+
2 => [ 200, 200, 200 ],
|
316
|
+
3 => [ 300, 300, 300 ]
|
317
|
+
},
|
318
|
+
:b => {
|
319
|
+
1 => [ 100, 100, 100 ],
|
320
|
+
2 => [ 200, 200, 200 ],
|
321
|
+
3 => [ 300, 300, 300 ]
|
322
|
+
}
|
323
|
+
}
|
324
|
+
req_stmt = "require 'stdlib/total_range_sum_of_type';"
|
325
|
+
eval("#{req_stmt} total_range_sum_of_type('Feuerwehrgebäude', types, 'a'..'b');", env).should == 600
|
326
|
+
eval("#{req_stmt} total_range_sum_of_type('Schulgebäude', types, 'a'..'b');", env).should == 1200
|
327
|
+
eval("#{req_stmt} total_range_sum_of_type('Sonstige', types, 'a'..'b');", env).should == 1800
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should define a 'avg_range_sum_of_type' function" do
|
331
|
+
env = {
|
332
|
+
:types => {
|
333
|
+
1 => "Feuerwehrgebäude",
|
334
|
+
2 => "Schulgebäude",
|
335
|
+
3 => "Sonstige",
|
336
|
+
},
|
337
|
+
:a => {
|
338
|
+
1 => [ 100, 100, 100 ],
|
339
|
+
2 => [ 200, 200, 200 ],
|
340
|
+
3 => [ 300, 300, 300 ]
|
341
|
+
},
|
342
|
+
:b => {
|
343
|
+
1 => [ 100, 100, 100 ],
|
344
|
+
2 => [ 200, 200, 200 ],
|
345
|
+
3 => [ 300, 300, 300 ]
|
346
|
+
}
|
347
|
+
}
|
348
|
+
req_stmt = "require 'stdlib/avg_range_sum_of_type';"
|
349
|
+
eval("#{req_stmt} avg_range_sum_of_type('Feuerwehrgebäude', types, 'a'..'b');", env).should == 200
|
350
|
+
eval("#{req_stmt} avg_range_sum_of_type('Schulgebäude', types, 'a'..'b');", env).should == 400
|
351
|
+
eval("#{req_stmt} avg_range_sum_of_type('Sonstige', types, 'a'..'b');", env).should == 600
|
352
|
+
end
|
353
|
+
|
354
|
+
it "should define a 'year_from_date' function" do
|
355
|
+
req_stmt = "require 'stdlib/year_from_date';"
|
356
|
+
eval("#{req_stmt} year_from_date('01/1999');").should == 1999
|
357
|
+
eval("#{req_stmt} year_from_date('12/1999');").should == 1999
|
358
|
+
eval("#{req_stmt} year_from_date('12/2008');").should == 2008
|
359
|
+
eval("#{req_stmt} year_from_date('12/2008');").should == 2008
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should define a 'month_from_date' function" do
|
363
|
+
req_stmt = "require 'stdlib/month_from_date';"
|
364
|
+
eval("#{req_stmt} month_from_date('01/1999');").should == 1
|
365
|
+
eval("#{req_stmt} month_from_date('12/1999');").should == 12
|
366
|
+
eval("#{req_stmt} month_from_date('1/2008');").should == 1
|
367
|
+
eval("#{req_stmt} month_from_date('12/2008');").should == 12
|
368
|
+
end
|
369
|
+
|
370
|
+
end
|