finitio 0.7.0 → 0.8.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.
Files changed (70) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +10 -0
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +40 -41
  5. data/lib/finitio/generation.rb +106 -0
  6. data/lib/finitio/generation/ad_type.rb +10 -0
  7. data/lib/finitio/generation/alias_type.rb +9 -0
  8. data/lib/finitio/generation/any_type.rb +11 -0
  9. data/lib/finitio/generation/builtin_type.rb +9 -0
  10. data/lib/finitio/generation/hash_based_type.rb +15 -0
  11. data/lib/finitio/generation/heuristic.rb +8 -0
  12. data/lib/finitio/generation/heuristic/constant.rb +30 -0
  13. data/lib/finitio/generation/heuristic/random.rb +52 -0
  14. data/lib/finitio/generation/rel_based_type.rb +13 -0
  15. data/lib/finitio/generation/seq_type.rb +13 -0
  16. data/lib/finitio/generation/set_type.rb +13 -0
  17. data/lib/finitio/generation/sub_type.rb +9 -0
  18. data/lib/finitio/generation/union_type.rb +10 -0
  19. data/lib/finitio/inference.rb +51 -0
  20. data/lib/finitio/support.rb +18 -0
  21. data/lib/finitio/support/attribute.rb +8 -0
  22. data/lib/finitio/support/compilation.rb +18 -18
  23. data/lib/finitio/support/contract.rb +8 -0
  24. data/lib/finitio/support/fetch_scope.rb +19 -0
  25. data/lib/finitio/support/heading.rb +36 -1
  26. data/lib/finitio/syntax.rb +1 -1
  27. data/lib/finitio/syntax/lexer.citrus +1 -1
  28. data/lib/finitio/syntax/type.rb +2 -0
  29. data/lib/finitio/syntax/type/high_order_type_instantiation.rb +29 -0
  30. data/lib/finitio/syntax/type/high_order_vars.rb +16 -0
  31. data/lib/finitio/syntax/type/type_def.rb +11 -1
  32. data/lib/finitio/syntax/types.citrus +14 -1
  33. data/lib/finitio/system.rb +11 -1
  34. data/lib/finitio/type.rb +19 -0
  35. data/lib/finitio/type/ad_type.rb +8 -0
  36. data/lib/finitio/type/alias_type.rb +8 -0
  37. data/lib/finitio/type/any_type.rb +12 -0
  38. data/lib/finitio/type/builtin_type.rb +4 -0
  39. data/lib/finitio/type/collection_type.rb +15 -0
  40. data/lib/finitio/type/heading_based_type.rb +17 -0
  41. data/lib/finitio/type/high_order_type.rb +39 -0
  42. data/lib/finitio/type/multi_relation_type.rb +4 -0
  43. data/lib/finitio/type/multi_tuple_type.rb +4 -0
  44. data/lib/finitio/type/proxy_type.rb +10 -20
  45. data/lib/finitio/type/relation_type.rb +4 -0
  46. data/lib/finitio/type/seq_type.rb +1 -1
  47. data/lib/finitio/type/struct_type.rb +8 -0
  48. data/lib/finitio/type/sub_type.rb +8 -0
  49. data/lib/finitio/type/tuple_type.rb +4 -0
  50. data/lib/finitio/type/union_type.rb +19 -0
  51. data/lib/finitio/version.rb +1 -1
  52. data/spec/generation/test_generation.rb +169 -0
  53. data/spec/heading/test_looks_similar.rb +45 -0
  54. data/spec/heading/test_suppremum.rb +56 -0
  55. data/spec/inference/test_inference.rb +42 -0
  56. data/spec/spec_helper.rb +31 -6
  57. data/spec/support/test_compare_attrs.rb +67 -0
  58. data/spec/syntax/test_compile.rb +57 -0
  59. data/spec/type/ad_type/test_initialize.rb +1 -8
  60. data/spec/type/relation_type/test_suppremum.rb +104 -0
  61. data/spec/type/seq_type/test_suppremum.rb +54 -0
  62. data/spec/type/set_type/test_suppremum.rb +54 -0
  63. data/spec/type/test_suppremum.rb +49 -0
  64. data/spec/type/test_unconstrained.rb +150 -0
  65. data/spec/type/tuple_type/test_suppremum.rb +119 -0
  66. data/spec/type/union_type/test_suppremum.rb +51 -0
  67. data/tasks/test.rake +1 -1
  68. metadata +183 -144
  69. data/spec/type/proxy_type/test_delegation.rb +0 -37
  70. data/spec/type/proxy_type/test_resolve.rb +0 -29
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ module Finitio
3
+ describe Heading, "looks_similar?" do
4
+
5
+ let(:heading){
6
+ Heading.new([Attribute.new(:a, intType),
7
+ Attribute.new(:b, stringType)])
8
+ }
9
+
10
+ subject{
11
+ heading.looks_similar?(h2)
12
+ }
13
+
14
+ context 'when equal' do
15
+ let(:h2){ heading }
16
+
17
+ it 'says yes' do
18
+ expect(subject).to be_truthy
19
+ end
20
+ end
21
+
22
+ context 'when shared attributes are in majority' do
23
+ let(:h2){
24
+ Heading.new([Attribute.new(:a, intType),
25
+ Attribute.new(:c, stringType)])
26
+ }
27
+
28
+ it 'says yes' do
29
+ expect(subject).to be_truthy
30
+ end
31
+ end
32
+
33
+ context 'when shared attributes are in minority' do
34
+ let(:h2){
35
+ Heading.new([Attribute.new(:d, intType),
36
+ Attribute.new(:c, stringType)])
37
+ }
38
+
39
+ it 'says no' do
40
+ expect(subject).to be_falsy
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ module Finitio
3
+ describe Heading, "suppremum" do
4
+
5
+ subject{
6
+ left.suppremum(right)
7
+ }
8
+
9
+ let(:left){
10
+ Heading.new([Attribute.new(:a, intType),
11
+ Attribute.new(:b, stringType)])
12
+ }
13
+
14
+ context 'when both are equal' do
15
+ let(:right){
16
+ Heading.new([Attribute.new(:a, intType),
17
+ Attribute.new(:b, stringType)])
18
+ }
19
+
20
+ it 'works' do
21
+ expect(subject).to be(left)
22
+ end
23
+ end
24
+
25
+ context 'when they are different' do
26
+ let(:right){
27
+ Heading.new([Attribute.new(:a, nilType),
28
+ Attribute.new(:b, stringType)])
29
+ }
30
+
31
+ it 'works' do
32
+ expect(subject).to be_a(Heading)
33
+ expect(subject[:a].type).to eql(UnionType.new [intType, nilType])
34
+ expect(subject[:b].type).to eql(stringType)
35
+ end
36
+ end
37
+
38
+ context 'when they are different II' do
39
+ let(:right){
40
+ Heading.new([Attribute.new(:c, nilType),
41
+ Attribute.new(:b, stringType)])
42
+ }
43
+
44
+ it 'works' do
45
+ expect(subject).to be_a(Heading)
46
+ expect(subject[:a].type).to eql(intType)
47
+ expect(subject[:a].required).to eql(false)
48
+ expect(subject[:b].type).to eql(stringType)
49
+ expect(subject[:b].required).to eql(true)
50
+ expect(subject[:c].type).to eql(nilType)
51
+ expect(subject[:c].required).to eql(false)
52
+ end
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'finitio/inference'
3
+ module Finitio
4
+ describe Inference do
5
+
6
+ let(:system) {
7
+ Finitio.system <<-FIO
8
+ @import finitio/data
9
+
10
+ Nil = .NilClass
11
+ Boolean = .TrueClass|.FalseClass
12
+ Integer = .Integer
13
+ Date = .Date <iso8601> .String \\( s | Date.iso8601(s) )
14
+ \\( d | d.iso8601 )
15
+ String = .String
16
+ FIO
17
+ }
18
+
19
+ let(:input) {
20
+ [
21
+ { "id" => 1, "createdAt" => "2018-01-12", "size" => "15", "priority" => "XL", "meta" => { foo: true, bar: "foo" }, "hobbies" => [] },
22
+ { "id" => 2, "createdAt" => "2019-02-23", "size" => "1", "priority" => "L", "meta" => { foo: true, bar: "baz" }, "hobbies" => ["testing"] },
23
+ { "id" => 3, "createdAt" => "2018-07-15", "size" => "7", "priority" => "S", "meta" => { foo: true, bar: "bar" } },
24
+ { "id" => 4, "createdAt" => "2019-12-12", "size" => "9", "priority" => "M", "meta" => { foo: true, baz: "baz" } },
25
+ { "id" => 4, "createdAt" => nil, "size" => "9", "priority" => "M" },
26
+ ]
27
+ }
28
+
29
+ it 'works as expected' do
30
+ result = Inference.new(system).call(input)
31
+ expect(result).to be_a(SeqType)
32
+ expect(result.elm_type).to be_a(MultiTupleType)
33
+ expect(result.elm_type[:id].type.name).to eql("Integer")
34
+ expect(result.elm_type[:createdAt].type.name).to eql("Date|Nil")
35
+ expect(result.elm_type[:size].type.name).to eql("String")
36
+ expect(result.elm_type[:priority].type.name).to eql("String")
37
+
38
+ puts result
39
+ end
40
+
41
+ end
42
+ end
@@ -2,6 +2,7 @@ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'path'
3
3
  require 'finitio'
