qrb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +58 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +11 -0
- data/README.md +118 -0
- data/Rakefile +11 -0
- data/lib/qrb/Q/default.q +29 -0
- data/lib/qrb/data_type.rb +23 -0
- data/lib/qrb/errors.rb +23 -0
- data/lib/qrb/support/attribute.rb +53 -0
- data/lib/qrb/support/collection_type.rb +25 -0
- data/lib/qrb/support/dress_helper.rb +68 -0
- data/lib/qrb/support/heading.rb +57 -0
- data/lib/qrb/support/type_factory.rb +178 -0
- data/lib/qrb/support.rb +5 -0
- data/lib/qrb/syntax/ad_type.rb +25 -0
- data/lib/qrb/syntax/attribute.rb +11 -0
- data/lib/qrb/syntax/builtin_type.rb +13 -0
- data/lib/qrb/syntax/constraint_def.rb +11 -0
- data/lib/qrb/syntax/constraints.rb +18 -0
- data/lib/qrb/syntax/contract.rb +25 -0
- data/lib/qrb/syntax/definitions.rb +14 -0
- data/lib/qrb/syntax/expression.rb +12 -0
- data/lib/qrb/syntax/heading.rb +15 -0
- data/lib/qrb/syntax/lambda_expr.rb +11 -0
- data/lib/qrb/syntax/named_constraint.rb +11 -0
- data/lib/qrb/syntax/q.citrus +195 -0
- data/lib/qrb/syntax/relation_type.rb +11 -0
- data/lib/qrb/syntax/seq_type.rb +12 -0
- data/lib/qrb/syntax/set_type.rb +12 -0
- data/lib/qrb/syntax/sub_type.rb +13 -0
- data/lib/qrb/syntax/support.rb +13 -0
- data/lib/qrb/syntax/system.rb +15 -0
- data/lib/qrb/syntax/tuple_type.rb +11 -0
- data/lib/qrb/syntax/type_def.rb +14 -0
- data/lib/qrb/syntax/type_ref.rb +13 -0
- data/lib/qrb/syntax/union_type.rb +12 -0
- data/lib/qrb/syntax/unnamed_constraint.rb +11 -0
- data/lib/qrb/syntax.rb +42 -0
- data/lib/qrb/system.rb +63 -0
- data/lib/qrb/type/ad_type.rb +111 -0
- data/lib/qrb/type/builtin_type.rb +56 -0
- data/lib/qrb/type/relation_type.rb +81 -0
- data/lib/qrb/type/seq_type.rb +51 -0
- data/lib/qrb/type/set_type.rb +52 -0
- data/lib/qrb/type/sub_type.rb +94 -0
- data/lib/qrb/type/tuple_type.rb +99 -0
- data/lib/qrb/type/union_type.rb +78 -0
- data/lib/qrb/type.rb +63 -0
- data/lib/qrb/version.rb +14 -0
- data/lib/qrb.rb +63 -0
- data/qrb.gemspec +186 -0
- data/spec/acceptance/Q/test_default.rb +96 -0
- data/spec/acceptance/Q/test_parsing.rb +15 -0
- data/spec/acceptance/ad_type/test_in_q.rb +82 -0
- data/spec/acceptance/ad_type/test_in_ruby.rb +60 -0
- data/spec/spec_helper.rb +68 -0
- data/spec/unit/attribute/test_equality.rb +26 -0
- data/spec/unit/attribute/test_fetch_on.rb +50 -0
- data/spec/unit/attribute/test_initialize.rb +13 -0
- data/spec/unit/attribute/test_to_name.rb +10 -0
- data/spec/unit/heading/test_each.rb +28 -0
- data/spec/unit/heading/test_equality.rb +28 -0
- data/spec/unit/heading/test_initialize.rb +36 -0
- data/spec/unit/heading/test_size.rb +30 -0
- data/spec/unit/heading/test_to_name.rb +32 -0
- data/spec/unit/qrb/test_parse.rb +18 -0
- data/spec/unit/syntax/nodes/test_ad_type.rb +94 -0
- data/spec/unit/syntax/nodes/test_attribute.rb +25 -0
- data/spec/unit/syntax/nodes/test_builtin_type.rb +32 -0
- data/spec/unit/syntax/nodes/test_comment.rb +26 -0
- data/spec/unit/syntax/nodes/test_constraint_def.rb +27 -0
- data/spec/unit/syntax/nodes/test_constraints.rb +51 -0
- data/spec/unit/syntax/nodes/test_contract.rb +62 -0
- data/spec/unit/syntax/nodes/test_expression.rb +43 -0
- data/spec/unit/syntax/nodes/test_heading.rb +41 -0
- data/spec/unit/syntax/nodes/test_named_constraint.rb +31 -0
- data/spec/unit/syntax/nodes/test_relation_type.rb +41 -0
- data/spec/unit/syntax/nodes/test_seq_type.rb +24 -0
- data/spec/unit/syntax/nodes/test_set_type.rb +24 -0
- data/spec/unit/syntax/nodes/test_spacing.rb +25 -0
- data/spec/unit/syntax/nodes/test_sub_type.rb +52 -0
- data/spec/unit/syntax/nodes/test_tuple_type.rb +41 -0
- data/spec/unit/syntax/nodes/test_union_type.rb +23 -0
- data/spec/unit/syntax/nodes/test_unnamed_constraint.rb +31 -0
- data/spec/unit/syntax/test_compile_type.rb +22 -0
- data/spec/unit/system/test_add_type.rb +47 -0
- data/spec/unit/system/test_dsl.rb +30 -0
- data/spec/unit/system/test_dup.rb +30 -0
- data/spec/unit/system/test_fetch.rb +42 -0
- data/spec/unit/system/test_get_type.rb +30 -0
- data/spec/unit/system/test_initialize.rb +10 -0
- data/spec/unit/test_qrb.rb +15 -0
- data/spec/unit/type/ad_type/test_default_name.rb +15 -0
- data/spec/unit/type/ad_type/test_dress.rb +55 -0
- data/spec/unit/type/ad_type/test_include.rb +22 -0
- data/spec/unit/type/ad_type/test_initialize.rb +40 -0
- data/spec/unit/type/ad_type/test_name.rb +20 -0
- data/spec/unit/type/builtin_type/test_default_name.rb +12 -0
- data/spec/unit/type/builtin_type/test_dress.rb +33 -0
- data/spec/unit/type/builtin_type/test_equality.rb +26 -0
- data/spec/unit/type/builtin_type/test_include.rb +22 -0
- data/spec/unit/type/builtin_type/test_initialize.rb +12 -0
- data/spec/unit/type/builtin_type/test_name.rb +24 -0
- data/spec/unit/type/relation_type/test_default_name.rb +16 -0
- data/spec/unit/type/relation_type/test_dress.rb +164 -0
- data/spec/unit/type/relation_type/test_equality.rb +32 -0
- data/spec/unit/type/relation_type/test_include.rb +46 -0
- data/spec/unit/type/relation_type/test_initialize.rb +26 -0
- data/spec/unit/type/relation_type/test_name.rb +24 -0
- data/spec/unit/type/seq_type/test_default_name.rb +14 -0
- data/spec/unit/type/seq_type/test_dress.rb +49 -0
- data/spec/unit/type/seq_type/test_equality.rb +26 -0
- data/spec/unit/type/seq_type/test_include.rb +43 -0
- data/spec/unit/type/seq_type/test_initialize.rb +28 -0
- data/spec/unit/type/seq_type/test_name.rb +24 -0
- data/spec/unit/type/set_type/test_default_name.rb +14 -0
- data/spec/unit/type/set_type/test_dress.rb +66 -0
- data/spec/unit/type/set_type/test_equality.rb +26 -0
- data/spec/unit/type/set_type/test_include.rb +43 -0
- data/spec/unit/type/set_type/test_initialize.rb +28 -0
- data/spec/unit/type/set_type/test_name.rb +24 -0
- data/spec/unit/type/sub_type/test_default_name.rb +14 -0
- data/spec/unit/type/sub_type/test_dress.rb +75 -0
- data/spec/unit/type/sub_type/test_equality.rb +34 -0
- data/spec/unit/type/sub_type/test_include.rb +34 -0
- data/spec/unit/type/sub_type/test_initialize.rb +16 -0
- data/spec/unit/type/sub_type/test_name.rb +24 -0
- data/spec/unit/type/tuple_type/test_default_name.rb +14 -0
- data/spec/unit/type/tuple_type/test_dress.rb +112 -0
- data/spec/unit/type/tuple_type/test_equality.rb +32 -0
- data/spec/unit/type/tuple_type/test_include.rb +38 -0
- data/spec/unit/type/tuple_type/test_initialize.rb +30 -0
- data/spec/unit/type/tuple_type/test_name.rb +24 -0
- data/spec/unit/type/union_type/test_default_name.rb +12 -0
- data/spec/unit/type/union_type/test_dress.rb +43 -0
- data/spec/unit/type/union_type/test_equality.rb +30 -0
- data/spec/unit/type/union_type/test_include.rb +28 -0
- data/spec/unit/type/union_type/test_initialize.rb +24 -0
- data/spec/unit/type/union_type/test_name.rb +20 -0
- data/spec/unit/type_factory/dsl/test_adt.rb +54 -0
- data/spec/unit/type_factory/dsl/test_attribute.rb +37 -0
- data/spec/unit/type_factory/dsl/test_attributes.rb +41 -0
- data/spec/unit/type_factory/dsl/test_builtin.rb +45 -0
- data/spec/unit/type_factory/dsl/test_relation.rb +85 -0
- data/spec/unit/type_factory/dsl/test_seq.rb +57 -0
- data/spec/unit/type_factory/dsl/test_set.rb +57 -0
- data/spec/unit/type_factory/dsl/test_subtype.rb +91 -0
- data/spec/unit/type_factory/dsl/test_tuple.rb +73 -0
- data/spec/unit/type_factory/dsl/test_union.rb +81 -0
- data/spec/unit/type_factory/factory/test_builtin.rb +24 -0
- data/spec/unit/type_factory/factory/test_seq_type.rb +44 -0
- data/spec/unit/type_factory/factory/test_set_type.rb +44 -0
- data/spec/unit/type_factory/factory/test_sub_type.rb +53 -0
- data/spec/unit/type_factory/factory/test_tuple_type.rb +43 -0
- data/tasks/gem.rake +73 -0
- data/tasks/test.rake +31 -0
- metadata +344 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Heading, "equality" do
|
4
|
+
|
5
|
+
let(:h1){ Heading.new([Attribute.new(:r, intType), Attribute.new(:b, intType)]) }
|
6
|
+
let(:h2){ Heading.new([Attribute.new(:b, intType), Attribute.new(:r, intType)]) }
|
7
|
+
let(:h3){ Heading.new([Attribute.new(:b, intType)]) }
|
8
|
+
|
9
|
+
it 'should apply structural equality' do
|
10
|
+
(h1 == h2).should be_true
|
11
|
+
(h2 == h1).should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should apply distinguish different types' do
|
15
|
+
(h1 == h3).should be_false
|
16
|
+
(h2 == h3).should be_false
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should be a total function, with nil for non types' do
|
20
|
+
(h1 == 12).should be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should implement hash accordingly' do
|
24
|
+
[h1, h2].map(&:hash).uniq.size.should eq(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Heading, "initialize" do
|
4
|
+
|
5
|
+
subject{ Heading.new(attributes) }
|
6
|
+
|
7
|
+
context 'with no attribute' do
|
8
|
+
let(:attributes){
|
9
|
+
[ ]
|
10
|
+
}
|
11
|
+
|
12
|
+
it{ should be_a(Heading) }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with valid attributes' do
|
16
|
+
let(:attributes){
|
17
|
+
[ Attribute.new(:red, intType) ]
|
18
|
+
}
|
19
|
+
|
20
|
+
it{ should be_a(Heading) }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with invalid attributes' do
|
24
|
+
let(:attributes){
|
25
|
+
[ Attribute.new(:red, intType), Attribute.new(:red, intType) ]
|
26
|
+
}
|
27
|
+
|
28
|
+
it 'should raise an error' do
|
29
|
+
->{
|
30
|
+
subject
|
31
|
+
}.should raise_error(ArgumentError, "Attribute names must be unique")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Heading, "size" do
|
4
|
+
|
5
|
+
let(:r){ Attribute.new(:red, intType) }
|
6
|
+
let(:g){ Attribute.new(:green, intType) }
|
7
|
+
let(:b){ Attribute.new(:blue, intType) }
|
8
|
+
|
9
|
+
subject{ heading.size }
|
10
|
+
|
11
|
+
context 'on an empty heading' do
|
12
|
+
let(:heading){ Heading.new([]) }
|
13
|
+
|
14
|
+
it{ should eq(0) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'on an singleton heading' do
|
18
|
+
let(:heading){ Heading.new([r]) }
|
19
|
+
|
20
|
+
it{ should eq(1) }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'on an big heading' do
|
24
|
+
let(:heading){ Heading.new([r, g, b]) }
|
25
|
+
|
26
|
+
it{ should eq(3) }
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Heading, "to_name" do
|
4
|
+
|
5
|
+
subject{ Heading.new(attributes).to_name }
|
6
|
+
|
7
|
+
context 'with no attribute' do
|
8
|
+
let(:attributes){
|
9
|
+
[ ]
|
10
|
+
}
|
11
|
+
|
12
|
+
it{ should eq('') }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with one attribute' do
|
16
|
+
let(:attributes){
|
17
|
+
[ Attribute.new(:red, intType) ]
|
18
|
+
}
|
19
|
+
|
20
|
+
it{ should eq('red: intType') }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with multiple attributes' do
|
24
|
+
let(:attributes){
|
25
|
+
[ Attribute.new(:red, intType), Attribute.new(:blue, floatType) ]
|
26
|
+
}
|
27
|
+
|
28
|
+
it{ should eq('red: intType, blue: floatType') }
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Qrb, "parse" do
|
3
|
+
|
4
|
+
subject{
|
5
|
+
Qrb.parse <<-EOF
|
6
|
+
Posint = .Fixnum( i | i>=0 )
|
7
|
+
Point = { x: Posint, y: Posint }
|
8
|
+
EOF
|
9
|
+
}
|
10
|
+
|
11
|
+
it{ should be_a(Qrb::System) }
|
12
|
+
|
13
|
+
it 'should have the expected types' do
|
14
|
+
subject["Posint"].should be_a(Qrb::SubType)
|
15
|
+
subject["Point"].should be_a(Qrb::TupleType)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "ad_type" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "ad_type")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile(type_factory)
|
11
|
+
}
|
12
|
+
|
13
|
+
context 'One contract' do
|
14
|
+
let(:input){ '.Color <rgb> {r: .Integer, g: .Integer, b: .Integer}' }
|
15
|
+
|
16
|
+
it 'compiles to an AdType' do
|
17
|
+
compiled.should be_a(AdType)
|
18
|
+
compiled.ruby_type.should be(Color)
|
19
|
+
compiled.contract_names.should eq([:rgb])
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should behave as expected' do
|
23
|
+
compiled.dress(r: 138, g: 43, b: 226).should eq(blueviolet)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'Two contracts' do
|
28
|
+
let(:input){
|
29
|
+
<<-TYPE.strip
|
30
|
+
.Color <rgb> {r: .Integer, g: .Integer, b: .Integer},
|
31
|
+
<hex> .String
|
32
|
+
TYPE
|
33
|
+
}
|
34
|
+
|
35
|
+
it 'compiles to an AdType' do
|
36
|
+
compiled.should be_a(AdType)
|
37
|
+
compiled.ruby_type.should be(Color)
|
38
|
+
compiled.contract_names.should eq([:rgb, :hex])
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should behave as expected' do
|
42
|
+
compiled.dress("#8A2BE2").should eq(blueviolet)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'No ruby class' do
|
47
|
+
let(:input){ '<as> {r: .Integer}' }
|
48
|
+
|
49
|
+
it 'compiles to an AdType' do
|
50
|
+
compiled.should be_a(AdType)
|
51
|
+
compiled.ruby_type.should be_nil
|
52
|
+
compiled.contract_names.should eq([:as])
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should behave as expected' do
|
56
|
+
compiled.dress(r: 12).should eq(r: 12)
|
57
|
+
->{
|
58
|
+
compiled.dress("foo")
|
59
|
+
}.should raise_error(TypeError)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'Duplicate contract name' do
|
64
|
+
let(:input){ '.Color <rgb> {r: .Integer}, <rgb> .String' }
|
65
|
+
|
66
|
+
it 'raises an error' do
|
67
|
+
->{
|
68
|
+
compiled
|
69
|
+
}.should raise_error(Error, "Duplicate contract name `rgb`")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'A contract with explicit converters' do
|
74
|
+
let(:input){ '.DateTime <iso> .String \( s | DateTime.parse(s) ) \( d | d.to_s )' }
|
75
|
+
|
76
|
+
it 'compiles to an AdType' do
|
77
|
+
compiled.should be_a(AdType)
|
78
|
+
compiled.ruby_type.should be(DateTime)
|
79
|
+
compiled.contract_names.should eq([:iso])
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should behave as expected' do
|
83
|
+
compiled.dress("2014-01-19T12:00").should be_a(DateTime)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should hide errors' do
|
87
|
+
err = compiled.dress("foo") rescue $!
|
88
|
+
err.should be_a(TypeError)
|
89
|
+
err.message.should eq("Invalid value `foo` for DateTime")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "attribute" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "attribute")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile(type_factory)
|
11
|
+
}
|
12
|
+
|
13
|
+
context 'a: .Integer' do
|
14
|
+
let(:input){ 'a: .Integer' }
|
15
|
+
|
16
|
+
it 'compiles to an Attribute' do
|
17
|
+
compiled.should be_a(Attribute)
|
18
|
+
compiled.name.should eq(:a)
|
19
|
+
compiled.type.should be_a(BuiltinType)
|
20
|
+
compiled.type.ruby_type.should be(Integer)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "builtin_type" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(source, root: "builtin_type")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile(type_factory)
|
11
|
+
}
|
12
|
+
|
13
|
+
context 'when an unqualified class name' do
|
14
|
+
let(:source){ ".Integer" }
|
15
|
+
|
16
|
+
it 'compiles to a BuiltinType' do
|
17
|
+
compiled.should be_a(BuiltinType)
|
18
|
+
compiled.ruby_type.should be(Integer)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when a qualified class name' do
|
23
|
+
let(:source){ ".Qrb::Type" }
|
24
|
+
|
25
|
+
it 'compiles to a BuiltinType' do
|
26
|
+
compiled.should be_a(BuiltinType)
|
27
|
+
compiled.ruby_type.should be(::Qrb::Type)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "comment" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "comment")
|
7
|
+
}
|
8
|
+
|
9
|
+
[
|
10
|
+
'#',
|
11
|
+
"#\n",
|
12
|
+
"# \n",
|
13
|
+
'# foo bar',
|
14
|
+
"# foo bar\n",
|
15
|
+
].each do |source|
|
16
|
+
context "when `#{source}`" do
|
17
|
+
let(:input){ source }
|
18
|
+
|
19
|
+
it 'should parse' do
|
20
|
+
subject.should eq(source)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "constraint_def" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "constraint_def")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile(type_factory)
|
11
|
+
}
|
12
|
+
|
13
|
+
context '(i | i >= 0)' do
|
14
|
+
let(:input){ '(i | i >= 0)' }
|
15
|
+
|
16
|
+
it 'compiles to an Hash' do
|
17
|
+
compiled.should be_a(Hash)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'compiled to the correct proc' do
|
21
|
+
compiled[:predicate].call(12).should be_true
|
22
|
+
compiled[:predicate].call(-12).should be_false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "constraints" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "constraints")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile("a")
|
11
|
+
}
|
12
|
+
|
13
|
+
context 'a >= 10' do
|
14
|
+
let(:input){ 'a >= 10' }
|
15
|
+
|
16
|
+
it 'compiles to an Hash' do
|
17
|
+
compiled.should be_a(Hash)
|
18
|
+
compiled.keys.should eq([:predicate])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'foo: a >= 10' do
|
23
|
+
let(:input){ 'foo: a >= 10' }
|
24
|
+
|
25
|
+
it 'compiles to an Hash' do
|
26
|
+
compiled.should be_a(Hash)
|
27
|
+
compiled.keys.should eq([:foo])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'foo: a >= 10, bar: a <= 255' do
|
32
|
+
let(:input){ 'foo: a >= 10, bar: a <= 255' }
|
33
|
+
|
34
|
+
it 'compiles to an Hash' do
|
35
|
+
compiled.should be_a(Hash)
|
36
|
+
compiled.keys.should eq([:foo, :bar])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'foo: a >= 10, foo: a <= 255' do
|
41
|
+
let(:input){ 'foo: a >= 10, foo: a <= 255' }
|
42
|
+
|
43
|
+
it 'compiles to an Hash' do
|
44
|
+
->{
|
45
|
+
compiled
|
46
|
+
}.should raise_error("Duplicate constraint name `foo`")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "contract" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "contract")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:contract){
|
10
|
+
compiled.values.first
|
11
|
+
}
|
12
|
+
|
13
|
+
context 'No converter and a class' do
|
14
|
+
let(:input){ '<rgb> {r: .Integer, g: .Integer, b: .Integer}' }
|
15
|
+
|
16
|
+
let(:compiled){
|
17
|
+
subject.compile(type_factory, Color)
|
18
|
+
}
|
19
|
+
|
20
|
+
it 'compiles to the expected Hash' do
|
21
|
+
compiled.should be_a(Hash)
|
22
|
+
compiled.keys.should eq([:rgb])
|
23
|
+
contract.should be_a(Array)
|
24
|
+
contract.first.should be_a(TupleType)
|
25
|
+
contract.last.should be_a(Method)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'No converter and no class' do
|
30
|
+
let(:input){ '<rgb> {r: .Integer, g: .Integer, b: .Integer}' }
|
31
|
+
|
32
|
+
let(:compiled){
|
33
|
+
subject.compile(type_factory, nil)
|
34
|
+
}
|
35
|
+
|
36
|
+
it 'compiles to the expected Hash' do
|
37
|
+
compiled.should be_a(Hash)
|
38
|
+
compiled.keys.should eq([:rgb])
|
39
|
+
contract.should be_a(Array)
|
40
|
+
contract.first.should be_a(TupleType)
|
41
|
+
contract.last.should be(Qrb::IDENTITY)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'A contract with explicit converters' do
|
46
|
+
let(:input){ '<iso> .String \( s | DateTime.parse(s) ) \( d | d.to_s )' }
|
47
|
+
|
48
|
+
let(:compiled){
|
49
|
+
subject.compile(type_factory, nil)
|
50
|
+
}
|
51
|
+
|
52
|
+
it 'compiles to the expected Hash' do
|
53
|
+
compiled.should be_a(Hash)
|
54
|
+
compiled.keys.should eq([:iso])
|
55
|
+
contract.should be_a(Array)
|
56
|
+
contract.first.should be_a(BuiltinType)
|
57
|
+
contract.last.should be_a(Proc)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "expression" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "expression")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile("a")
|
11
|
+
}
|
12
|
+
|
13
|
+
context 'a >= 10' do
|
14
|
+
let(:input){ 'a >= 10' }
|
15
|
+
|
16
|
+
it 'compiles to an Proc' do
|
17
|
+
compiled.should be_a(Proc)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should be the correct Proc' do
|
21
|
+
compiled.call(12).should be_true
|
22
|
+
compiled.call(9).should be_false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context '(a >= 10)' do
|
27
|
+
let(:input){ '(a >= 10)' }
|
28
|
+
|
29
|
+
it 'compiles to an Proc' do
|
30
|
+
compiled.should be_a(Proc)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'acall(a)' do
|
35
|
+
let(:input){ 'acall(a)' }
|
36
|
+
|
37
|
+
it 'compiles to an Proc' do
|
38
|
+
compiled.should be_a(Proc)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "heading" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "heading")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile(type_factory)
|
11
|
+
}
|
12
|
+
|
13
|
+
context 'empty heading' do
|
14
|
+
let(:input){ ' ' }
|
15
|
+
|
16
|
+
it 'compiles to a Heading' do
|
17
|
+
compiled.should be_a(Heading)
|
18
|
+
compiled.to_name.should eq('')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'a: .Integer' do
|
23
|
+
let(:input){ 'a: .Integer' }
|
24
|
+
|
25
|
+
it 'compiles to a Heading' do
|
26
|
+
compiled.should be_a(Heading)
|
27
|
+
compiled.to_name.should eq('a: Integer')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'a: .Integer, b: .Float' do
|
32
|
+
let(:input){ 'a: .Integer, b: .Float' }
|
33
|
+
|
34
|
+
it 'compiles to a Heading' do
|
35
|
+
compiled.should be_a(Heading)
|
36
|
+
compiled.to_name.should eq('a: Integer, b: Float')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "named_constraint" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "named_constraint")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile("a")
|
11
|
+
}
|
12
|
+
|
13
|
+
context 'a >= 10' do
|
14
|
+
let(:input){ 'foo: a >= 10' }
|
15
|
+
|
16
|
+
it 'compiles to an Hash' do
|
17
|
+
compiled.should be_a(Hash)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'has expected keys' do
|
21
|
+
compiled.keys.should eq([:foo])
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should be the correct Proc' do
|
25
|
+
compiled[:foo].call(12).should be_true
|
26
|
+
compiled[:foo].call(9).should be_false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "relation_type" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "relation_type")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile(type_factory)
|
11
|
+
}
|
12
|
+
|
13
|
+
context 'empty heading' do
|
14
|
+
let(:input){ '{{ }}' }
|
15
|
+
|
16
|
+
it 'compiles to a RelationType' do
|
17
|
+
compiled.should be_a(RelationType)
|
18
|
+
compiled.heading.should be_empty
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context '{{a: .Integer}}' do
|
23
|
+
let(:input){ '{{a: .Integer}}' }
|
24
|
+
|
25
|
+
it 'compiles to a RelationType' do
|
26
|
+
compiled.should be_a(RelationType)
|
27
|
+
compiled.heading.size.should eq(1)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context '{{a: .Integer, b: .Float}}' do
|
32
|
+
let(:input){ '{{a: .Integer, b: .Float}}' }
|
33
|
+
|
34
|
+
it 'compiles to a RelationType' do
|
35
|
+
compiled.should be_a(RelationType)
|
36
|
+
compiled.heading.size.should eq(2)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "seq_type" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "seq_type")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile(type_factory)
|
11
|
+
}
|
12
|
+
|
13
|
+
context '[.Integer]' do
|
14
|
+
let(:input){ '[.Integer]' }
|
15
|
+
|
16
|
+
it 'compiles to a SeqType' do
|
17
|
+
compiled.should be_a(SeqType)
|
18
|
+
compiled.elm_type.should be_a(BuiltinType)
|
19
|
+
compiled.elm_type.ruby_type.should be(Integer)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Syntax, "set_type" do
|
4
|
+
|
5
|
+
subject{
|
6
|
+
Syntax.parse(input, root: "set_type")
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:compiled){
|
10
|
+
subject.compile(type_factory)
|
11
|
+
}
|
12
|
+
|
13
|
+
context '{.Integer}' do
|
14
|
+
let(:input){ '{.Integer}' }
|
15
|
+
|
16
|
+
it 'compiles to a SeqType' do
|
17
|
+
compiled.should be_a(SetType)
|
18
|
+
compiled.elm_type.should be_a(BuiltinType)
|
19
|
+
compiled.elm_type.ruby_type.should be(Integer)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|