finitio 0.7.0.pre.rc3 → 0.9.1

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 (104) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +34 -0
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +41 -41
  5. data/README.md +88 -12
  6. data/lib/finitio.rb +37 -5
  7. data/lib/finitio/generation.rb +106 -0
  8. data/lib/finitio/generation/ad_type.rb +10 -0
  9. data/lib/finitio/generation/alias_type.rb +9 -0
  10. data/lib/finitio/generation/any_type.rb +11 -0
  11. data/lib/finitio/generation/builtin_type.rb +9 -0
  12. data/lib/finitio/generation/hash_based_type.rb +15 -0
  13. data/lib/finitio/generation/heuristic.rb +8 -0
  14. data/lib/finitio/generation/heuristic/constant.rb +30 -0
  15. data/lib/finitio/generation/heuristic/random.rb +52 -0
  16. data/lib/finitio/generation/rel_based_type.rb +13 -0
  17. data/lib/finitio/generation/seq_type.rb +13 -0
  18. data/lib/finitio/generation/set_type.rb +13 -0
  19. data/lib/finitio/generation/sub_type.rb +9 -0
  20. data/lib/finitio/generation/union_type.rb +10 -0
  21. data/lib/finitio/inference.rb +51 -0
  22. data/lib/finitio/json_schema.rb +16 -0
  23. data/lib/finitio/json_schema/ad_type.rb +11 -0
  24. data/lib/finitio/json_schema/alias_type.rb +9 -0
  25. data/lib/finitio/json_schema/any_type.rb +9 -0
  26. data/lib/finitio/json_schema/builtin_type.rb +27 -0
  27. data/lib/finitio/json_schema/hash_based_type.rb +25 -0
  28. data/lib/finitio/json_schema/rel_based_type.rb +13 -0
  29. data/lib/finitio/json_schema/seq_type.rb +12 -0
  30. data/lib/finitio/json_schema/set_type.rb +13 -0
  31. data/lib/finitio/json_schema/struct_type.rb +12 -0
  32. data/lib/finitio/json_schema/sub_type.rb +10 -0
  33. data/lib/finitio/json_schema/union_type.rb +11 -0
  34. data/lib/finitio/support.rb +18 -0
  35. data/lib/finitio/support/attribute.rb +8 -0
  36. data/lib/finitio/support/compilation.rb +18 -18
  37. data/lib/finitio/support/contract.rb +10 -2
  38. data/lib/finitio/support/fetch_scope.rb +19 -0
  39. data/lib/finitio/support/heading.rb +42 -1
  40. data/lib/finitio/syntax.rb +1 -1
  41. data/lib/finitio/syntax/import.rb +1 -1
  42. data/lib/finitio/syntax/lexer.citrus +1 -1
  43. data/lib/finitio/syntax/type.rb +2 -0
  44. data/lib/finitio/syntax/type/high_order_type_instantiation.rb +29 -0
  45. data/lib/finitio/syntax/type/high_order_vars.rb +16 -0
  46. data/lib/finitio/syntax/type/type_def.rb +11 -1
  47. data/lib/finitio/syntax/types.citrus +14 -1
  48. data/lib/finitio/system.rb +20 -4
  49. data/lib/finitio/type.rb +19 -0
  50. data/lib/finitio/type/ad_type.rb +9 -1
  51. data/lib/finitio/type/alias_type.rb +8 -0
  52. data/lib/finitio/type/any_type.rb +12 -0
  53. data/lib/finitio/type/builtin_type.rb +4 -0
  54. data/lib/finitio/type/collection_type.rb +15 -0
  55. data/lib/finitio/type/heading_based_type.rb +17 -0
  56. data/lib/finitio/type/high_order_type.rb +39 -0
  57. data/lib/finitio/type/multi_relation_type.rb +4 -0
  58. data/lib/finitio/type/multi_tuple_type.rb +4 -0
  59. data/lib/finitio/type/proxy_type.rb +10 -20
  60. data/lib/finitio/type/relation_type.rb +4 -0
  61. data/lib/finitio/type/seq_type.rb +1 -1
  62. data/lib/finitio/type/struct_type.rb +8 -0
  63. data/lib/finitio/type/sub_type.rb +8 -0
  64. data/lib/finitio/type/tuple_type.rb +4 -0
  65. data/lib/finitio/type/union_type.rb +19 -0
  66. data/lib/finitio/version.rb +2 -2
  67. data/spec/finitio/test_stdlib_memoization.rb +22 -0
  68. data/spec/finitio/test_system.rb +0 -11
  69. data/spec/generation/test_generation.rb +169 -0
  70. data/spec/heading/test_looks_similar.rb +45 -0
  71. data/spec/heading/test_suppremum.rb +56 -0
  72. data/spec/inference/test_inference.rb +42 -0
  73. data/spec/json_schema/test_ad_type.rb +20 -0
  74. data/spec/json_schema/test_alias_type.rb +15 -0
  75. data/spec/json_schema/test_any_type.rb +11 -0
  76. data/spec/json_schema/test_builtin_type.rb +51 -0
  77. data/spec/json_schema/test_multi_relation_type.rb +58 -0
  78. data/spec/json_schema/test_multi_tuple_type.rb +50 -0
  79. data/spec/json_schema/test_relation_type.rb +30 -0
  80. data/spec/json_schema/test_seq_type.rb +18 -0
  81. data/spec/json_schema/test_set_type.rb +19 -0
  82. data/spec/json_schema/test_struct_type.rb +18 -0
  83. data/spec/json_schema/test_sub_type.rb +17 -0
  84. data/spec/json_schema/test_tuple_type.rb +26 -0
  85. data/spec/json_schema/test_union_type.rb +17 -0
  86. data/spec/regression/test_heading_extra_are_proxy_resolved.rb +41 -0
  87. data/spec/spec_helper.rb +32 -6
  88. data/spec/support/test_compare_attrs.rb +67 -0
  89. data/spec/syntax/test_compile.rb +57 -0
  90. data/spec/system/fixtures/system.fio +2 -0
  91. data/spec/{finitio → system/fixtures}/with-duplicates.fio +2 -1
  92. data/spec/system/test_check_and_warn.rb +55 -0
  93. data/spec/type/ad_type/test_initialize.rb +1 -8
  94. data/spec/type/relation_type/test_suppremum.rb +104 -0
  95. data/spec/type/seq_type/test_suppremum.rb +54 -0
  96. data/spec/type/set_type/test_suppremum.rb +54 -0
  97. data/spec/type/test_suppremum.rb +49 -0
  98. data/spec/type/test_unconstrained.rb +150 -0
  99. data/spec/type/tuple_type/test_suppremum.rb +119 -0
  100. data/spec/type/union_type/test_suppremum.rb +51 -0
  101. data/tasks/test.rake +1 -1
  102. metadata +99 -15
  103. data/spec/type/proxy_type/test_delegation.rb +0 -37
  104. data/spec/type/proxy_type/test_resolve.rb +0 -29