4
4
  require 'finitio/syntax'
5
+ require 'finitio/generation'
5
6
 
6
7
  require 'coveralls'
7
8
  Coveralls.wear!
@@ -49,15 +50,27 @@ module SpecHelpers
49
50
  end
50
51
 
51
52
  def intType
52
- Finitio::BuiltinType.new(Integer, "intType")
53
+ @intType ||= Finitio::BuiltinType.new(Integer, "intType")
53
54
  end
54
55
 
55
56
  def floatType
56
- Finitio::BuiltinType.new(Float, "floatType")
57
+ @floatType ||= Finitio::BuiltinType.new(Float, "floatType")
57
58
  end
58
59
 
59
60
  def nilType
60
- Finitio::BuiltinType.new(NilClass, "nilType")
61
+ @nilType ||= Finitio::BuiltinType.new(NilClass, "nilType")
62
+ end
63
+
64
+ def trueType
65
+ @trueType ||= Finitio::BuiltinType.new(TrueClass, "trueType")
66
+ end
67
+
68
+ def falseType
69
+ @falseType ||= Finitio::BuiltinType.new(FalseClass, "falseType")
70
+ end
71
+
72
+ def stringType
73
+ @stringType ||= Finitio::BuiltinType.new(String, "stringType")
61
74
  end
