rom 0.6.0.beta3 → 0.6.0.rc1
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 +4 -4
- data/.gitignore +1 -2
- data/CHANGELOG.md +2 -1
- data/Gemfile +1 -1
- data/lib/rom.rb +0 -2
- data/lib/rom/commands/abstract.rb +1 -1
- data/lib/rom/env.rb +9 -7
- data/lib/rom/memory/storage.rb +6 -1
- data/lib/rom/relation.rb +14 -134
- data/lib/rom/relation/class_interface.rb +180 -0
- data/lib/rom/relation/lazy.rb +1 -1
- data/lib/rom/relation/registry_reader.rb +1 -1
- data/lib/rom/setup/finalize.rb +1 -21
- data/lib/rom/version.rb +1 -1
- data/rakelib/benchmark.rake +3 -1
- data/rom.gemspec +2 -2
- data/spec/integration/mappers/deep_embedded_spec.rb +1 -1
- data/spec/integration/mappers/definition_dsl_spec.rb +8 -6
- data/spec/integration/mappers/embedded_spec.rb +2 -6
- data/spec/integration/mappers/group_spec.rb +4 -4
- data/spec/integration/mappers/prefixing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/renaming_attributes_spec.rb +5 -3
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +2 -2
- data/spec/integration/mappers/wrap_spec.rb +4 -4
- data/spec/integration/multi_repo_spec.rb +5 -1
- data/spec/integration/relations/reading_spec.rb +6 -14
- data/spec/integration/setup_spec.rb +3 -3
- data/spec/unit/rom/env_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy_spec.rb +16 -4
- data/spec/unit/rom/setup_spec.rb +2 -2
- metadata +9 -4
- data/lib/rom/reader.rb +0 -174
- data/spec/unit/rom/reader_spec.rb +0 -146
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 0ea7e1a611937b1db33e9bb5f6495c116ff163bd
         | 
| 4 | 
            +
              data.tar.gz: 98243b1e80fc05db0038fdeea7465a7b913990f8
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: fde6f6d9efc44fe43c2bffefdfcf809e6f7d3991a4059185ac58909c3455c3e821dda71843503c3a4c31f36178eaff0454ef48c2d71c4ae1106beb30f95623c0
         | 
| 7 | 
            +
              data.tar.gz: 1fa7191e19578e32cfc72c71db3eeebb7a28a7410dd98db8064af3f19f85bfa19e7397f22d46c86eaf42013943a91cc7f754f89fd2f62e96f6de12737fc7e7c9
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -20,8 +20,9 @@ | |
| 20 20 |  | 
| 21 21 | 
             
            ### Changed
         | 
| 22 22 |  | 
| 23 | 
            -
            * [BREAKING] Command API was simplified - commands should be accessed directly in `.try` block (solnic)
         | 
| 24 23 | 
             
            * [BREAKING] Schema DSL was **removed** - attributes can be specified only in mapper DSL
         | 
| 24 | 
            +
            * [BREAKING] Reader was **removed** in favor of relation interface with explicit mapping (solnic)
         | 
| 25 | 
            +
            * [BREAKING] Command API was simplified - commands should be accessed directly in `.try` block (solnic)
         | 
| 25 26 | 
             
              and default repository can be changed when defining a relation (solnic)
         | 
| 26 27 | 
             
            * `.setup` interface requires either an adapter identifier or can accept a repository
         | 
| 27 28 | 
             
              instance (aflatter)
         | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/lib/rom.rb
    CHANGED
    
    | @@ -13,7 +13,6 @@ require 'rom/support/class_builder' | |
| 13 13 | 
             
            # core parts
         | 
| 14 14 | 
             
            require 'rom/relation'
         | 
| 15 15 | 
             
            require 'rom/mapper'
         | 
| 16 | 
            -
            require 'rom/reader'
         | 
| 17 16 | 
             
            require 'rom/command'
         | 
| 18 17 |  | 
| 19 18 | 
             
            # default mapper processor using Transproc gem
         | 
