finitio 0.7.0.pre.rc4 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +42 -0
  3. data/Gemfile +1 -11
  4. data/Gemfile.lock +101 -54
  5. data/README.md +89 -13
  6. data/finitio.gemspec +9 -157
  7. data/lib/finitio.rb +7 -5
  8. data/lib/finitio/generation.rb +106 -0
  9. data/lib/finitio/generation/ad_type.rb +10 -0
  10. data/lib/finitio/generation/alias_type.rb +9 -0
  11. data/lib/finitio/generation/any_type.rb +11 -0
  12. data/lib/finitio/generation/builtin_type.rb +9 -0
  13. data/lib/finitio/generation/hash_based_type.rb +15 -0
  14. data/lib/finitio/generation/heuristic.rb +8 -0
  15. data/lib/finitio/generation/heuristic/constant.rb +30 -0
  16. data/lib/finitio/generation/heuristic/random.rb +52 -0
  17. data/lib/finitio/generation/rel_based_type.rb +13 -0
  18. data/lib/finitio/generation/seq_type.rb +13 -0
  19. data/lib/finitio/generation/set_type.rb +13 -0
  20. data/lib/finitio/generation/sub_type.rb +9 -0
  21. data/lib/finitio/generation/union_type.rb +10 -0
  22. data/lib/finitio/inference.rb +51 -0
  23. data/lib/finitio/json_schema.rb +16 -0
  24. data/lib/finitio/json_schema/ad_type.rb +11 -0
  25. data/lib/finitio/json_schema/alias_type.rb +9 -0
  26. data/lib/finitio/json_schema/any_type.rb +9 -0
  27. data/lib/finitio/json_schema/builtin_type.rb +27 -0
  28. data/lib/finitio/json_schema/hash_based_type.rb +25 -0
  29. data/lib/finitio/json_schema/rel_based_type.rb +13 -0
  30. data/lib/finitio/json_schema/seq_type.rb +12 -0
  31. data/lib/finitio/json_schema/set_type.rb +13 -0
  32. data/lib/finitio/json_schema/struct_type.rb +12 -0
  33. data/lib/finitio/json_schema/sub_type.rb +10 -0
  34. data/lib/finitio/json_schema/union_type.rb +11 -0
  35. data/lib/finitio/support.rb +18 -0
  36. data/lib/finitio/support/attribute.rb +8 -0
  37. data/lib/finitio/support/compilation.rb +18 -18
  38. data/lib/finitio/support/contract.rb +10 -2
  39. data/lib/finitio/support/fetch_scope.rb +19 -0
  40. data/lib/finitio/support/heading.rb +42 -1
  41. data/lib/finitio/syntax.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 +18 -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_system.rb +0 -11
  68. data/spec/generation/test_generation.rb +169 -0
  69. data/spec/heading/test_looks_similar.rb +45 -0
  70. data/spec/heading/test_suppremum.rb +56 -0
  71. data/spec/inference/test_inference.rb +42 -0
  72. data/spec/json_schema/test_ad_type.rb +20 -0
  73. data/spec/json_schema/test_alias_type.rb +15 -0
  74. data/spec/json_schema/test_any_type.rb +11 -0
  75. data/spec/json_schema/test_builtin_type.rb +51 -0
  76. data/spec/json_schema/test_multi_relation_type.rb +58 -0
  77. data/spec/json_schema/test_multi_tuple_type.rb +50 -0
  78. data/spec/json_schema/test_relation_type.rb +30 -0
  79. data/spec/json_schema/test_seq_type.rb +18 -0
  80. data/spec/json_schema/test_set_type.rb +19 -0
  81. data/spec/json_schema/test_struct_type.rb +18 -0
  82. data/spec/json_schema/test_sub_type.rb +17 -0
  83. data/spec/json_schema/test_tuple_type.rb +26 -0
  84. data/spec/json_schema/test_union_type.rb +17 -0
  85. data/spec/regression/test_heading_extra_are_proxy_resolved.rb +41 -0
  86. data/spec/spec_helper.rb +32 -6
  87. data/spec/support/test_compare_attrs.rb +67 -0
  88. data/spec/syntax/test_compile.rb +57 -0
  89. data/spec/system/fixtures/system.fio +2 -0
  90. data/spec/{finitio → system/fixtures}/with-duplicates.fio +2 -1
  91. data/spec/system/test_check_and_warn.rb +55 -0
  92. data/spec/type/ad_type/test_initialize.rb +1 -8
  93. data/spec/type/relation_type/test_suppremum.rb +104 -0
  94. data/spec/type/seq_type/test_suppremum.rb +54 -0
  95. data/spec/type/set_type/test_suppremum.rb +54 -0
  96. data/spec/type/test_suppremum.rb +49 -0
  97. data/spec/type/test_unconstrained.rb +150 -0
  98. data/spec/type/tuple_type/test_suppremum.rb +119 -0
  99. data/spec/type/union_type/test_suppremum.rb +51 -0
  100. data/tasks/test.rake +1 -1
  101. metadata +203 -17
  102. data/spec/type/proxy_type/test_delegation.rb +0 -37
  103. data/spec/type/proxy_type/test_resolve.rb +0 -29
