diff --git a/lib/finitio/generation/proxy_type.rb b/lib/finitio/generation/proxy_type.rb new file mode 100644 index 0000000..e8bc3d6 --- /dev/null +++ b/lib/finitio/generation/proxy_type.rb @@ -0,0 +1,9 @@ +module Finitio + class ProxyType + + def generate_data(*args, &bl) + @target&.generate_data(*args, &bl) + end + + end # class ProxyType +end # module Finitio diff --git a/lib/finitio/json_schema/hash_based_type.rb b/lib/finitio/json_schema/hash_based_type.rb index 894c8a0..8ef2df7 100644 --- a/lib/finitio/json_schema/hash_based_type.rb +++ b/lib/finitio/json_schema/hash_based_type.rb @@ -7,7 +7,7 @@ def to_json_schema(*args, &bl) } unless heading.empty? base[:properties] = heading.inject({}){|ps,a| - ps.merge(a.name => a.type.to_json_schema(*args, &bl)) + ps.merge(a.name => a.type.to_json_schema(*args, &bl)) } end unless (reqs = heading.select{|a| a.required? }).empty? diff --git a/lib/finitio/support.rb b/lib/finitio/support.rb index 50dfb9a..ee4fc87 100644 --- a/lib/finitio/support.rb +++ b/lib/finitio/support.rb @@ -24,4 +24,5 @@ def compare_attrs(h1, h2, &bl) require_relative 'support/dress_helper' require_relative 'support/type_factory' require_relative 'support/fetch_scope' +require_relative 'support/proxy_resolution_scope' require_relative 'support/compilation' diff --git a/lib/finitio/support/proxy_resolution_scope.rb b/lib/finitio/support/proxy_resolution_scope.rb new file mode 100644 index 0000000..51c2567 --- /dev/null +++ b/lib/finitio/support/proxy_resolution_scope.rb @@ -0,0 +1,31 @@ +module Finitio + class ProxyResolutionScope + def initialize(system) + @system = system + @built = {} + @building = {} + end + attr_reader :built + + def fetch(name) + @built[name] || build_it(name) || import_it(name, &bl) + end + + def build_it(name) + if under_build = @building[name] + under_build + else + return nil unless type = @system.fetch(name, false) + + @building[name] = type + @built[name] = type.resolve_proxies(self) + @building[name] = nil + @built[name] + end + end + + def import_it(name, &bl) + @system.fetch_on_imports(name, &bl) + end + end # class ProxyResolutionScope +end # module Finitio diff --git a/lib/finitio/system.rb b/lib/finitio/system.rb index 49abc11..3cd9652 100644 --- a/lib/finitio/system.rb +++ b/lib/finitio/system.rb @@ -50,24 +50,23 @@ def main def fetch(name, with_imports = true, &bl) if with_imports @types.fetch(name) do - _fetch(name, @imports, &bl) + fetch_on_imports(name, &bl) end else @types.fetch(name, &bl) end end - def _fetch(name, imports, &bl) + def fetch_on_imports(name, imports = @imports, &bl) if imports.empty? raise KeyError, %Q{key not found: "#{name}"} unless bl bl.call(name) else imports.first.fetch(name, false) do - _fetch(name, imports[1..-1], &bl) + fetch_on_imports(name, imports[1..-1], &bl) end end end - private :_fetch def factory @factory ||= TypeFactory.new @@ -89,14 +88,12 @@ def parse(source) Syntax.compile(source, self.dup) end - def resolve_proxies(recurse = true) - rebuilt = {} - scope = FetchScope.new(self, rebuilt) - types.each_with_object(rebuilt) do |(name,type),memo| - rebuilt[name] = type.resolve_proxies(scope) + def resolve_proxies + scope = ProxyResolutionScope.new(self) + types.each_key do |name| + scope.fetch(name) end - resolved = System.new(rebuilt, imports) - recurse ? resolved.resolve_proxies(false) : resolved + System.new(scope.built, imports) end def inspect diff --git a/lib/finitio/type/proxy_type.rb b/lib/finitio/type/proxy_type.rb index c434fd7..50f2b8a 100644 --- a/lib/finitio/type/proxy_type.rb +++ b/lib/finitio/type/proxy_type.rb @@ -16,7 +16,7 @@ def default_name end def resolve_proxies(system) - system.fetch(target_name){ + system.fetch(target_name) { raise Error, "No such type `#{target_name}` in #{system}" } end diff --git a/spec/json_schema/test_recursive_type.rb b/spec/json_schema/test_recursive_type.rb index 93e3f9b..f491f48 100644 --- a/spec/json_schema/test_recursive_type.rb +++ b/spec/json_schema/test_recursive_type.rb @@ -15,7 +15,7 @@ module JsonSchema system['Tree'] } - xit 'works as expected' do + it 'works as expected' do expect(type.to_json_schema).to eql({ type: "object", properties: { diff --git a/spec/syntax/test_compile.rb b/spec/syntax/test_compile.rb index af43331..fe09f74 100644 --- a/spec/syntax/test_compile.rb +++ b/spec/syntax/test_compile.rb @@ -77,6 +77,24 @@ module Finitio end context 'with AD types' do + let(:source){ + <<-EOF.strip + Int = .Integer + Byte = Int(i | i>0) + Color = .Color { r: Byte, g: Byte, b: Byte } + Colors = [Color] + EOF + } + + it{ should be_a(System) } + + it 'should work fine' do + got = subject['Colors'].dress([{ r: 10, g: 15, b: 20 }]) + expect(got.first).to be_a(Color) + end + end + + context 'with AD types that make forward references' do let(:source){ <<-EOF.strip Colors = [Color] @@ -88,7 +106,7 @@ module Finitio it{ should be_a(System) } - it 'should work ine' do + it 'should work fine' do got = subject['Colors'].dress([{ r: 10, g: 15, b: 20 }]) expect(got.first).to be_a(Color) end