62
75
 
63
76
  def byte_full
@@ -81,15 +94,19 @@ module SpecHelpers
81
94
  end
82
95
 
83
96
  def byte
84
- Finitio::SubType.new(intType, [byte_full])
97
+ @byte ||= Finitio::SubType.new(intType, [byte_full])
98
+ end
99
+
100
+ def pos_byte
101
+ @pos_byte ||= Finitio::SubType.new(byte, [positive])
85
102
  end
86
103
 
87
104
  def posInt
88
- Finitio::SubType.new(intType, [positive])
105
+ @posInt ||= Finitio::SubType.new(intType, [positive])
89
106
  end
90
107
 
91
108
  def negInt
92
- Finitio::SubType.new(intType, [negative])
109
+ @negInt ||= Finitio::SubType.new(intType, [negative])
93
110
  end
94
111
 
95
112
  def type_factory
@@ -104,6 +121,14 @@ module SpecHelpers
104
121
  Color.new(138, 43, 226)
105
122
  end
106
123
 
124
+ def rgb_contract
125
+ @rgb_contract ||= Finitio::Contract.new(byte, Color.method(:rgb), Finitio::IDENTITY, :rgb)
126
+ end
127
+
128
+ def hex_contract
129
+ @hex_contract ||= Finitio::Contract.new(floatType, Color.method(:hex), Finitio::IDENTITY, :hex)
130
+ end
131
+
107
132
  end
108
133
 
