finitio 0.11.3 → 0.11.4

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.
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