qrb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|