@@ -0,0 +1,17 @@
1
+ module Finitio
2
+ module JsonSchema
3
+ describe "SubType" do
4
+
5
+ let(:type) {
6
+ byte
7
+ }
8
+
9
+ it 'skips constraints (for now)' do
10
+ expect(byte.to_json_schema).to eql({
11
+ type: "integer"
12
+ })
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ module Finitio
2
+ module JsonSchema
3
+ describe "TupleType" do
4
+
5
+ let(:heading){
6
+ Heading.new([Attribute.new(:a, anyType)])
7
+ }
8
+
9
+ let(:tuple_type) {
10
+ TupleType.new(heading)
11
+ }
12
+
13
+ it 'works as expected' do
14
+ expect(tuple_type.to_json_schema).to eql({
15
+ type: "object",
16
+ properties: {
17
+ a: {}
18
+ },
19
+ required: [:a],
20
+ additionalProperties: false
21
+ })
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ module Finitio
2
+ module JsonSchema
3
+ describe "UnionType" do
4
+
5
+ let(:union_type) {
6
+ UnionType.new([anyType])
7
+ }
8
+
9
+ it 'works as expected' do
10
+ expect(union_type.to_json_schema).to eql({
11
+ anyOf: [{}]
12
+ })
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Heading extra are properly resolved" do
4
+
5
+ describe "When the extra map to a type" do
6
+ let(:schema){
7
+ Finitio.system <<~F
8
+ Type = { ... : World }
9
+ World = .String
10
+ Type
11
+ F
12
+ }
13
+
14
+ it 'works' do
15
+ expect(schema.dress("hello" => "World")).to eql(hello: "World")
16
+ end
17
+ end
18
+
19
+ describe "When the extra maps to nothing" do
20
+ let(:schema){
21
+ Finitio.system <<~F
22
+ {
23
+ hello: .String
24
+ ...
25
+ }
26
+ F
27
+ }
28
+
29
+ it 'works' do
30
+ expect(schema.dress("hello" => "World")).to eql(hello: "World")
31
+ end
32
+
33
+ it 'supports extra' do
34
+ expect(schema.dress({
35
+ "hello" => "World",
36
+ "extra" => "Foo"
37
+ })).to eql(hello: "World")
38
+ end
39
+ end
40
+
41
+ end
@@ -2,6 +2,8 @@ $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'
6
+ require 'finitio/json_schema'
5
7
 