109
134
  RSpec.configure do |c|
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+ module Finitio
3
+ describe Support, "compare_attrs" do
4
+ include Support
5
+
6
+ context 'with arrays' do
7
+ it 'works on same attrs' do
8
+ h1 = [:a, :b]
9
+ h2 = [:b, :a]
10
+ shared, mine, yours = compare_attrs(h1, h2)
11
+ expect(shared).to eql([:a, :b])
12
+ expect(mine).to eql([])
13
+ expect(yours).to eql([])
14
+ end
15
+
16
+ it 'works on not same attrs' do
17
+ h1 = [ :a, :b ]
18
+ h2 = [ :c, :a ]
19
+ shared, mine, yours = compare_attrs(h1, h2)
20
+ expect(shared).to eql([:a])
21
+ expect(mine).to eql([:b])
22
+ expect(yours).to eql([:c])
23
+ end
24
+ end
25
+
26
+ context 'with hashes' do
27
+ it 'works on same attrs' do
28
+ h1 = { a: 1, b: 2 }
29
+ h2 = { a: 1, b: 2 }
30
+ shared, mine, yours = compare_attrs(h1, h2)
31
+ expect(shared).to eql([:a, :b])
32
+ expect(mine).to eql([])
33
+ expect(yours).to eql([])
34
+ end
35
+
36
+ it 'works on not same attrs' do
37
+ h1 = { a: 1, b: 2 }
38
+ h2 = { a: 1, c: 2 }
39
+ shared, mine, yours = compare_attrs(h1, h2)
40
+ expect(shared).to eql([:a])
41
+ expect(mine).to eql([:b])
42
+ expect(yours).to eql([:c])
43
+ end
44
+ end
45
+
46
+ context 'with a block' do
47
+ it 'works on same attrs' do
48
+ h1 = [{:name => :a}, {:name => :b}]
49
+ h2 = [{:name => :b}, {:name => :a}]
50
+ shared, mine, yours = compare_attrs(h1, h2){|a| a[:name] }
51
+ expect(shared).to eql([:a, :b])
52
+ expect(mine).to eql([])
53
+ expect(yours).to eql([])
54
+ end
55
+
56
+ it 'works on not same attrs' do
57
+ h1 = [{:name => :a}, {:name => :b}]
58
+ h2 = [{:name => :c}, {:name => :a}]
59
+ shared, mine, yours = compare_attrs(h1, h2){|a| a[:name] }
60
+ expect(shared).to eql([:a])
61
+ expect(mine).to eql([:b])
62
+ expect(yours).to eql([:c])
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -37,5 +37,62 @@ module Finitio
37
37
  end
38
38
  end
39
39
 
40
+ context 'with lots of proxies to resolve' do
41
+ let(:source){
42
+ <<-EOF.strip
43
+ Deep = .String
44
+ Obj = { i: Deep }
45
+ Objs = [Obj]
46
+ EOF
47
+ }
48
+
49
+ it{ should be_a(System) }
50
+
51
+ it 'should work fine' do
52
+ expect {
53
+ subject['Objs'].dress([{i: "hello"}])
54
+ }.not_to raise_error
55
+ end
56
+ end
57
+
58
+ context 'with a recursive def' do
59
+ let(:source){
60
+ <<-EOF.strip
61
+ S = .String
62
+ NodeLabel = S
63
+ Tree = { label: NodeLabel, children: [Tree] }
64
+ EOF
65
+ }
66
+
67
+ it{ should be_a(System) }
68
+
69
+ it 'should work ine' do
70
+ expect {
71
+ subject['Tree'].dress({ label: "Root", children: [
72
+ { label: "Child1", children: [] },
73
+ { label: "Child2", children: [] }
74
+ ]})
75
+ }.not_to raise_error
76
+ end
77
+ end
78
+
79
+ context 'with AD types' do
80
+ let(:source){
81
+ <<-EOF.strip
82
+ Colors = [Color]
83
+ Color = .Color <rgb> { r: Byte, g: Byte, b: Byte }
84
+ Byte = Int(i | i>0)
85
+ Int = .Integer
86
+ EOF
87
+ }
88
+
89
+ it{ should be_a(System) }
90
+
91
+ it 'should work ine' do
92
+ got = subject['Colors'].dress([{ r: 10, g: 15, b: 20 }])
93
+ expect(got.first).to be_a(Color)
94
+ end
95
+ end
96
+
40
97
  end
41
98
  end
@@ -2,16 +2,9 @@ require 'spec_helper'
2
2
  module Finitio
3
3
  describe AdType, 'initialize' do
