finitio 0.11.3 → 0.11.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: acf74d5293b979c7c03d55dc9cbea273b9f85d6c
4
- data.tar.gz: 14e18b10f4668fc996354ec2ceb6627eb56dffbc
3
+ metadata.gz: 29fd883abee1e98b436a1c8aa80ee32ffc9740dc
4
+ data.tar.gz: 9aa135c687855dbdfb6a52e245d21c3488ef0128
5
5
  SHA512:
6
- metadata.gz: ba3a092904c8ac102361ef17b2fc0f49d8f6ed209d2a3ffe0ec852f3c3b52772716762bf65d3604831a631f2ecc8782cdaa120b7768608849ec72bdbc164f8d2
7
- data.tar.gz: a33d566ed9e25caed8b90d7228583056152ee1fb0c50533fad4008ab72d318fd3d51430f1f50146f42c77104f6fad40c86591200e168cce14de05d46995e228d
6
+ metadata.gz: 0af6653c37bc1fdb2e5aeef7f0d43e70f92d967658219b638c58a8039b975460f64ab80339d7d727aed716175cc722614973e387c5720315868bd6b8a6d1fc7c
7
+ data.tar.gz: ef96c4bd3a7f4910b83acab224940afe7a1885be98eeddf5ce8542c0037d0c702da98e372f55a42638cb7cef3cfbf9394dd8c0d162daace35c6731e86083c061
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 0.11.4 - 2023/01/06
2
+
3
+ * The proxy resolution is fixed and clarified. When compiling
4
+ a system, all proxies are actually replaced by their actual
5
+ Type instance. Only recursive types still keep ProxyType
6
+ instances (as sentinels) ; they are bound to their target
7
+ type and delete dress and include? to them.
8
+
9
+ Given that ProxyType is a sentinel on recursive types, calls
10
+ to generate_data and to_json_schema are not delegated to the
11
+ target type, to avoid infinite recursions.
12
+
13
+ * Generated names of instantiated high order types are better
14
+ (e.g. Collection<String>).
15
+
1
16
  # 0.11.3 - 2023/01/06
2
17
 
3
18
  * Fix json_schema generation on unresolved ProxyTypes. We use
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- finitio (0.11.3)
4
+ finitio (0.11.4)
5
5
  citrus (>= 3.0, < 4.0)
6
6
 
7
7
  GEM
@@ -0,0 +1,11 @@
1
+ module Finitio
2
+ class ProxyType
3
+
4
+ def generate_data(*args, &bl)
5
+ # Proxy type is supposed to be used only on recursive types
6
+ # so we can't go further to avoid a infinite recursion
7
+ {}
8
+ end
9
+
10
+ end # class ProxyType
11
+ end # module Finitio
@@ -104,3 +104,4 @@ require_relative 'generation/union_type'
104
104
  require_relative 'generation/alias_type'
105
105
  require_relative 'generation/sub_type'
106
106
  require_relative 'generation/ad_type'
107
+ require_relative 'generation/proxy_type'
@@ -7,7 +7,7 @@ module Finitio
7
7
  }
8
8
  unless heading.empty?
9
9
  base[:properties] = heading.inject({}){|ps,a|
10
- ps.merge(a.name => a.type.to_json_schema(*args, &bl))
10
+ ps.merge(a.name => a.type.to_json_schema(*args, &bl))
11
11
  }
12
12
  end
13
13
  unless (reqs = heading.select{|a| a.required? }).empty?
@@ -2,11 +2,10 @@ module Finitio
2
2
  class ProxyType
3
3
 
4
4
  def to_json_schema(*args, &bl)
5
- if @target
6
- @target.to_json_schema(*args, &bl)
7
- else
8
- "object"
9
- end
5
+ # ProxyType is supposed to be used only for recursive types.
6
+ # We don't have support for references yet, so let just
7
+ # generate an object here in the mean time.
8
+ { type: "object" }
10
9
  end
11
10
 
12
11
  end # module ProxyType
@@ -48,10 +48,6 @@ module Finitio
48
48
  Pathname.new(file)
49
49
  end
50
50
 
51
- def resolve_proxies
52
- system.resolve_proxies
53
- end
54
-
55
51
  # Delegation to Factory
56
52
 
57
53
  TypeFactory::DSL_METHODS.each do |dsl_method|