6
8
  require 'coveralls'
7
9
  Coveralls.wear!
@@ -49,15 +51,27 @@ module SpecHelpers
49
51
  end
50
52
 
51
53
  def intType
52
- Finitio::BuiltinType.new(Integer, "intType")
54
+ @intType ||= Finitio::BuiltinType.new(Integer, "intType")
53
55
  end
54
56
 
55
57
  def floatType
56
- Finitio::BuiltinType.new(Float, "floatType")
58
+ @floatType ||= Finitio::BuiltinType.new(Float, "floatType")
57
59
  end
58
60
 
59
61
  def nilType
60
- Finitio::BuiltinType.new(NilClass, "nilType")
62
+ @nilType ||= Finitio::BuiltinType.new(NilClass, "nilType")
63
+ end
64
+
65
+ def trueType
66
+ @trueType ||= Finitio::BuiltinType.new(TrueClass, "trueType")
67
+ end
68
+
69
+ def falseType
70
+ @falseType ||= Finitio::BuiltinType.new(FalseClass, "falseType")
71
+ end
72
+
73
+ def stringType
74
+ @stringType ||= Finitio::BuiltinType.new(String, "stringType")
61
75
  end
62
76
 
63
77
  def byte_full
@@ -81,15 +95,19 @@ module SpecHelpers
81
95
  end
82
96
 
83
97
  def byte
84
- Finitio::SubType.new(intType, [byte_full])
98
+ @byte ||= Finitio::SubType.new(intType, [byte_full])
99
+ end
100
+
101
+ def pos_byte
102
+ @pos_byte ||= Finitio::SubType.new(byte, [positive])
85
103
  end
86
104
 
87
105
  def posInt
88
- Finitio::SubType.new(intType, [positive])
106
+ @posInt ||= Finitio::SubType.new(intType, [positive])
89
107
  end
90
108
 
91
109
  def negInt
92
- Finitio::SubType.new(intType, [negative])
110
+ @negInt ||= Finitio::SubType.new(intType, [negative])
93
111
  end
94
112
 
95
113
  def type_factory
@@ -104,6 +122,14 @@ module SpecHelpers
104
122
  Color.new(138, 43, 226)
105
123
  end
106
124
 
125
+ def rgb_contract
126
+ @rgb_contract ||= Finitio::Contract.new(byte, Color.method(:rgb), Finitio::IDENTITY, :rgb)
127
+ end
128
+
129
+ def hex_contract
130
+ @hex_contract ||= Finitio::Contract.new(stringType, Color.method(:hex), Finitio::IDENTITY, :hex)
131
+ end
132
+
107
133
  end
108
134
 
109
135
  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
@@ -0,0 +1,2 @@
1
+ Posint = .Integer( i | i >= 0 )
2
+ Negint = .Integer( i | i < 0 )
@@ -1,5 +1,6 @@
1
1
  @import finitio/data
2
- @import finitio/system
2
+ @import ./system
3
3
 
4
4
  NilClass = .NilClass
5
5
  Posint = .Integer( i | i >= 0 )
6
+ Negint = .Integer( i | i <= 0 )
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+ module Finitio
3
+ describe System, "check_and_warn" do
4
+
5
+ before {
6
+ Finitio.stdlib_path(Path.dir)
7
+ }
8
+
9
+ subject{
10
+ Finitio.system(Path.dir/"fixtures/with-duplicates.fio").check_and_warn(logger)
11
+ }
12
+
13
+ let(:logger){
14
+ TestLogger.new
15
+ }
16
+
17
+ it {
18
+ should be_a(Finitio::System)
19
+ }
20
+
21
+ it 'detects duplicate types as expected' do
22
+ subject
23
+ expect(logger.infos).to eql([
24
+ "Duplicate type def `NilClass`",
25
+ "Duplicate type def `Posint`"
26
+ ])
27
+ end
28
+
29
+ it 'detects type erasures as expected' do
30
+ subject
31
+ expect(logger.warns).to eql([
32
+ "Type erasure `Negint`",
33
+ ])
34
+ end
35
+
36
+ class TestLogger
37
+
38
+ def initialize
39
+ @warns = []
40
+ @infos = []
41
+ end
42
+ attr_reader :warns, :infos
43
+
44
+ def warn(msg)
45
+ @warns << msg
46
+ end
47
+
48
+ def info(msg)
49
+ @infos << msg
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+ 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