4
4
 
5
- let(:rgb){
6
- Contract.new(intType, Color.method(:rgb), Finitio::IDENTITY, :rgb)
7
- }
8
-
9
- let(:hex){
10
- Contract.new(floatType, Color.method(:hex), Finitio::IDENTITY, :hex)
11
- }
12
5
 
13
6
  subject{
14
- AdType.new(Color, [rgb, hex])
7
+ AdType.new(Color, [rgb_contract, hex_contract])
15
8
  }
16
9
 
17
10
  context 'with valid arguments' do
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+ module Finitio
3
+ describe RelationType, "suppremum" do
4
+
5
+ subject{
6
+ left.suppremum(right)
7
+ }
8
+
9
+ let(:heading){
10
+ Heading.new([Attribute.new(:a, intType),
11
+ Attribute.new(:b, stringType)])
12
+ }
13
+
14
+ let(:left){
15
+ RelationType.new(heading)
16
+ }
17
+
18
+ context 'when right is not a tuple type' do
19
+ let(:right){
20
+ stringType
21
+ }
22
+
23
+ it 'builds a union type' do
24
+ expect(subject).to be_a(UnionType)
25
+ expect(subject.candidates).to eql([left, right])
26
+ end
27
+ end
28
+
29
+ context 'when right is an equal tuple type' do
30
+ let(:right){
31
+ RelationType.new(heading)
32
+ }
33
+
34
+ it 'keeps left' do
35
+ expect(subject).to be(left)
36
+ end
37
+ end
38
+
39
+ context 'when right is an non-equal tuple type but compatible with RelationType' do
40
+ let(:heading2){
41
+ Heading.new([Attribute.new(:a, nilType),
42
+ Attribute.new(:b, stringType)])
43
+ }
44
+
45
+ let(:right){
46
+ RelationType.new(heading2)
47
+ }
48
+
49
+ it 'builds the suppremum as expected' do
50
+ expect(subject).to be_a(RelationType)
51
+ expect(subject.heading[:a].type).to eql(UnionType.new [intType,nilType])
52
+ expect(subject.heading[:b].type).to eql(stringType)
53
+ end
54
+ end
55
+
56
+ context 'when right is an non-equal tuple type yielding a MultiRelationType' do
57
+ let(:heading2){
58
+ Heading.new([Attribute.new(:c, nilType),
59
+ Attribute.new(:b, stringType)])
60
+ }
61
+
62
+ let(:right){
63
+ RelationType.new(heading2)
64
+ }
65
+
66
+ it 'builds the suppremum as expected' do
67
+ expect(subject).to be_a(MultiRelationType)
68
+ expect(subject.heading[:a].type).to eql(intType)
69
+ expect(subject.heading[:a].required).to eql(false)
70
+ expect(subject.heading[:b].type).to eql(stringType)
71
+ expect(subject.heading[:b].required).to eql(true)
72
+ expect(subject.heading[:c].type).to eql(nilType)
73
+ expect(subject.heading[:c].required).to eql(false)
74
+ end
75
+ end
76
+
77
+ context 'when right is an non-equal tuple type yielding a MultiRelationType II' do
78
+ let(:heading2){
79
+ Heading.new([Attribute.new(:a, nilType, false),
80
+ Attribute.new(:b, stringType)])
81
+ }
82
+
83
+ let(:right){
84
+ MultiRelationType.new(heading2)
85
+ }
86
+
87
+ it 'builds the suppremum as expected' do
88
+ expect(subject).to be_a(MultiRelationType)
89
+ expect(subject.heading[:a].type).to eql(UnionType.new [intType,nilType])
90
+ expect(subject.heading[:a].required).to eql(false)
91
+ expect(subject.heading[:b].type).to eql(stringType)
92
+ end
93
+
94
+ it 'works the other way round too' do
95
+ subject = right.suppremum(left)
96
+ expect(subject).to be_a(MultiRelationType)
97
+ expect(subject.heading[:a].type).to eql(UnionType.new [intType,nilType])
98
+ expect(subject.heading[:a].required).to eql(false)
99
+ expect(subject.heading[:b].type).to eql(stringType)
100
+ end
101
+ end
102
+
103
+ end
104
+ end