@@ -0,0 +1,52 @@
1
+ module Finitio
2
+ # Part of the compilation schema, this proxy resolver replaces
3
+ # proxies by their real Type instance.
4
+ #
5
+ # Given that Finitio can support recursive types, we do this in
6
+ # two passes:
7
+ # 1. Replace proxy types by rewrite (see Type#resolve_proxies)
8
+ # in a depth first search.
9
+ # 2. If a loop is found, recreate a late ProxyType, that is then
10
+ # bound later by mutation.
11
+ #
12
+ # So ProxyType may still be present in the type chain, but will
13
+ # only correspond to recursive types.
14
+ class ProxyResolver
15
+ def resolve!(system)
16
+ @system = system
17
+ @built = {}
18
+ @building = {}
19
+ @late_proxies = []
20
+ system.types.each_key do |name|
21
+ fetch(name)
22
+ end
23
+ @late_proxies.each do |proxy|
24
+ proxy.bind!(self)
25
+ end
26
+ system.dup(@built)
27
+ end
28
+
29
+ def fetch(name, &bl)
30
+ @built[name] || build_it(name) || import_it(name, &bl)
31
+ end
32
+
33
+ def build_it(name)
34
+ if under_build = @building[name]
35
+ proxy = ProxyType.new(name)
36
+ @late_proxies << proxy
37
+ proxy
38
+ else
39
+ return nil unless type = @system.fetch(name, false){ nil }
40
+
41
+ @building[name] = type
42
+ @built[name] = type.resolve_proxies(self)
43
+ @building[name] = nil
44
+ @built[name]
45
+ end
46
+ end
47
+
48
+ def import_it(name, &bl)
49
+ @system.fetch_on_imports(name, &bl)
50
+ end
51
+ end # class ProxyResolver
52
+ end # module Finitio
@@ -24,4 +24,5 @@ require_relative 'support/heading'
24
24
  require_relative 'support/dress_helper'
25
25
  require_relative 'support/type_factory'
26
26
  require_relative 'support/fetch_scope'
27
+ require_relative 'support/proxy_resolver'
27
28
  require_relative 'support/compilation'
@@ -21,18 +21,18 @@ module Finitio
21
21
  end
22
22
 
23
23
  def self.ast(source)
24
- parse(source, root: "system").to_ast
24
+ parse(source, root: 'system').to_ast
25
25
  end
26
26
 
27
27
  def self.compile(source, cpl = nil)
28
28
  cpl = Compilation.coerce(cpl, source)
29
- parse(source, root: "system").compile(cpl)
30
- cpl.resolve_proxies
29
+ parse(source, root: 'system').compile(cpl)
30
+ ProxyResolver.new.resolve!(cpl.system)
31
31
  end
32
32
 
33
33
  def self.compile_type(source, cpl = nil)
34
34
  cpl = Compilation.coerce(cpl, source)
35
- parse(source, root: "type").compile(cpl)
35
+ parse(source, root: 'type').compile(cpl)
36
36
  end
37
37
 
38
38
  end # module Syntax
@@ -50,24 +50,23 @@ module Finitio
50
50
  def fetch(name, with_imports = true, &bl)
51
51
  if with_imports
52
52
  @types.fetch(name) do
53
- _fetch(name, @imports, &bl)
53
+ fetch_on_imports(name, &bl)
54
54
  end
55
55
  else
56
56
  @types.fetch(name, &bl)
57
57
  end
58
58
  end
59
59
 
60
- def _fetch(name, imports, &bl)
60
+ def fetch_on_imports(name, imports = @imports, &bl)
61
61
  if imports.empty?
62
62
  raise KeyError, %Q{key not found: "#{name}"} unless bl
63
63
  bl.call(name)
64
64
  else
65
65
  imports.first.fetch(name, false) do
66
- _fetch(name, imports[1..-1], &bl)
66
+ fetch_on_imports(name, imports[1..-1], &bl)
67
67
  end
68
68
  end
69
69
  end
70
- private :_fetch
71
70
 
72
71
  def factory
73
72
  @factory ||= TypeFactory.new
@@ -89,22 +88,12 @@ module Finitio
89
88
  Syntax.compile(source, self.dup)
90
89
  end
91
90
 