@@ -0,0 +1,9 @@
1
+ module Finitio
2
+ class AliasType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ target.to_json_schema(*args, &bl)
6
+ end
7
+
8
+ end # class AliasType
9
+ end # module Finitio
@@ -0,0 +1,9 @@
1
+ module Finitio
2
+ class AnyType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ {}
6
+ end
7
+
8
+ end # class AnyType
9
+ end # module Finitio
@@ -0,0 +1,27 @@
1
+ module Finitio
2
+ module JsonSchema
3
+
4
+ BUILTIN_MAPPING = {
5
+ NilClass => "null",
6
+ String => "string",
7
+ Integer => "integer",
8
+ Fixnum => "integer",
9
+ Bignum => "integer",
10
+ Float => "number",
11
+ Numeric => "number"
12
+ }
13
+
14
+ end
15
+ class BuiltinType
16
+
17
+ def to_json_schema(*args, &bl)
18
+ mapped = JsonSchema::BUILTIN_MAPPING[ruby_type]
19
+ if mapped
20
+ { type: mapped }
21
+ else
22
+ raise JsonSchema::Error, "Unable to map #{ruby_type} to json-schema"
23
+ end
24
+ end
25
+
26
+ end # class BuiltinType
27
+ end # module Finitio
@@ -0,0 +1,25 @@
1
+ module Finitio
2
+ module HashBasedType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ base = {
6
+ type: "object"
7
+ }
8
+ unless heading.empty?
9
+ base[:properties] = heading.inject({}){|ps,a|
10
+ ps.merge(a.name => a.type.to_json_schema(*args, &bl))
11
+ }
12
+ end
13
+ unless (reqs = heading.select{|a| a.required? }).empty?
14
+ base[:required] = reqs.map{|a| a.name }
15
+ end
16
+ base[:additionalProperties] = if heading.allow_extra?
17
+ heading.allow_extra.to_json_schema(*args, &bl)
18
+ else
19
+ false
20
+ end
21
+ base
22
+ end
23
+
24
+ end # module HashBasedType
25
+ end # module UnionType
@@ -0,0 +1,13 @@
1
+ module Finitio
2
+ module RelBasedType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ {
6
+ type: "array",
7
+ items: tuple_type.to_json_schema(*args, &bl),
8
+ uniqueItems: true
9
+ }
10
+ end
11
+
12
+ end # module RelBasedType
13
+ end # module Finitio
@@ -0,0 +1,12 @@
1
+ module Finitio
2
+ class SeqType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ {
6
+ type: "array",
7
+ items: elm_type.to_json_schema(*args, &bl)
8
+ }
9
+ end
10
+
11
+ end # class SeqType
12
+ end # module Finitio
@@ -0,0 +1,13 @@
1
+ module Finitio
2
+ class SetType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ {
6
+ type: "array",
7
+ items: elm_type.to_json_schema(*args, &bl),
8
+ uniqueItems: true
9
+ }
10
+ end
11
+
12
+ end # class SetType
13
+ end # module Finitio
@@ -0,0 +1,12 @@
1
+ module Finitio
2
+ class StructType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ {
6
+ type: "array",
7
+ items: component_types.map{|c| c.to_json_schema(*args, &bl) }
8
+ }
9
+ end
10
+
11
+ end # class StructType
12
+ end # module Finitio
@@ -0,0 +1,10 @@
1
+ module Finitio
2
+ class SubType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ # TODO: add support for constraints here...
6
+ super_type.to_json_schema(*args, &bl)
7
+ end
8
+
9
+ end # class SubType
10
+ end # module Finitio
@@ -0,0 +1,11 @@
1
+ module Finitio
2
+ class UnionType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ {
6
+ anyOf: candidates.map{|c| c.to_json_schema(*args, &bl) }
7
+ }
8
+ end
9
+
10
+ end # class UnionType
11
+ end # module Finitio
@@ -1,3 +1,20 @@
1
+ module Finitio
2
+ module Support
3
+
4
+ def compare_attrs(h1, h2, &bl)
5
+ mine, yours = if bl
6
+ [h1.map(&bl), h2.map(&bl)]
7
+ elsif h1.is_a?(Hash)
8
+ [h1.keys, h2.keys]
9
+ else
10
+ [h1, h2]
11
+ end
12
+ [ mine & yours, mine - yours, yours - mine ]
13
+ end
14
+ module_function :compare_attrs
15
+
16
+ end # module Support
17
+ end # module Finitio
1
18
  require_relative 'support/proc_with_code'
