module Ecoportal module API class V2 class Page class Force class Bindings < Common::Content::CollectionModel class_resolver :binding_class, "Ecoportal::API::V2::Page::Force::Binding" self.klass = :binding_class order_matters = true def ooze self._parent.ooze end def force self._parent end # @note first local binding name will shadow later ones # @param only_winner [Boolean] specifies if retrieving multiple bindings with same name or just the winner # @return [Hash] where **key** is `name` and **value** is # 1. a single _binding_, if `only_winner` is `true` # 2. an `Array` of _bindings_ with same _name_, otherwise def by_name(only_winner: false) self.each_with_object({}) do |binding, hash| if winner_only hash[binding.name] ||= binding else hash[binding.name] ||= [] hash[binding.name].push(binding) end end end # @note first local binding name will shadow later ones. # @param only_winner [Boolean] specifies if shadowed bindings (inactive) should be excluded (`true`) # @return [Hash] where **key** is a _section_ or a _component_ and **value** is eitheran `Array` of _bindings_. def by_reference(only_winner: false) if only_winner by_name(only_winner: true).each_with_object({}) do |(name, binds), hash| if binds.is_a?(Array) binds.each {|binding| (hash[binding.reference] ||= []).push(binding)} else (hash[binds.reference] ||= []).push(binds) end end else self.each_with_object({}) do |binding, hash| (hash[binding.reference] ||= []).push(binding) end end end # @param obj [Ecoportal::API::V2::Page::Section, Ecoportal::API::V2::Page::Component)] the referred component or section. # @return [Boolean] `true` if `obj` is referred in the bindings, `false` otherwise def reference?(obj) get_by_reference(obj).count > 0 end # @param obj [Ecoportal::API::V2::Page::Section, Ecoportal::API::V2::Page::Component)] the referred component or section. # @return [Array] binding to the component or section. def get_by_reference(obj) unless obj.is_a?(Ecoportal::API::V2::Page::Section) || obj.is_a?(Ecoportal::API::V2::Page::Component) raise ArgumentError.new("Expected either a Ecoportal::API::V2::Page::Section or a Ecoportal::API::V2::Page::Component. Given: #{obj.class}") end self.select do |bind| bind.reference == obj end end # @param id [String] the `id` of the binding to find. # @return [Ecoportal::API::V2::Page::Force::Binding] binding with `id` def get_by_id(id) self.find do |bind| bind.id == id end end # @param type [String] target `type` of binding # 1. Ecoportal::API::V2::Page::Force::Binding::COMPONENT_TYPE # 2. Ecoportal::API::V2::Page::Force::Binding::SECTION_TYPE # @return [Array] the bindings of type `type` def get_by_type(type = Ecoportal::API::V2::Page::Force::Binding::COMPONENT_TYPE) self.select do |bind| bind.type.downcase == type.to_s.strip.downcase end end # @param type [String] target `type` of binding # 1. Ecoportal::API::V2::Page::Force::Binding::COMPONENT_TYPE # 2. Ecoportal::API::V2::Page::Force::Binding::SECTION_TYPE # @return [Array] the bindings matching `name` def get_by_name(name, type: nil) pool = type ? get_by_type(type) : self pool.select do |bind| same_string?(bind.name, name) end end # Creates a new `binding` # @note # - As there's no position property, it will upsert to the array of bindings # @raise [ArgumentError] when `reference` is neither of Component or Section # @raise [Exception] when # 1. `reference` is a field missing in ooze.components # 2. `reference` is a section missing in ooze.sections # @param reference [Ecoportal::API::V2::Page::Component, Ecoportal::API::V2::Page::Section] # The field or the section to bind. # @yield [binding] do some stuff with binding # @yieldparam binding [Ecoportal::API::V2::Page::Force::Binding] the created binding # @return [Ecoportal::API::V2::Page::Force::Binding] the created binding. def add(reference, name:, pos: NOT_USED, before: NOT_USED, after: NOT_USED) binding_doc = binding_class.new_doc type = case reference when Ecoportal::API::V2::Page::Component unless ooze.components.include?(reference) msg = "The field '#{reference.label}' (#{reference.id}) is not present in ooze.components.\n" msg += "Review your script (i.e. @var where you store previous ooze runs)." raise msg end Ecoportal::API::V2::Page::Force::Binding::COMPONENT_TYPE when Ecoportal::API::V2::Page::Section unless ooze.sections.include?(reference) msg = "The section '#{reference.heading}' (#{reference.id}) is not present in ooze.sections.\n" msg += "Review your script (i.e. @var where you store previous ooze runs)." raise msg end Ecoportal::API::V2::Page::Force::Binding::SECTION_TYPE else msg = "You can only create bindings with Component and Section. Given: #{reference.class}" raise ArgumentError.new(msg) end position = scope_position(pos: pos, before: before, after: after) upsert!(binding_doc, pos: position) do |bind| bind.name = name bind.reference_id = reference.id bind.type = type yield(bind) if block_given? end end private def scope_position(pos: NOT_USED, before: NOT_USED, after: NOT_USED) case when used_param?(pos) if pos = to_binding(pos) _doc_pos(pos) - 1 end when used_param?(before) if before = to_binding(before) _doc_pos(before) - 1 end when used_param?(after) if after = to_binding(after) _doc_pos(after) - 1 end end.yield_self do |position| position ||= self.count end end def to_binding(value) case value when Ecoportal::API::V2::Page::Force::Binding value when Numeric self[value] else get_by_name(value).first end end end end end end end end