92
- def resolve_proxies(recurse = true)
93
- rebuilt = {}
94
- scope = FetchScope.new(self, rebuilt)
95
- types.each_with_object(rebuilt) do |(name,type),memo|
96
- rebuilt[name] = type.resolve_proxies(scope)
97
- end
98
- resolved = System.new(rebuilt, imports)
99
- recurse ? resolved.resolve_proxies(false) : resolved
100
- end
101
-
102
91
  def inspect
103
92
  @types.each_pair.map{|k,v| "#{k} = #{v}" }.join("\n")
104
93
  end
105
94
 
106
- def dup
107
- System.new(@types.dup, @imports.dup)
95
+ def dup(types = @types.dup, imports = @imports.dup)
96
+ System.new(types, imports)
108
97
  end
109
98
 
110
99
  def check_and_warn(logger = nil)
@@ -28,7 +28,9 @@ module Finitio
28
28
 
29
29
  def instantiate(compilation, sub_types)
30
30
  overrides = Hash[vars.zip(sub_types)]
31
- defn.resolve_proxies(compilation.with_scope(overrides))
31
+ defn.resolve_proxies(compilation.with_scope(overrides)).dup.tap{|x|
32
+ x.send(:name=, "#{name}<#{overrides.values.join(',')}>", true)
33
+ }
32
34
  end
33
35
 
34
36
  def unconstrained
@@ -15,8 +15,26 @@ module Finitio
15
15
  "_#{target_name}_"
16
16
  end
17
17
 
18
+ def include?(*args, &bl)
19
+ raise Error, "Proxy not resolved: #{target_name}" unless @target
20
+
21
+ @target.include?(*args, &bl)
22
+ end
23
+
24
+ def dress(*args, &bl)
25
+ raise Error, "Proxy not resolved: #{target_name}" unless @target
26
+
27
+ @target.dress(*args, &bl)
28
+ end
29
+
30
+ def bind!(system)
31
+ @target = system.fetch(target_name) {
32
+ raise Error, "No such type `#{target_name}` in #{system}"
33
+ }
34
+ end
35
+
18
36
  def resolve_proxies(system)
19
- system.fetch(target_name){
37
+ system.fetch(target_name) {
20
38
  raise Error, "No such type `#{target_name}` in #{system}"
21
39
  }
22
40
  end
data/lib/finitio/type.rb CHANGED
@@ -32,8 +32,10 @@ module Finitio
32
32
  @name || default_name
33
33
  end
34
34
 
35
- def name=(n)
36
- raise Error, "Name already set to `#{@name}`" unless @name.nil?
35
+ def name=(n, force = false)
36
+ if !@name.nil? && !force
37
+ raise Error, "Name already set to `#{@name}` on #{self.class}"
38
+ end
37
39
  @name = n
38
40
  end
39
41
 
@@ -3,7 +3,7 @@ module Finitio
3
3
 
4
4
  MAJOR = 0
5
5
  MINOR = 11
6
- TINY = 3
6
+ TINY = 4
7
7
 
8
8
  def self.to_s
9
9
  [ MAJOR, MINOR, TINY ].join('.')
@@ -35,7 +35,7 @@ module Finitio
35
35
  expect(result.elm_type[:size].type.name).to eql("String")
36
36
  expect(result.elm_type[:priority].type.name).to eql("String")
37
37
 
38
- puts result
38
+ #puts result
39
39
  end
40
40
 
41
41
  end
@@ -15,24 +15,14 @@ module Finitio
15
15
  system['Tree']
16
16
  }
17
17
 
