finitio 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1be4c866c9b4cc67fddb28b39ef618897013cd29
4
- data.tar.gz: 51d2f530a4be64de2a3f9a075e5ff536775454ac
2
+ SHA256:
3
+ metadata.gz: 467a7c5d8dd70fe9b5de2154217a5594182150d6e9c9996ec85c861980c02ecc
4
+ data.tar.gz: cadb1b56c039b7a88456f803733d9c0da9f7d879393674de0fc067c2fb71679b
5
5
  SHA512:
6
- metadata.gz: 9024a94cb06ec0df550904d8b1b2029b0e54956a48d54a95ada3ca9a679fd6314278c2ae6bd524ae6ff171a71f6ec6928cb5bfda0a54cda40ddac07168770308
7
- data.tar.gz: 3d2eee7016ee732383c1deb0ec202c8c2346eb5a3c2610dd1788d2dc6361c30e46a6438f96144822ff991e883cfdb0c03eb50bd7e8e6777724be91345cc6063b
6
+ metadata.gz: 4606b1f8de1df5a7712f8c6546252683928066a18e5e2ed91a96af2e68be552f66e3ccea26d8b6760e9ac5c073fffa416f06ae0ca8001bbac5ca4f2532469f1e
7
+ data.tar.gz: 1d9436c52479abab152422d471b559724e72ea7d933ec8538cf2877e1fa14bebccfc6219dcf662c76758d167653cf47fe10b0332ee2cc118b6e18229826d5eed
@@ -1,3 +1,13 @@
1
+ # 0.8.0 - 2019/10/21
2
+
3
+ * Add `Type#unconstrained` that returns a super type with all user specific
4
+ constraints removed on sub types, recursively on all non scalar types.
5
+
6
+ * Add high-order types, such as `Collection<T> = [T]`
7
+
8
+ * Add support for random data generation through `Finitio::Generation`.
9
+ Please `require 'finitio/generation'` to use it.
10
+
1
11
  # 0.7.0 / 2019-02-28
2
12
 
3
13
  * Implement (basic) @import feature, working with relative paths
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'http://rubygems.org'
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
@@ -1,59 +1,58 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- finitio (0.7.0)
4
+ finitio (0.8.0)
5
5
  citrus (>= 2.4, < 4.0)
6
6
 
7
7
  GEM
8
- remote: http://rubygems.org/
8
+ remote: https://rubygems.org/
9
9
  specs:
10
- awesome_print (1.6.1)
11
- builder (3.2.2)
10
+ awesome_print (1.8.0)
11
+ builder (3.2.3)
12
12
  citrus (3.0.2)
13
- coveralls (0.7.2)
14
- multi_json (~> 1.3)
15
- rest-client (= 1.6.7)
16
- simplecov (>= 0.7)
17
- term-ansicolor (= 1.2.2)
18
- thor (= 0.18.1)
19
- cucumber (1.3.18)
13
+ coveralls (0.8.23)
14
+ json (>= 1.8, < 3)
15
+ simplecov (~> 0.16.1)
16
+ term-ansicolor (~> 1.3)
17
+ thor (>= 0.19.4, < 2.0)
18
+ tins (~> 1.6)
19
+ cucumber (1.3.20)
20
20
  builder (>= 2.1.2)
21
21
  diff-lcs (>= 1.1.3)
22
22
  gherkin (~> 2.12)
23
23
  multi_json (>= 1.7.5, < 2.0)
24
- multi_test (>= 0.1.1)
25
- diff-lcs (1.2.5)
26
- docile (1.1.5)
24
+ multi_test (>= 0.1.2)
25
+ diff-lcs (1.3)
26
+ docile (1.3.1)
27
27
  gherkin (2.12.2)
28
28
  multi_json (~> 1.3)
29
- mime-types (2.4.3)
30
- multi_json (1.10.1)
31
- multi_test (0.1.1)
29
+ json (2.2.0)
30
+ multi_json (1.13.1)
31
+ multi_test (0.1.2)
32
32
  path (1.3.3)
33
- rake (10.4.2)
34
- rest-client (1.6.7)
35
- mime-types (>= 1.16)
36
- rspec (3.1.0)
37
- rspec-core (~> 3.1.0)
38
- rspec-expectations (~> 3.1.0)
39
- rspec-mocks (~> 3.1.0)
40
- rspec-core (3.1.7)
41
- rspec-support (~> 3.1.0)
42
- rspec-expectations (3.1.2)
33
+ rake (10.5.0)
34
+ rspec (3.8.0)
35
+ rspec-core (~> 3.8.0)
36
+ rspec-expectations (~> 3.8.0)
37
+ rspec-mocks (~> 3.8.0)
38
+ rspec-core (3.8.0)
39
+ rspec-support (~> 3.8.0)
40
+ rspec-expectations (3.8.3)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.8.0)
43
+ rspec-mocks (3.8.0)
43
44
  diff-lcs (>= 1.2.0, < 2.0)