2
19
  require_relative 'support/metadata'
3
20
  require_relative 'support/attribute'
@@ -6,4 +23,5 @@ require_relative 'support/contract'
6
23
  require_relative 'support/heading'
7
24
  require_relative 'support/dress_helper'
8
25
  require_relative 'support/type_factory'
26
+ require_relative 'support/fetch_scope'
9
27
  require_relative 'support/compilation'
@@ -55,5 +55,13 @@ module Finitio
55
55
  name.hash ^ type.hash ^ required.hash
56
56
  end
57
57
 
58
+ def resolve_proxies(system)
59
+ Attribute.new(name, type.resolve_proxies(system), required, metadata)
60
+ end
61
+
62
+ def unconstrained
63
+ Attribute.new(name, type.unconstrained, required, metadata)
64
+ end
65
+
58
66
  end # class Attribute
59
67
  end # module Finitio
@@ -1,19 +1,19 @@
1
1
  module Finitio
2
2
  class Compilation
3
3
 
4
- def initialize(system = System.new, factory = TypeFactory.new, source = nil)
4
+ def initialize(system = System.new, factory = TypeFactory.new, scope = nil, source = nil)
5
5
  @system = system
6
6
  @factory = factory
7
- @proxies = []
7
+ @scope = scope || FetchScope.new(system, {})
8
8
  @source = source
9
9
  end
10
- attr_reader :system, :factory, :proxies, :source
10
+ attr_reader :system, :factory, :scope, :source
11
11
 
12
12
  def self.coerce(arg, source = nil)
13
13
  case arg
14
- when NilClass then new(System.new, TypeFactory.new, source)
15
- when System then new(arg, arg.factory, source)
16
- when TypeFactory then new(System.new, arg, source)
14
+ when NilClass then new(System.new, TypeFactory.new, nil, source)
15
+ when System then new(arg, arg.factory, nil, source)
16
+ when TypeFactory then new(System.new, arg, nil, source)
17
17
  else
18
18
  raise ArgumentError, "Unable to coerce `#{arg}`"
19
19
  end
@@ -48,11 +48,8 @@ module Finitio
48
48
  Pathname.new(file)
49
49
  end
50
50
 
