finitio 0.7.0.pre.rc2 → 0.9.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 (111) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +29 -0
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +40 -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 +19 -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 +23 -0
  38. data/lib/finitio/support/fetch_scope.rb +19 -0
  39. data/lib/finitio/support/heading.rb +36 -1
  40. data/lib/finitio/support/proc_with_code.rb +34 -0
  41. data/lib/finitio/syntax.rb +1 -1
  42. data/lib/finitio/syntax/import.rb +1 -1
  43. data/lib/finitio/syntax/lexer.citrus +1 -1
  44. data/lib/finitio/syntax/type.rb +2 -0
  45. data/lib/finitio/syntax/type/expression.rb +1 -2
  46. data/lib/finitio/syntax/type/high_order_type_instantiation.rb +29 -0
  47. data/lib/finitio/syntax/type/high_order_vars.rb +16 -0
  48. data/lib/finitio/syntax/type/type_def.rb +11 -1
  49. data/lib/finitio/syntax/types.citrus +14 -1
  50. data/lib/finitio/system.rb +20 -4
  51. data/lib/finitio/type.rb +19 -0
  52. data/lib/finitio/type/ad_type.rb +21 -0
  53. data/lib/finitio/type/alias_type.rb +8 -0
  54. data/lib/finitio/type/any_type.rb +12 -0
  55. data/lib/finitio/type/builtin_type.rb +4 -0
  56. data/lib/finitio/type/collection_type.rb +15 -0
  57. data/lib/finitio/type/heading_based_type.rb +17 -0
  58. data/lib/finitio/type/high_order_type.rb +39 -0
  59. data/lib/finitio/type/multi_relation_type.rb +4 -0
  60. data/lib/finitio/type/multi_tuple_type.rb +4 -0
  61. data/lib/finitio/type/proxy_type.rb +10 -20
  62. data/lib/finitio/type/relation_type.rb +4 -0
  63. data/lib/finitio/type/seq_type.rb +1 -1
  64. data/lib/finitio/type/struct_type.rb +8 -0
  65. data/lib/finitio/type/sub_type.rb +8 -0
  66. data/lib/finitio/type/tuple_type.rb +4 -0
  67. data/lib/finitio/type/union_type.rb +19 -0
  68. data/lib/finitio/version.rb +2 -2
  69. data/spec/finitio/test_stdlib_memoization.rb +22 -0
  70. data/spec/finitio/test_system.rb +0 -8
  71. data/spec/generation/test_generation.rb +169 -0
  72. data/spec/heading/test_looks_similar.rb +45 -0
  73. data/spec/heading/test_suppremum.rb +56 -0
  74. data/spec/inference/test_inference.rb +42 -0
  75. data/spec/json_schema/test_ad_type.rb +20 -0
  76. data/spec/json_schema/test_alias_type.rb +15 -0
  77. data/spec/json_schema/test_any_type.rb +11 -0
  78. data/spec/json_schema/test_builtin_type.rb +51 -0
  79. data/spec/json_schema/test_multi_relation_type.rb +58 -0
  80. data/spec/json_schema/test_multi_tuple_type.rb +50 -0
  81. data/spec/json_schema/test_relation_type.rb +30 -0
  82. data/spec/json_schema/test_seq_type.rb +18 -0
  83. data/spec/json_schema/test_set_type.rb +19 -0
  84. data/spec/json_schema/test_struct_type.rb +18 -0
  85. data/spec/json_schema/test_sub_type.rb +17 -0
  86. data/spec/json_schema/test_tuple_type.rb +26 -0
  87. data/spec/json_schema/test_union_type.rb +17 -0
  88. data/spec/spec_helper.rb +32 -6
  89. data/spec/support/test_compare_attrs.rb +67 -0
  90. data/spec/support/test_proc_with_code.rb +27 -0
  91. data/spec/syntax/nodes/test_ad_type.rb +6 -0
  92. data/spec/syntax/nodes/test_contract.rb +5 -0
  93. data/spec/syntax/nodes/test_expression.rb +5 -0
  94. data/spec/syntax/nodes/test_sub_type.rb +5 -0
  95. data/spec/syntax/test_compile.rb +57 -0
  96. data/spec/system/fixtures/system.fio +2 -0
  97. data/spec/system/fixtures/with-duplicates.fio +6 -0
  98. data/spec/system/test_check_and_warn.rb +55 -0
  99. data/spec/type/ad_type/test_initialize.rb +1 -8
  100. data/spec/type/relation_type/test_suppremum.rb +104 -0
  101. data/spec/type/seq_type/test_suppremum.rb +54 -0
  102. data/spec/type/set_type/test_suppremum.rb +54 -0
  103. data/spec/type/test_suppremum.rb +49 -0
  104. data/spec/type/test_unconstrained.rb +150 -0
  105. data/spec/type/tuple_type/test_suppremum.rb +119 -0
  106. data/spec/type/union_type/test_suppremum.rb +51 -0
  107. data/tasks/test.rake +1 -1
  108. metadata +230 -145
  109. data/spec/finitio/with-duplicates.fio +0 -3
  110. data/spec/type/proxy_type/test_delegation.rb +0 -37
  111. data/spec/type/proxy_type/test_resolve.rb +0 -29
