class Carbon::Concrete::Index
A list of all of the “items” in the global context of Carbon
. Items are mostly functions and data definitions. This keeps track of them and their dependencies, so that they can be built later. Indexes are also designed to be easily serialized if needed (which is likely the case, for libraries).
Constants
- ITEMS
Used only for {#define}. This maps item “names” to the classes that represent them.
@api private @return [{::Symbol => Item::Base}]
Public Class Methods
Initialize the index with the given data.
@api public @param data [{::Symbol => ::Object}] The data to initialize with. @option data [::Hash] :items ({}) The definitions. @option data [::String] :id (id
) The ID of the index. This is
completely derived from the index itself; or, rather, what's defined on the index. See {#id}.
# File lib/carbon/concrete/index.rb, line 41 def initialize(data = {}) @items = ::Set.new.merge(data.fetch(:items, [])) @links = ::Set.new @id = data.fetch(:id) { id } end
Public Instance Methods
Adds a defined item to the index. The item just has to respond to the item API (see {Concrete::Item}). This clears the index's cache, such that the ID ({#id}) and item list ({#items}) are reset and have to be recalculated.
@api public @example Adding an item.
index << item index.key?(item.intern) # => true
@param item [Concrete::Item::Base] The item to add. @return [self]
# File lib/carbon/concrete/index.rb, line 110 def add(item) @items << item clear! end
Yields the builds that need to be built for the given item. This uses the TSort module in order to determine all of the dependencies the given item has, and yields each; and finally, yields the last item. The item may not have any generics, even if they are fully formed generics (e.g. have a definition). If any items have a cyclic depdendency, it fails.
@api semipublic @example Build
request.
request.intern # => "Main" request.generics # => [] index.build(request).to_a # => [...]
@param item [Concrete::Type] The type to build. @return [::Enumerable] The build items, if no block is given. @return [void] If a block is given. @yield [dep] Multiple times, each with a dependency. @yieldparam dep [Request] A request.
# File lib/carbon/concrete/index.rb, line 204 def build(item) fail ArgumentError, "Passed item cannot be generic" if \ item.generics.any? return to_enum(:build, item) unless block_given? build_from_request(item, &Proc.new) end
Defines a type. This is mostly a shorthand method. The purpose of this is to make it easy to define items on the index. The only parameter, data, is a hash. The key is the name of the type of the item; this corresponds to the keys in the {ITEMS} hash. The value is the {Concrete::Type} that is being defined. The method then yields a hash that is later used to define the item.
@api semipublic @example
index.class # => Carbon::Concrete::Index index.define(internal: Carbon::Boolean) do |bool| bool[:size] = 1 bool[:kind] = :integer bool[:implements] << Carbon::Type("Carbon::Numeric") bool[:implements] << Carbon::Type("Carbon::Boolean") end internal = index[Carbon::Boolean] internal.name # => "Carbon::Boolean"
@param data [{::Symbol => Concrete::Type}] The name and
item type information. There should only be one key pair; any more will cause an error.
@yield [data] To construct the data. At the end of the block, the data
should contain all the information needed to create the item.
@yieldparam data [{::Symbol => ::Object}] The data to be passed to the
item's intializer.
@raise [ArgumentError] if more than one key-value pair is provided for
the `data` argument.
@return [void]
# File lib/carbon/concrete/index.rb, line 177 def define(data) fail ArgumentError, "Expected only one pair" if data.size > 1 data.each do |itype, name| item = ITEMS.fetch(itype) opts = item.from(Carbon::Type(name)) yield opts self << item.new(opts) end end
# File lib/carbon/concrete/index.rb, line 48 def fetch(type, default = @canary) matching = items.map { |i| [i, i.type.match?(type)] }.select(&:last) fail TooManyItemsError, "Multiple items match #{type}" if matching.size > 1 match = matching.first return match if match return yield if block_given? return default if default != @canary fail ItemNotFoundError, "Could not find an item named #{type}" end
Finalizes the index. This should only be used when all of the items defined on the index are defined. For libraries, this is the culmination of everything in the library.
@note
This freezes the item list for the index. This prevents modification for this instance of the index.
@return [self]
# File lib/carbon/concrete/index.rb, line 130 def finalize current = @items.dup items = ::Set.new(current.map { |item| item.define(self) }) @items = items.freeze clear! end
The digest of the ID. This uses the SHA256 base58 digest of the items defined on the current index. This includes both defined and merged items.
@api public @example
index.items # => [] index.id # => "gjNT5GbSC-81KmUPncw-hzQAGV3GU-eAXafmkMP-Bw2GMHWM"
@return [::String]
# File lib/carbon/concrete/index.rb, line 92 def id @_id ||= begin body = (@items.map(&:type).map(&:to_s) + @links.map(&:id)).join("\n") Carbon.hash(body) end end
# File lib/carbon/concrete/index.rb, line 60 def item?(type) items.any? { |item| item.type.match?(type) } end
# File lib/carbon/concrete/index.rb, line 64 def items @_current ||= begin current = @items.dup @links.each do |link| current.merge(link.items) end current.freeze end end
# File lib/carbon/concrete/index.rb, line 117 def link(index) @links << index clear! end
# File lib/carbon/concrete/index.rb, line 75 def to_json links, @links = @links, nil clear! && id value = Oj.dump(self, Concrete::OPTIONS) @links = links value end
Private Instance Methods
# File lib/carbon/concrete/index.rb, line 219 def build_from_request(request) components = to_enum(:each_strongly_connected_component_from, request) components.each do |group| fail TSort::Cyclic, "cyclic dependencies: #{group.join(', ')}" if \ group.size > 1 yield group.first end end
# File lib/carbon/concrete/index.rb, line 214 def clear! @_id = @_current = nil self end
Iterates over all of the “children” of a node. This iterates over all of the corrected dependencies of a node, allowing the TSort module to build a dependency map.
@api private @param node [#intern] The item. @yield [request] Yields each corrected dependency of the item. @yieldparam request [Request] @return [void]
# File lib/carbon/concrete/index.rb, line 237 def tsort_each_child(node, &block) fetch(node).first.corrected_dependencies(node, &block) end