class Moonrope::Structure

Attributes

attributes[R]

@return [Hash] attributes which should be included in this structure

base[R]

@return [Moonrope::Base] the base API

basic[RW]

@return [Proc] the basic data block

doc[RW]

@return [Bool] should this structure be documented

dsl[R]

@return [Moonrope::DSL::StructureDSL] the DSL

expansions[R]

@return [Hash] all expansions for the structure

full[RW]

@return [Proc] the full data block

name[RW]

@return [Symbol] the name of the structure

Public Class Methods

new(base, name, &block) click to toggle source

Initialize a new structure

@param base [Moonrope::Base] @param name [Symbol] @yield instance evals the contents within the structure DSL

# File lib/moonrope/structure.rb, line 36
def initialize(base, name, &block)
  @base = base
  @name = name
  @expansions = {}
  @attributes = {:basic => [], :full => [], :expansion => []}
  @dsl = Moonrope::DSL::StructureDSL.new(self)
  @dsl.instance_eval(&block) if block_given?
end

Public Instance Methods

all_expansions() click to toggle source

Return an array of all expansions which are available on this structure

# File lib/moonrope/structure.rb, line 128
def all_expansions
  @attributes[:expansion].map(&:name) + expansions.keys
end
attribute(name) click to toggle source

Return details for the given attribute

# File lib/moonrope/structure.rb, line 48
def attribute(name)
  @attributes[:basic].select { |p| p.name == name }.first ||
  @attributes[:full].select { |p| p.name == name }.first ||
  @attributes[:expansion].select { |p| p.name == name }.first
end
description_for_condition(condition) click to toggle source

Return the description for a given condition hash

# File lib/moonrope/structure.rb, line 135
def description_for_condition(condition)
  if condition[:authenticator] && condition[:access_rule]
    if authenticator = base.authenticators[condition[:authenticator]]
      if access_rule = authenticator.rules[condition[:access_rule]]
        access_rule[:description]
      end
    end
  else
    condition[:description]
  end
end
hash(object, options = {}) click to toggle source

Return a hash for this struture

@param object [Object] the object @param options [Hash] additional options @return [Hash]

# File lib/moonrope/structure.rb, line 61
def hash(object, options = {})
  # Set up an environment
  environment = EvalEnvironment.new(base, options[:request], options[:request] ? options[:request].action : nil, :o => object)

  # Set a new hash
  hash = Hash.new

  # Add the 'basic' structured fields
  DeepMerge.deep_merge! hash_for_attributes(@attributes[:basic], object, environment), hash

  # Always get a basic hash to work from
  if self.basic.is_a?(Proc)
    DeepMerge.deep_merge! environment.instance_eval(&self.basic), hash
  end

  # Enhance with the full hash if requested
  if options[:full]

    # Add the 'full' structured fields
    DeepMerge.deep_merge! hash_for_attributes(@attributes[:full], object, environment), hash

    if self.full.is_a?(Proc)
      full_hash = environment.instance_eval(&self.full)
      DeepMerge.deep_merge! full_hash,hash
    end
  end

  if options[:attributes]
    hash.reject! { |k,v| !options[:attributes].include?(k.to_sym) }
  end

  # Add expansions
  if options[:expansions]

    if options[:expansions].is_a?(Array)
      expansions_to_include = options[:expansions].each_with_object({}) do |expan, hash|
        if expan.is_a?(Symbol) || expan.is_a?(String)
          hash[expan.to_sym] = nil
        elsif expan.is_a?(Hash)
          hash[expan.first.first.to_sym] = expan.first.last
        end
      end
    else
      expansions_to_include = true
    end

    # Add structured expansions
    @attributes[:expansion].each do |attribute|
      next if expansions_to_include.is_a?(Hash) && !expansions_to_include.keys.include?(attribute.name.to_sym)
      DeepMerge.deep_merge! hash_for_attributes([attribute], object, environment, :structure_opts => expansions_to_include.is_a?(Hash) && expansions_to_include[attribute.name.to_sym]), hash
    end

    # Add the expansions
    expansions.each do |name, expansion|
      next if options[:expansions].is_a?(Array) && !options[:expansions].include?(name.to_sym)
      next unless check_conditions(environment, expansion[:conditions])
      DeepMerge.deep_merge!({name.to_sym => environment.instance_eval(&expansion[:block])}, hash)
    end
  end

  # Return the hash
  hash
end

Private Instance Methods

check_conditions(environment, conditions) click to toggle source

 Call all conditions provided and return whether they pass or not

# File lib/moonrope/structure.rb, line 152
def check_conditions(environment, conditions)
  conditions.each do |condition|
    if condition[:block]
      unless environment.instance_eval(&condition[:block])
        return false
      end
    elsif condition[:authenticator] && condition[:access_rule]
      if authenticator = base.authenticators[condition[:authenticator]]
        if access_rule = authenticator.rules[condition[:access_rule]]
          # If we have an authenticator and access rule, use the access rule
          # block with this environment to determine if we should include the
          # given block or not.
          unless environment.instance_exec(self, &access_rule[:block])
            return false
          end
        else
          raise Moonrope::Errors::MissingAccessRule, "The rule '#{condition[:access_rule]}' was not found on '#{authenticator.name}' authenticator"
        end
      else
        raise Moonrope::Errors::MissingAuthenticator, "The authentication '#{condition[:authenticator]}' was not found"
      end
    end
  end
  true
end
hash_for_attributes(attributes, object, environment, value_options = {}) click to toggle source

Return a returnable hash for a given set of structured fields.

# File lib/moonrope/structure.rb, line 181
def hash_for_attributes(attributes, object, environment, value_options = {})
  return {} unless attributes.is_a?(Array)
  Hash.new.tap do |hash|
    attributes.each do |attribute|

      unless attribute.conditions.empty?
        unless check_conditions(environment, attribute.conditions)
          # Skip this item because a condition didn't evaluate
          # to true.
          next
        end
      end

      if attribute.value.is_a?(Proc)
        value = environment.instance_eval(&attribute.value)
      elsif attribute.value
        value = attribute.value
      else
        value = value_for_attribute(object, environment, attribute, value_options)
      end

      value = attribute.mutate(value)

      if attribute.groups.empty?
        hash[attribute.name] = value
      else
        last_hash = hash
        attribute.groups.each_with_index do |group, index|
          last_hash[group] ||= {}
          if index == attribute.groups.size - 1
            last_hash[group][attribute.name] = value
          end
          last_hash = last_hash[group]
        end
      end

    end
  end
end
value_for_attribute(object, environment, attribute, options = {}) click to toggle source

Return a value for a structured field.

# File lib/moonrope/structure.rb, line 224
def value_for_attribute(object, environment, attribute, options = {})
  if attribute.source_attribute.is_a?(Proc)
    value = environment.instance_eval(&attribute.source_attribute)
  else
    value = object.send(attribute.source_attribute)
  end

  if value && attribute.structure
    # If a structure is required, lookup the desired structure and set the
    # hash value as appropriate.
    if structure = self.base.structure(attribute.structure)
      structure_opts = options[:structure_opts] || attribute.structure_opts || {}
      if value.is_a?(Enumerable) && value.respond_to?(:map)
        value.map do |v|
          structure.hash(v, structure_opts.merge(:request => environment.request))
        end
      else
        structure.hash(value, structure_opts.merge(:request => environment.request))
      end
    end
  else
    # Return the value as normal for non-structure values.
    value
  end
end