| @@ -33,5 +32,4 @@ module ROM | |
| 33 32 | 
             
              extend Global
         | 
| 34 33 |  | 
| 35 34 | 
             
              RelationRegistry = Class.new(Registry)
         | 
| 36 | 
            -
              ReaderRegistry = Class.new(Registry)
         | 
| 37 35 | 
             
            end
         | 
    
        data/lib/rom/env.rb
    CHANGED
    
    | @@ -88,15 +88,17 @@ module ROM | |
| 88 88 | 
             
                #
         | 
| 89 89 | 
             
                # @param [Symbol] name of the registered reader
         | 
| 90 90 | 
             
                #
         | 
| 91 | 
            +
                # @deprecated
         | 
| 92 | 
            +
                #
         | 
| 91 93 | 
             
                # @api public
         | 
| 92 94 | 
             
                def read(name, &block)
         | 
| 93 | 
            -
                   | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
                     | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
                   | 
| 95 | 
            +
                  warn <<-MSG
         | 
| 96 | 
            +
                    #{self.class}#read is deprecated.
         | 
| 97 | 
            +
                    Please use `#{self.class}#relation(#{name.inspect})` instead.
         | 
| 98 | 
            +
                    For mapping append `.map_with(:your_mapper_name)`
         | 
| 99 | 
            +
                    [#{caller[0]}]
         | 
| 100 | 
            +
                  MSG
         | 
| 101 | 
            +
                  relation(name, &block)
         | 
| 100 102 | 
             
                end
         | 
| 101 103 |  | 
| 102 104 | 
             
                # Returns commands registry for the given relation
         | 
    
        data/lib/rom/memory/storage.rb
    CHANGED
    
    
    
        data/lib/rom/relation.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            require ' | 
| 2 | 
            -
             | 
| 1 | 
            +
            require 'rom/relation/class_interface'
         | 
| 2 | 
            +
             | 
| 3 3 | 
             
            require 'rom/relation/lazy'
         | 
| 4 4 | 
             
            require 'rom/relation/curried'
         | 
| 5 5 |  | 
| @@ -19,147 +19,26 @@ module ROM | |
| 19 19 | 
             
              #
         | 
| 20 20 | 
             
              # @api public
         | 
| 21 21 | 
             
              class Relation
         | 
| 22 | 
            -
                extend  | 
| 22 | 
            +
                extend ClassInterface
         | 
| 23 23 |  | 
| 24 24 | 
             
                include Options
         | 
| 25 25 | 
             
                include Equalizer.new(:dataset)
         | 
| 26 26 |  | 
| 27 | 
            -
                 | 
| 28 | 
            -
             | 
| 29 | 
            -
                repository :default
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                attr_reader :name, :dataset, :exposed_relations
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                # Register adapter relation subclasses during setup phase
         | 
| 34 | 
            -
                #
         | 
| 35 | 
            -
                # In adition those subclasses are extended with an interface for accessing
         | 
| 36 | 
            -
                # relation registry and to define `register_as` setting
         | 
| 37 | 
            -
                #
         | 
| 38 | 
            -
                # @api private
         | 
| 39 | 
            -
                def self.inherited(klass)
         | 
| 40 | 
            -
                  super
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                  return if self == ROM::Relation
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                  klass.class_eval do
         | 
| 45 | 
            -
                    include ROM::Relation::RegistryReader
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                    dataset(default_name)
         | 
| 48 | 
            -
                    exposed_relations Set.new
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                    def self.register_as(value = Undefined)
         | 
| 51 | 
            -
                      if value == Undefined
         | 
| 52 | 
            -
                        @register_as || dataset
         | 
| 53 | 
            -
                      else
         | 
| 54 | 
            -
                        super
         | 
| 55 | 
            -
                      end
         | 
| 56 | 
            -
                    end
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                    def self.method_added(name)
         | 
| 59 | 
            -
                      super
         | 
| 60 | 
            -
                      exposed_relations << name if public_instance_methods.include?(name)
         | 
| 61 | 
            -
                    end
         | 
| 62 | 
            -
                  end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                  ROM.register_relation(klass)
         | 
| 65 | 
            -
                end
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                # Return adapter-specific relation subclass
         | 
| 68 | 
            -
                #
         | 
| 69 | 
            -
                # @example
         | 
| 70 | 
            -
                #   ROM::Relation[:memory]
         | 
| 71 | 
            -
                #   # => ROM::Memory::Relation
         | 
| 27 | 
            +
                # Dataset used by the relation
         | 
| 72 28 | 
             
                #
         | 
| 73 | 
            -
                #  | 
| 74 | 
            -
                #
         | 
| 75 | 
            -
                # @api public
         | 
| 76 | 
            -
                def self.[](type)
         | 
| 77 | 
            -
                  ROM.adapters.fetch(type).const_get(:Relation)
         | 
| 78 | 
            -
                end
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                # Dynamically define a method that will forward to the dataset and wrap
         | 
| 81 | 
            -
                # response in the relation itself
         | 
| 82 | 
            -
                #
         | 
| 83 | 
            -
                # @example
         | 
| 84 | 
            -
                #   class SomeAdapterRelation < ROM::Relation
         | 
| 85 | 
            -
                #     forward :super_query
         | 
| 86 | 
            -
                #   end
         | 
| 87 | 
            -
                #
         | 
| 88 | 
            -
                # @api public
         | 
| 89 | 
            -
                def self.forward(*methods)
         | 
| 90 | 
            -
                  methods.each do |method|
         | 
| 91 | 
            -
                    class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 92 | 
            -
                      def #{method}(*args, &block)
         | 
| 93 | 
            -
                        __new__(dataset.__send__(:#{method}, *args, &block))
         | 
| 94 | 
            -
                      end
         | 
| 95 | 
            -
                    RUBY
         | 
| 96 | 
            -
                  end
         | 
| 97 | 
            -
                end
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                # Return default relation name used for `register_as` setting
         | 
| 29 | 
            +
                # This object is provided by the repository during the setup
         | 
| 100 30 | 
             
                #
         | 
| 101 | 
            -
                # @return [ | 
| 31 | 
            +
                # @return [Object]
         | 
| 102 32 | 
             
                #
         | 
| 103 33 | 
             
                # @api private
         | 
| 104 | 
            -
                 | 
| 105 | 
            -
                  return unless name
         | 
| 106 | 
            -
                  Inflector.underscore(name).gsub('/', '_').to_sym
         | 
| 107 | 
            -
                end
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                # Build relation registry of specified descendant classes
         | 
| 110 | 
            -
                #
         | 
| 111 | 
            -
                # This is used by the setup
         | 
| 112 | 
            -
                #
         | 
| 113 | 
            -
                # @param [Hash] repositories
         | 
| 114 | 
            -
                # @param [Array] descendants a list of relation descendants
         | 
| 115 | 
            -
                #
         | 
| 116 | 
            -
                # @return [Hash]
         | 
| 117 | 
            -
                #
         | 
| 118 | 
            -
                # @api private
         | 
| 119 | 
            -
                def self.registry(repositories, descendants)
         | 
| 120 | 
            -
                  registry = {}
         | 
| 121 | 
            -
             | 
| 122 | 
            -
                  descendants.each do |klass|
         | 
| 123 | 
            -
                    # TODO: raise a meaningful error here and add spec covering the case
         | 
| 124 | 
            -
                    #       where klass' repository points to non-existant repo
         | 
| 125 | 
            -
                    repository = repositories.fetch(klass.repository)
         | 
| 126 | 
            -
                    dataset = repository.dataset(klass.dataset)
         | 
| 127 | 
            -
             | 
| 128 | 
            -
                    relation = klass.new(dataset, __registry__: registry)
         | 
| 129 | 
            -
             | 
| 130 | 
            -
                    name = klass.register_as
         | 
| 131 | 
            -
             | 
| 132 | 
            -
                    if registry.key?(name)
         | 
| 133 | 
            -
                      raise RelationAlreadyDefinedError,
         | 
| 134 | 
            -
                        "Relation with `register_as #{name.inspect}` registered more " \
         | 
| 135 | 
            -
                        "than once"
         | 
| 136 | 
            -
                    end
         | 
| 137 | 
            -
             | 
| 138 | 
            -
                    registry[name] = relation
         | 
| 139 | 
            -
                  end
         | 
| 140 | 
            -
             | 
| 141 | 
            -
                  registry.each_value do |relation|
         | 
| 142 | 
            -
                    relation.class.finalize(registry, relation)
         | 
| 143 | 
            -
                  end
         | 
| 144 | 
            -
             | 
| 145 | 
            -
                  registry
         | 
| 146 | 
            -
                end
         | 
| 34 | 
            +
                attr_reader :dataset
         | 
| 147 35 |  | 
| 148 36 | 
             
                # @api private
         | 
| 149 37 | 
             
                def initialize(dataset, options = {})
         | 
| 150 38 | 
             
                  @dataset = dataset
         | 
| 151 | 
            -
                  @name = self.class.dataset
         | 
| 152 | 
            -
                  @exposed_relations = self.class.exposed_relations
         | 
| 153 39 | 
             
                  super
         | 
| 154 40 | 
             
                end
         | 
| 155 41 |  | 
| 156 | 
            -
                # Hook to finalize a relation after its instance was created
         | 
| 157 | 
            -
                #
         | 
| 158 | 
            -
                # @api private
         | 
| 159 | 
            -
                def self.finalize(_env, _relation)
         | 
| 160 | 
            -
                  # noop
         | 
| 161 | 
            -
                end
         | 
| 162 | 
            -
             | 
| 163 42 | 
             
                # Yield dataset tuples
         | 
| 164 43 | 
             
                #
         | 
| 165 44 | 
             
                # @yield [Hash]
         | 
| @@ -170,7 +49,7 @@ module ROM | |
| 170 49 | 
             
                  dataset.each { |tuple| yield(tuple) }
         | 
| 171 50 | 
             
                end
         | 
| 172 51 |  | 
| 173 | 
            -
                # Materialize relation into an array
         | 
| 52 | 
            +
                # Materialize a relation into an array
         | 
| 174 53 | 
             
                #
         | 
| 175 54 | 
             
                # @return [Array<Hash>]
         | 
| 176 55 | 
             
                #
         | 
| @@ -179,11 +58,12 @@ module ROM | |
| 179 58 | 
             
                  to_enum.to_a
         | 
| 180 59 | 
             
                end
         | 
| 181 60 |  | 
| 182 | 
            -
                #  | 
| 183 | 
            -
                 | 
| 184 | 
            -
             | 
| 185 | 
            -
                 | 
| 186 | 
            -
             | 
| 61 | 
            +
                # Turn relation into a lazy-loadable and composable relation
         | 
| 62 | 
            +
                #
         | 
| 63 | 
            +
                # @see Lazy
         | 
| 64 | 
            +
                #
         | 
| 65 | 
            +
                # @return [Lazy]
         | 
| 66 | 
            +
                #
         | 
| 187 67 | 
             
                # @api public
         | 
| 188 68 | 
             
                def to_lazy(*args)
         | 
| 189 69 | 
             
                  Lazy.new(self, *args)
         | 
| @@ -0,0 +1,180 @@ | |
| 1 | 
            +
            require 'set'
         | 
| 2 | 
            +
            require 'rom/relation/registry_reader'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module ROM
         | 
| 5 | 
            +
              class Relation
         | 
| 6 | 
            +
                module ClassInterface
         | 
| 7 | 
            +
                  # Register adapter relation subclasses during setup phase
         | 
| 8 | 
            +
                  #
         | 
| 9 | 
            +
                  # In adition those subclasses are extended with an interface for accessing
         | 
| 10 | 
            +
                  # relation registry and to define `register_as` setting
         | 
| 11 | 
            +
                  #
         | 
| 12 | 
            +
                  # @api private
         | 
| 13 | 
            +
                  def inherited(klass)
         | 
| 14 | 
            +
                    super
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    return if klass.superclass == ROM::Relation
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    klass.class_eval do
         | 
| 19 | 
            +
                      extend ClassMacros
         | 
| 20 | 
            +
                      include RegistryReader
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      defines :repository, :dataset, :register_as, :exposed_relations
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                      repository :default
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                      dataset(default_name)
         | 
| 27 | 
            +
                      exposed_relations Set.new
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                      # Relation's dataset name
         | 
| 30 | 
            +
                      #
         | 
| 31 | 
            +
                      # In example a table name in an SQL database
         | 
| 32 | 
            +
                      #
         | 
| 33 | 
            +
                      # @return [Symbol]
         | 
| 34 | 
            +
                      #
         | 
| 35 | 
            +
                      # @api public
         | 
| 36 | 
            +
                      attr_reader :name
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                      # A set with public method names that return "virtual" relations
         | 
| 39 | 
            +
                      #
         | 
| 40 | 
            +
                      # Only those methods are exposed directly on relations return by
         | 
| 41 | 
            +
                      # Env#relation interface
         | 
| 42 | 
            +
                      #
         | 
| 43 | 
            +
                      # @return [Set]
         | 
| 44 | 
            +
                      #
         | 
| 45 | 
            +
                      # @api private
         | 
| 46 | 
            +
                      attr_reader :exposed_relations
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                      # Set or get name under which a relation will be registered
         | 
| 49 | 
            +
                      #
         | 
| 50 | 
            +
                      # This defaults to `dataset` name
         | 
| 51 | 
            +
                      #
         | 
| 52 | 
            +
                      # @return [Symbol]
         | 
| 53 | 
            +
                      #
         | 
| 54 | 
            +
                      # @api public
         | 
| 55 | 
            +
                      def self.register_as(value = Undefined)
         | 
| 56 | 
            +
                        if value == Undefined
         | 
| 57 | 
            +
                          super() || dataset
         | 
| 58 | 
            +
                        else
         | 
| 59 | 
            +
                          super
         | 
| 60 | 
            +
                        end
         | 
| 61 | 
            +
                      end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                      # Hook used to collect public method names
         | 
| 64 | 
            +
                      #
         | 
| 65 | 
            +
                      # @api private
         | 
| 66 | 
            +
                      def self.method_added(name)
         | 
| 67 | 
            +
                        super
         | 
| 68 | 
            +
                        exposed_relations << name if public_instance_methods.include?(name)
         | 
| 69 | 
            +
                      end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                      # @api private
         | 
| 72 | 
            +
                      def initialize(dataset, options = {})
         | 
| 73 | 
            +
                        @name = self.class.dataset
         | 
| 74 | 
            +
                        @exposed_relations = self.class.exposed_relations
         | 
| 75 | 
            +
                        super
         | 
| 76 | 
            +
                      end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                      # Return name of the source repository of this relation
         | 
| 79 | 
            +
                      #
         | 
| 80 | 
            +
                      # @return [Symbol]
         | 
| 81 | 
            +
                      #
         | 
| 82 | 
            +
                      # @api private
         | 
| 83 | 
            +
                      def repository
         | 
| 84 | 
            +
                        self.class.repository
         | 
| 85 | 
            +
                      end
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    ROM.register_relation(klass)
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  # Return adapter-specific relation subclass
         | 
| 92 | 
            +
                  #
         | 
| 93 | 
            +
                  # @example
         | 
| 94 | 
            +
                  #   ROM::Relation[:memory]
         | 
| 95 | 
            +
                  #   # => ROM::Memory::Relation
         | 
| 96 | 
            +
                  #
         | 
| 97 | 
            +
                  # @return [Class]
         | 
| 98 | 
            +
                  #
         | 
| 99 | 
            +
                  # @api public
         | 
| 100 | 
            +
                  def [](type)
         | 
| 101 | 
            +
                    ROM.adapters.fetch(type).const_get(:Relation)
         | 
| 102 | 
            +
                  end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  # Dynamically define a method that will forward to the dataset and wrap
         | 
| 105 | 
            +
                  # response in the relation itself
         | 
| 106 | 
            +
                  #
         | 
| 107 | 
            +
                  # @example
         | 
| 108 | 
            +
                  #   class SomeAdapterRelation < ROM::Relation
         | 
| 109 | 
            +
                  #     forward :super_query
         | 
| 110 | 
            +
                  #   end
         | 
| 111 | 
            +
                  #
         | 
| 112 | 
            +
                  # @api public
         | 
| 113 | 
            +
                  def forward(*methods)
         | 
| 114 | 
            +
                    methods.each do |method|
         | 
| 115 | 
            +
                      class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 116 | 
            +
                        def #{method}(*args, &block)
         | 
| 117 | 
            +
                          __new__(dataset.__send__(:#{method}, *args, &block))
         | 
| 118 | 
            +
                        end
         | 
| 119 | 
            +
                      RUBY
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  # Return default relation name used for `register_as` setting
         | 
| 124 | 
            +
                  #
         | 
| 125 | 
            +
                  # @return [Symbol]
         | 
| 126 | 
            +
                  #
         | 
| 127 | 
            +
                  # @api private
         | 
| 128 | 
            +
                  def default_name
         | 
| 129 | 
            +
                    return unless name
         | 
| 130 | 
            +
                    Inflector.underscore(name).gsub('/', '_').to_sym
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  # Build relation registry of specified descendant classes
         | 
| 134 | 
            +
                  #
         | 
| 135 | 
            +
                  # This is used by the setup
         | 
| 136 | 
            +
                  #
         | 
| 137 | 
            +
                  # @param [Hash] repositories
         | 
| 138 | 
            +
                  # @param [Array] descendants a list of relation descendants
         | 
| 139 | 
            +
                  #
         | 
| 140 | 
            +
                  # @return [Hash]
         | 
| 141 | 
            +
                  #
         | 
| 142 | 
            +
                  # @api private
         | 
| 143 | 
            +
                  def registry(repositories, descendants)
         | 
| 144 | 
            +
                    registry = {}
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                    descendants.each do |klass|
         | 
| 147 | 
            +
                      # TODO: raise a meaningful error here and add spec covering the case
         | 
| 148 | 
            +
                      #       where klass' repository points to non-existant repo
         | 
| 149 | 
            +
                      repository = repositories.fetch(klass.repository)
         | 
| 150 | 
            +
                      dataset = repository.dataset(klass.dataset)
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                      relation = klass.new(dataset, __registry__: registry)
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                      name = klass.register_as
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                      if registry.key?(name)
         | 
| 157 | 
            +
                        raise RelationAlreadyDefinedError,
         | 
| 158 | 
            +
                          "Relation with `register_as #{name.inspect}` registered more " \
         | 
| 159 | 
            +
                          "than once"
         | 
| 160 | 
            +
                      end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                      registry[name] = relation
         | 
| 163 | 
            +
                    end
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                    registry.each_value do |relation|
         | 
| 166 | 
            +
                      relation.class.finalize(registry, relation)
         | 
| 167 | 
            +
                    end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                    registry
         | 
| 170 | 
            +
                  end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                  # Hook to finalize a relation after its instance was created
         | 
| 173 | 
            +
                  #
         | 
| 174 | 
            +
                  # @api private
         | 
| 175 | 
            +
                  def finalize(_env, _relation)
         | 
| 176 | 
            +
                    # noop
         | 
| 177 | 
            +
                  end
         | 
| 178 | 
            +
                end
         | 
| 179 | 
            +
              end
         | 
| 180 | 
            +
            end
         |