@@ -0,0 +1,10 @@
1
+ module Finitio
2
+ class AdType
3
+
4
+ def generate_data(generator, world = nil)
5
+ infotype = generator.flip_one_out_of(contracts).infotype
6
+ generator.call(infotype, world)
7
+ end
8
+
9
+ end # class AliasType
10
+ end # module Finitio
@@ -0,0 +1,9 @@
1
+ module Finitio
2
+ class AliasType
3
+
4
+ def generate_data(generator, world = nil)
5
+ generator.call(target, world)
6
+ end
7
+
8
+ end # class AliasType
9
+ end # module Finitio
@@ -0,0 +1,11 @@
1
+ module Finitio
2
+ class AnyType
3
+
4
+ def generate_data(generator, world = nil)
5
+ candidates = [NilClass, String, Integer, Float]
6
+ type = generator.flip_one_out_of(candidates)
7
+ generator.heuristic.call(type, generator, world)
8
+ end
9
+
10
+ end # class AnyType
11
+ end # module Finitio
@@ -0,0 +1,9 @@
1
+ module Finitio
2
+ class BuiltinType
3
+
4
+ def generate_data(generator, world = nil)
5
+ generator.heuristic.call(ruby_type, generator, world)
6
+ end
7
+
8
+ end # class BuiltinType
9
+ end # module Finitio
@@ -0,0 +1,15 @@
1
+ module Finitio
2
+ module HashBasedType
3
+
4
+ def generate_data(generator, world = nil)
5
+ tuple = {}
6
+ heading.each do |a|
7
+ if a.required or generator.flip_coin
8
+ tuple[a.name.to_sym] = generator.call(a.type, world)
9
+ end
10
+ end
11
+ tuple
12
+ end
13
+
14
+ end # class HashBasedType
15
+ end # module Finitio
@@ -0,0 +1,8 @@
1
+ module Finitio
2
+ class Generation
3
+ class Heuristic
4
+ end # class Heuristic
5
+ end # class Generation
6
+ end # module Finitio
7
+ require_relative "heuristic/constant"
8
+ require_relative "heuristic/random"
@@ -0,0 +1,30 @@
1
+ module Finitio
2
+ class Generation
3
+ class Heuristic
4
+ class Constant < Heuristic
5
+
6
+ CONSTANTS = {
7
+ NilClass => nil,
8
+ TrueClass => true,
9
+ FalseClass => false,
10
+ Integer => 99,
11
+ Float => 99.99,
12
+ String => "Hello world",
13
+ Date => Date.today,
14
+ Time => Time.now,
15
+ DateTime => DateTime.now,
16
+ }
17
+
18
+ def call(ruby_type, generator, world = nil)
19
+ CONSTANTS.fetch(ruby_type) do
20
+ CONSTANTS.each_pair do |clazz, value|
21
+ return value if clazz >= ruby_type
22
+ end
23
+ throw :unfound
24
+ end
25
+ end
26
+
27
+ end # class Constant
28
+ end # class Heuristic
29
+ end # class Generation
30
+ end # module Finition
@@ -0,0 +1,52 @@
1
+ module Finitio
2
+ class Generation
3
+ class Heuristic
4
+ class Random < Heuristic
5
+
6
+ RANDOMERS = {
7
+ NilClass => nil,
8
+
9
+ TrueClass => true,
10
+
11
+ FalseClass => false,
12
+
13
+ Integer => ->(_,g,_) {
14
+ g.flip_one_out_of(1_000_000)
15
+ },
16
+
17
+ Float => ->(_,g,_) {
18
+ g.flip_one_out_of(1_000_000)
19
+ },
20
+
21
+ String => ->(_,g,_) {
22
+ (1..3).map{ SecureRandom.hex(6) }.join(" ")
23
+ },
24
+
25
+ Date => ->(_,g,_) {
26
+ Time.at(rand * Time.now.to_i).to_date
27
+ },
28
+
29
+ Time => ->(_,g,_) {
30
+ Time.at(rand * Time.now.to_i)
31
+ },
32
+
33
+ DateTime => ->(_,g,_) {
34
+ Time.at(rand * Time.now.to_i).to_datetime
35
+ }
36
+ }
37
+
38
+ def call(ruby_type, generator, world = nil)
39
+ r = RANDOMERS.fetch(ruby_type) do
40
+ pair = RANDOMERS.find do |clazz, value|
41
+ clazz >= ruby_type
42
+ end
43
+ throw :unfound unless pair
44
+ pair.last
45
+ end
46
+ r.is_a?(Proc) ? r.call(ruby_type, generator, world) : r
47
+ end
48
+
49
+ end # class Random
50
+ end # class Heuristic
51
+ end # class Generation
52
+ end # module Finition
@@ -0,0 +1,13 @@
1
+ module Finitio
2
+ module RelBasedType
3
+
4
+ def generate_data(generator, world = nil)
5
+ coll = []
6
+ generator.collection_size.times do
7
+ coll << generator.call(tuple_type, world)
8
+ end
9
+ coll.uniq
10
+ end
11
+
12
+ end # module RelBasedType
13
+ end # module Finitio
@@ -0,0 +1,13 @@
1
+ module Finitio
2
+ class SeqType
3
+
4
+ def generate_data(generator, world = nil)
5
+ coll = []
6
+ generator.collection_size.times do
7
+ coll << generator.call(elm_type, world)
8
+ end
9
+ coll
10
+ end
11
+
12
+ end # class SeqType
13
+ end # module Finitio
@@ -0,0 +1,13 @@
1
+ module Finitio
2
+ class SetType
3
+
4
+ def generate_data(generator, world = nil)
5
+ coll = []
6
+ generator.collection_size.times do
7
+ coll << generator.call(elm_type, world)
8
+ end
9
+ coll.uniq
10
+ end
11
+
12
+ end # class SetType
13
+ end # module Finitio
@@ -0,0 +1,9 @@
1
+ module Finitio
2
+ class SubType
3
+
4
+ def generate_data(generator, world = nil)
5
+ generator.call(super_type, world)
6
+ end
7
+
8
+ end # class SubType
9
+ end # module Finitio
@@ -0,0 +1,10 @@
1
+ module Finitio
2
+ class UnionType
3
+
4
+ def generate_data(generator, world = nil)
5
+ picked = generator.flip_one_out_of(candidates)
6
+ generator.call(picked, world)
7
+ end
8
+
9
+ end # class UnionType
10
+ end # module Finitio
@@ -0,0 +1,51 @@
1
+ module Finitio
2
+ class Inference
3
+
4
+ def initialize(system, options = {})
5
+ @system = system
6
+ @options = options
7
+ end
8
+ attr_reader :system
9
+
10
+ def call(input)
11
+ infer_type(input)
12
+ end
13
+
14
+ private
15
+
16
+ def infer_type(value)
17
+ case value
18
+ when Hash
19
+ attrs = value.map{|k,v|
20
+ Attribute.new(k.to_sym, infer_type(v))
21
+ }
22
+ heading = Heading.new(attrs)
23
+ TupleType.new(heading)
24
+ when Array
25
+ infered = value.inject(nil){|sup, value|
26
+ value_type = infer_type(value)
27
+ sup.nil? ? value_type : sup.suppremum(value_type)
28
+ }
29
+ SeqType.new(infered.nil? ? ANY_TYPE : infered)
30
+ else
31
+ found = self.system.types.values.find{|t|
32
+ try_dress(t, value)
33
+ }
34
+ found ? found : ANY_TYPE
35
+ end
36
+ end
37
+
38
+ def try_dress(t, value)
39
+ raise "Type expected, got #{t}" unless t.is_a?(Type)
40
+ t.dress(value)
41
+ true
42
+ rescue Finitio::Error => ex
43
+ #puts %Q{[#{ex.class}] #{ex.message}}
44
+ nil
45
+ rescue => ex
46
+ puts %Q{[#{ex.class}] #{ex.message}\n#{ex.backtrace.join("\n")}}
47
+ nil
48
+ end
49
+
50
+ end # class Inference
51
+ end # module Finitio
@@ -0,0 +1,16 @@
1
+ module Finitio
2
+ module JsonSchema
3
+ class Error < Finitio::Error; end
4
+ end # module JsonSchema
5
+ end # module Finitio
6
+ require_relative 'json_schema/ad_type'
7
+ require_relative 'json_schema/any_type'
8
+ require_relative 'json_schema/alias_type'
9
+ require_relative 'json_schema/builtin_type'
10
+ require_relative 'json_schema/hash_based_type'
11
+ require_relative 'json_schema/rel_based_type'
12
+ require_relative 'json_schema/seq_type'
13
+ require_relative 'json_schema/set_type'
14
+ require_relative 'json_schema/struct_type'
15
+ require_relative 'json_schema/sub_type'
16
+ require_relative 'json_schema/union_type'
@@ -0,0 +1,11 @@
1
+ module Finitio
2
+ class AdType
3
+
4
+ def to_json_schema(*args, &bl)
5
+ {
6
+ anyOf: contracts.map{|c| c.infotype.to_json_schema(*args, &bl) }
7
+ }
8
+ end
9
+
10
+ end # class AdType
11
+ end # module Finitio
@@ -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