18
- xit 'works as expected' do
18
+ it 'works as expected' do
19
19
  expect(type.to_json_schema).to eql({
20
20
  type: "object",
21
21
  properties: {
22
22
  children: {
23
23
  type: "array",
24
24
  items: {
25
- type: "object",
26
- properties: {
27
- children: {
28
- type: "array",
29
- items: "object"
30
- }
31
- },
32
- required: [
33
- :children
34
- ],
35
- additionalProperties: false
25
+ type: "object"
36
26
  }
37
27
  }
38
28
  },
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Dress on a recursive type" do
4
+ let(:schema){
5
+ Finitio.system <<~F
6
+ Tree = {
7
+ children: [Tree]
8
+ }
9
+ Tree
10
+ F
11
+ }
12
+
13
+ it 'works on an empty tree' do
14
+ expect(->(){
15
+ schema.dress({children: []})
16
+ }).not_to raise_error
17
+ end
18
+
19
+ it 'works on a non empty tree' do
20
+ expect(->(){
21
+ schema.dress({
22
+ children: [{
23
+ children: [{
24
+ children: [{
25
+ children: []
26
+ }]
27
+ }]
28
+ }]
29
+ })
30
+ }).not_to raise_error
31
+ end
32
+
33
+ it 'detects deep error' do
34
+ expect(->(){
35
+ schema.dress({
36
+ children: [{
37
+ children: [{
38
+ children: [{
39
+ children: [{
40
+ children: [{
41
+ children: [{
42
+ unrecognized: true,
43
+ children: []
44
+ }]
45
+ }]
46
+ }]
47
+ }]
48
+ }]
49
+ }]
50
+ })
51
+ }).to raise_error(Finitio::Error)
52
+ end
53
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe "The types of generics definitions" do
4
+ describe "When the extra map to a type" do
5
+ let(:schema){
6
+ Finitio.system <<~F
7
+ Collection<T> = [T]
8
+
9
+ String = .String
10
+ Collection<String>
11
+ F
12
+ }
13
+
14
+ it 'works' do
15
+ expect(schema['Main'].target.name).to eql("Collection<String>")
16
+ end
17
+ end
18
+ end
@@ -77,6 +77,24 @@ module Finitio
77
77
  end
78
78
 
79
79
  context 'with AD types' do
80
+ let(:source){
81
+ <<-EOF.strip
82
+ Int = .Integer
83
+ Byte = Int(i | i>0)
84
+ Color = .Color <rgb> { r: Byte, g: Byte, b: Byte }
85
+ Colors = [Color]
86
+ EOF
87
+ }
88
+
89
+ it{ should be_a(System) }
90
+
91
+ it 'should work fine' 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
+
97
+ context 'with AD types that make forward references' do
80
98
  let(:source){
81
99
  <<-EOF.strip
82
100
  Colors = [Color]
@@ -88,7 +106,7 @@ module Finitio
88
106
 
89
107
  it{ should be_a(System) }
90
108
 
91
- it 'should work ine' do
109
+ it 'should work fine' do
92
110
  got = subject['Colors'].dress([{ r: 10, g: 15, b: 20 }])
93
111
  expect(got.first).to be_a(Color)
94
112
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: finitio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.3
4
+ version: 0.11.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-06 00:00:00.000000000 Z
11
+ date: 2023-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: citrus
@@ -163,6 +163,7 @@ files:
163
163
  - lib/finitio/generation/heuristic.rb
164
164
  - lib/finitio/generation/heuristic/constant.rb
165
165
  - lib/finitio/generation/heuristic/random.rb
166
+ - lib/finitio/generation/proxy_type.rb
166
167
  - lib/finitio/generation/rel_based_type.rb
167
168
  - lib/finitio/generation/seq_type.rb
168
169
  - lib/finitio/generation/set_type.rb
@@ -193,6 +194,7 @@ files:
193
194
  - lib/finitio/support/heading.rb
194
195
  - lib/finitio/support/metadata.rb
195
196
  - lib/finitio/support/proc_with_code.rb
197
+ - lib/finitio/support/proxy_resolver.rb
196
198
  - lib/finitio/support/type_factory.rb
197
199
  - lib/finitio/syntax.rb
198
200
  - lib/finitio/syntax/definitions.rb
@@ -317,7 +319,9 @@ files:
317
319
  - spec/json_schema/test_sub_type.rb
318
320
  - spec/json_schema/test_tuple_type.rb
319
321
  - spec/json_schema/test_union_type.rb
322
+ - spec/regression/test_dress_on_recursive_type.rb
320
323
  - spec/regression/test_heading_extra_are_proxy_resolved.rb
324
+ - spec/regression/test_name_of_generic_types.rb
321
325
  - spec/spec_helper.rb
322
326
  - spec/support/test_compare_attrs.rb
323
327
  - spec/support/test_proc_with_code.rb
@@ -488,6 +492,8 @@ signing_key:
488
492
  specification_version: 4
489
493
  summary: Finitio - in Ruby
490
494
  test_files:
495
+ - spec/regression/test_dress_on_recursive_type.rb
496
+ - spec/regression/test_name_of_generic_types.rb
491
497
  - spec/regression/test_heading_extra_are_proxy_resolved.rb
492
498
  - spec/test_finitio.rb
493
499
  - spec/constraint/test_named.rb