44
- rspec-support (~> 3.1.0)
45
- rspec-mocks (3.1.3)
46
- rspec-support (~> 3.1.0)
47
- rspec-support (3.1.2)
48
- simplecov (0.9.1)
49
- docile (~> 1.1.0)
50
- multi_json (~> 1.0)
51
- simplecov-html (~> 0.8.0)
52
- simplecov-html (0.8.0)
53
- term-ansicolor (1.2.2)
54
- tins (~> 0.8)
55
- thor (0.18.1)
56
- tins (0.13.2)
45
+ rspec-support (~> 3.8.0)
46
+ rspec-support (3.8.0)
47
+ simplecov (0.16.1)
48
+ docile (~> 1.1)
49
+ json (>= 1.8, < 3)
50
+ simplecov-html (~> 0.10.0)
51
+ simplecov-html (0.10.2)
52
+ term-ansicolor (1.7.1)
53
+ tins (~> 1.0)
54
+ thor (0.20.3)
55
+ tins (1.20.2)
57
56
 
58
57
  PLATFORMS
59
58
  ruby
@@ -68,4 +67,4 @@ DEPENDENCIES
68
67
  rspec (~> 3.0)
69
68
 
70
69
  BUNDLED WITH
71
- 1.16.0
70
+ 2.0.1
@@ -0,0 +1,106 @@
1
+ require 'securerandom'
2
+ require_relative 'generation/heuristic'
3
+ module Finitio
4
+ #
5
+ # This class helps generating random data for a given Finitio type.
6
+ #
7
+ # Example
8
+ #
9
+ # type = Finitio.system(<<-FIO)
10
+ # .Integer
11
+ # FIO
12
+ # gen = Finitio::Generation.new
13
+ # gen.call(type)
14
+ #
15
+ # Random data is generated for most ruby builtin types, tuples and all sorts
16
+ # of collections (seq, set, relations).
17
+ #
18
+ # You can fine-tune the random data generation through the following means
19
+ # (the first one wins):
20
+ #
21
+ # * By passing generators by type name at construction:
22
+ #
23
+ # Finition::Generation.new({
24
+ # generators: {
25
+ # "Name" => ->(type, g, world) { "Bernard" }
26
+ # }
27
+ # })
28
+ #
29
+ # * Through `examples` metadata put on type definitions:
30
+ #
31
+ # /- examples: {"Bernard"} -/
32
+ # Name = .String
33
+ #
34
+ class Generation
35
+
36
+ DEFAULT_OPTIONS = {
37
+
38
+ heuristic: Heuristic::Random.new,
39
+
40
+ collection_size: 1..10,
41
+
42
+ generators: {
43
+ "Date" => ->(t,g,w) { g.heuristic.call(Date, g, w) },
44
+ "Time" => ->(t,g,w) { g.heuristic.call(Time, g, w) },
45
+ "DateTime" => ->(t,g,w) { g.heuristic.call(DateTime, g, w) }
46
+ }
47
+
48
+ }
49
+
50
+ def initialize(options = {})
51
+ @options = DEFAULT_OPTIONS.merge(options){|k,v1,v2|
52
+ v1.is_a?(Hash) ? v1.merge(v2) : v2
53
+ }
54
+ end
55
+ attr_reader :options
56
+
57
+ def heuristic
58
+ options[:heuristic]
59
+ end
60
+
61
+ def generators
62
+ options[:generators]
63
+ end
64
+
65
+ def flip_coin
66
+ flip_one_out_of(2) == 1
67
+ end
68
+
69
+ def flip_one_out_of(n)
70
+ case n
71
+ when Integer then Kernel.rand(n)
72
+ when Range then Kernel.rand(n)
73
+ when Enumerable then n[flip_one_out_of(n.size)]
74
+ else
75
+ raise "Cannot flip one on #{n}"
76
+ end
77
+ end
78
+
79
+ def collection_size
80
+ size = options[:collection_size]
81
+ size = size.is_a?(Proc) ? size.call : size
82
+ flip_one_out_of(size)
83
+ end
84
+
85
+ def call(type, world = nil)
86
+ if gen = generators[type.name]
87
+ gen.call(type, self, world)
88
+ elsif exs = type.metadata && type.metadata[:examples]
89
+ flip_one_out_of(exs)
90
+ else
91
+ type.generate_data(self, world)
92
+ end
93
+ end
94
+
95
+ end # class Generation
96
+ end # module Finitio
97
+ require_relative 'generation/any_type'
98
+ require_relative 'generation/builtin_type'
99
+ require_relative 'generation/seq_type'
100
+ require_relative 'generation/set_type'
101
+ require_relative 'generation/hash_based_type'
102
+ require_relative 'generation/rel_based_type'
103
+ require_relative 'generation/union_type'
104
+ require_relative 'generation/alias_type'
105
+ require_relative 'generation/sub_type'
106
+ require_relative 'generation/ad_type'
@@ -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