class Skemata::Node

Constants

ALLOWED_OPTS
RESERVED_SCHEMA_TOKENS

Attributes

data[R]
root_object[R]
type[R]

Public Class Methods

new(opts = {}) click to toggle source

Prepares internal data hash and assigns locals @param opts = {} [Hash] See Skemata::DSL.draw for valid

opts

@return [Node] A Node class.

# File lib/skemata/node.rb, line 12
def initialize(opts = {})
  ALLOWED_OPTS.each { |o| instance_variable_set("@#{o}", opts[o]) }
  @data = { '@type' => type }
  @data['@context'] = 'https://schema.org' if opts.fetch(:is_root, true)
end

Public Instance Methods

decorate(name, *args, &block) click to toggle source

Decorate the node with a new property (as delegated by method_missing)

@param name [Symbol] Key name @param *args [Array] Varargs for attributes describing key @param &block [Proc] Body for a child node, if present

# File lib/skemata/node.rb, line 25
def decorate(name, *args, &block)
  # Draw another node
  return route_block(name, *args, &block) if block.present?
  # Or populate the hash
  data[attify_token(name)] = extract(args.first || name.to_sym)
end

Private Instance Methods

attify_token(token) click to toggle source

Interpolate @ into string of reserved schema.org names @param token [String] Key

@return [String]

# File lib/skemata/node.rb, line 44
def attify_token(token)
  RESERVED_SCHEMA_TOKENS.include?(token) ? "@#{token}" : token
end
extract(property) click to toggle source

Driver for fetch_property. If passed a NodeMethodChain (Array), fold the chain of methods until the final value. If passed a Symbol, just extract that single method.

@param property [Symbol|NodeMethodChain] Propert(ies) to extract

@return [Object] Serializable value

# File lib/skemata/node.rb, line 56
def extract(property)
  case property
  when DSL::NodeMethodChain
    property.inject(root_object, &method(:fetch_property))
  when Symbol
    fetch_property(root_object, property)
  else property
  end
rescue NoMethodError, ArgumentError
  nil
end
fetch_property(object, property) click to toggle source

Extract property from object, if Hash, look up via []

@param object [Object] Object to serialize @param property [Symbol] Accessor signature

@return [Object] Serializable value

# File lib/skemata/node.rb, line 75
def fetch_property(object, property)
  object.send(object.is_a?(Hash) ? :fetch : :send, property)
end
find_property(*props) click to toggle source
# File lib/skemata/node.rb, line 79
def find_property(*props)
  props.inject(nil) do |m, e|
    next m if m.present?
    extract(e.to_s.underscore.to_sym)
  end
end
internal_draw(token, type, property, &block) click to toggle source

Draw a new schema.org node and merge it into the current serializable hash.

@param token [String] Name of DSL / Hash entry @param type [String] schema.org type @param property [Object] Anything, but if symbol,

will extract from #root_object

@param &block [Block] DSL definition

@return [Hash] Hash#merge! return value with new node

# File lib/skemata/node.rb, line 97
def internal_draw(token, type, property, &block)
  property = root_object.send(property) if property.is_a?(Symbol)
  data.merge!(
    token.to_s => DSL.draw(
      { type: type, root_object: property, is_root: false },
      &block
    )
  ) if property.present?
end
route_block(token, *args, &block) click to toggle source

If a schema entry is passed a block, extract the child's root_object attribute and draw a new node. Attempts to infer the attribute name.

The token is the schema definition key (e.g. a function invocation), the type is the schema.org object type, and the last key is the explicit attribute on the current node's root object. If only the token is provided, or if both the token and the type are provided, we try to extract an attribute with either of those names before falling back to null.

@param token [String] Invoked method name in DSL.draw block body @param *args [Array] Contains [type, token] @param &block [Block] The DSL definition of the child object

@return [Hash] A copy of the data hash as returned by Hash#merge!

# File lib/skemata/node.rb, line 123
def route_block(token, *args, &block)
  type, prop = args.shift(2)

  # Explicitly defined property
  child_root = extract(prop) if prop.is_a?(Symbol)

  # Hash key / token is type
  child_root = extract(token.titleize.to_sym) if type.nil? && prop.nil?

  # If we still have no data, fold to the first present
  # property by using token and type as keys
  child_root = find_property(token, type) unless child_root.present?

  internal_draw(token, type, child_root, &block)
end