51
- def resolve_proxies!
52
- proxies.each do |p|
53
- p.resolve(system)
54
- end
55
- self
51
+ def resolve_proxies
52
+ system.resolve_proxies
56
53
  end
57
54
 
58
55
  # Delegation to Factory
@@ -63,17 +60,10 @@ module Finitio
63
60
  }
64
61
  end
65
62
 
66
- def proxy(*args, &bl)
67
- proxy = factory.proxy(*args, &bl)
68
- proxies << proxy
69
- proxy
70
- end
71
-
72
63
  # Delegation to System
73
64
 
74
65
  [
75
66
  :add_type,
76
- :fetch,
77
67
  :main,
78
68
  ].each do |meth|
79
69
  define_method(meth) do |*args, &bl|
@@ -81,5 +71,15 @@ module Finitio
81
71
  end
82
72
  end
83
73
 
74
+ # Delegation to FetchScope
75
+
76
+ def fetch(type_name, &bl)
77
+ scope.fetch(type_name, &bl)
78
+ end
79
+
80
+ def with_scope(overrides)
81
+ Compilation.new(system, factory, scope.with(overrides), source)
82
+ end
83
+
84
84
  end # class Compilation
85
85
  end # module Finitio
@@ -30,7 +30,7 @@ module Finitio
30
30
  end
31
31
 
32
32
  def hash
33
- [infotype, dresser, undresser].hash
33
+ infotype.hash ^ dresser.hash ^ undresser.hash
34
34
  end
35
35
 
36
36
  def ==(other)
@@ -38,11 +38,19 @@ module Finitio
38
38
  other.is_a?(Contract) &&
39
39
  name == other.name &&
40
40
  infotype == other.infotype &&
41
- dresser == other.dresser &&
41
+ dresser == other.dresser &&
42
42
  undresser == other.undresser
43
43
  )
44
44
  end
45
45
  alias :eql? :==
46
46
 
47
+ def resolve_proxies(system)
48
+ Contract.new(infotype.resolve_proxies(system), dresser, undresser, name, metadata)
49
+ end
50
+
51
+ def unconstrained
52
+ Contract.new(infotype.unconstrained, dresser, undresser, name, metadata)
53
+ end
54
+
47
55
  end # class Contract
48
56
  end # module Finitio
@@ -0,0 +1,19 @@
1
+ module Finitio
2
+ class FetchScope
3
+
4
+ def initialize(parent, overrides)
5
+ @parent, @overrides = parent, overrides
6
+ end
7
+
8
+ def fetch(name, &bl)
9
+ @overrides.fetch(name) do
10
+ @parent.fetch(name, &bl)
11
+ end
12
+ end
13
+
14
+ def with(overrides)
15
+ FetchScope.new(self, overrides)
16
+ end
17
+
18
+ end # class FetchScope
19
+ end # module Finitio
@@ -61,6 +61,32 @@ module Finitio
61
61
  name
62
62
  end
63
63
 
64
+ def looks_similar?(other)
65
+ return self if other == self
66
+ shared, mine, yours = Support.compare_attrs(attributes, other.attributes)
67
+ shared.length >= mine.length && shared.length >= yours.length
68
+ end
69
+
70
+ def suppremum(other)
71
+ raise ArgumentError unless other.is_a?(Heading)
72
+ return self if other == self
73
+ options = { allow_extra: allow_extra? || other.allow_extra? }
74
+ shared, mine, yours = Support.compare_attrs(attributes, other.attributes)
75
+ attributes = shared.map{|attr|
76
+ a1, o1 = self[attr], other[attr]
77
+ Attribute.new(attr, a1.type.suppremum(o1.type), a1.required && o1.required)
78
+ }
79
+ attributes += mine.map{|attrname|
80
+ attr = self[attrname]
81
+ Attribute.new(attr.name, attr.type, false)
82
+ }
83
+ attributes += yours.map{|attrname|
84
+ attr = other[attrname]
85
+ Attribute.new(attr.name, attr.type, false)
86
+ }
87
+ Heading.new(attributes, options)
88
+ end
89
+
64
90
  def ==(other)
65
91
  return nil unless other.is_a?(Heading)
66
92
  attributes == other.attributes && options == other.options
@@ -73,6 +99,21 @@ module Finitio
73
99
  attr_reader :attributes, :options
74
100
  protected :attributes, :options
75
101
 
102
+ def resolve_proxies(system)
103
+ as = attributes.map{|k,a|
104
+ a.resolve_proxies(system)
105
+ }
106
+ opts = options.dup
107
+ if options[:allow_extra] && options[:allow_extra].is_a?(Type)
108
+ opts[:allow_extra] = opts[:allow_extra].resolve_proxies(system)
109
+ end
110
+ Heading.new(as, opts)
111
+ end
112
+
113
+ def unconstrained
114
+ Heading.new(attributes.values.map{|a| a.unconstrained }, options)
115
+ end
116
+
76
117
  private
77
118
 
78
119
  def normalize_attributes(attrs)
@@ -83,7 +124,7 @@ module Finitio
83
124
  attributes = {}
84
125
  attrs.each do |attr|
85
126
  unless attr.is_a?(Attribute)
86
- raise ArgumentError, "Enumerable[Attribute] expected"
127
+ raise ArgumentError, "Enumerable[Attribute] expected, got a `#{attr.inspect}`"
87
128
  end
88
129
  if attributes[attr.name]
89
130
  raise ArgumentError, "Attribute names must be unique"
@@ -27,7 +27,7 @@ module Finitio
27
27
  def self.compile(source, cpl = nil)
28
28
  cpl = Compilation.coerce(cpl, source)
29
29
  parse(source, root: "system").compile(cpl)
30
- cpl.resolve_proxies!.system
30
+ cpl.resolve_proxies
31
31
  end
32
32
 
33
33
  def self.compile_type(source, cpl = nil)
@@ -25,7 +25,7 @@ grammar Finitio::Syntax::Lexer
25
25
  end
26
26
 
27
27
  rule type_name
28
- /[A-Z][a-zA-Z]+(\.[A-Z][a-zA-Z]+)*/
28
+ /[A-Z][a-zA-Z]*(\.[A-Z][a-zA-Z]+)*/
29
29
  end
30
30
 
31
31
  rule builtin_type_name
@@ -19,9 +19,11 @@ require_relative 'type/relation_type'
19
19
  require_relative 'type/union_type'
20
20
  require_relative 'type/type_ref'
21
21
  require_relative 'type/ad_type'
22
+ require_relative 'type/high_order_type_instantiation'
22
23
  require_relative 'type/contract'
23
24
  require_relative 'type/inline_pair'
24
25
  require_relative 'type/external_pair'
25
26
  require_relative 'type/lambda_expr'
26
27
  require_relative 'type/metadata'
27
28
  require_relative 'type/metadata_attr'
29
+ require_relative 'type/high_order_vars'
@@ -0,0 +1,29 @@
1
+ module Finitio
2
+ module Syntax
3
+ module HighOrderTypeInstantiation
4
+ include Node
5
+
6
+ capture :high
7
+ capture :vars
8
+
9
+ def compile(system)
10
+ target = system.fetch(high.to_s){
11
+ raise Error, "No such type `#{high.to_s}`"
12
+ }
13
+ raise "#{high} is not a high order type" unless target.is_a?(HighOrderType)
14
+
15
+ subs = vars.compile(system).map{|low|
16
+ system.fetch(low.to_s) {
17
+ raise Error, "No such type `#{low.to_s}`"
18
+ }
19
+ }
20
+ target.instantiate(system, subs)
21
+ end
22
+
23
+ def to_ast
24
+ [:high_order_type_instantiation, high.to_s, lows.to_s]
25
+ end
26
+
27
+ end # module HighOrderTypeInstantiation
28
+ end # module Syntax
29
+ end # module Finitio