class OpenGraphReader::Builder

Convert a {Parser::Graph} into the right hierarchy of {Object}s attached to a {Base}, then validate it.

@api private

Constants

KNOWN_TYPES

Well-known types from

@see ogp.me

Public Class Methods

new(parser) click to toggle source

Create a new builder.

@param [Parser] parser @see Parser#graph @see Parser#additional_namespaces

# File lib/open_graph_reader/builder.rb, line 17
def initialize parser
  @parser = parser
end

Public Instance Methods

base() click to toggle source

Build and return the base.

@return [Base]

# File lib/open_graph_reader/builder.rb, line 24
def base
  base = Base.new

  type = @parser.graph.fetch("og:type", "website").downcase

  validate_type type

  @parser.graph.each do |property|
    build_property base, property
  end

  synthesize_required_properties base
  drop_empty_children base
  validate base

  base
end

Private Instance Methods

build_collection(object, property, name) click to toggle source
# File lib/open_graph_reader/builder.rb, line 70
def build_collection object, property, name
  collection = object.public_send "#{name}s"
  if Object::Registry.registered? property.fullname # of subobjects
    object = Object::Registry[property.fullname].new
    collection << object
    object.content = property.content
  else # of type
    collection << property.content
  end
end
build_property(base, property) click to toggle source
# File lib/open_graph_reader/builder.rb, line 44
def build_property base, property
  object, name = object_and_name base, property

  if collection? object, name
    build_collection object, property, name
  elsif subobject? property
    build_subobject object, property, name
  else # Direct attribute
    build_single object, property, name
  end
rescue UnknownNamespaceError, UndefinedPropertyError => e
  raise InvalidObjectError, e.message if OpenGraphReader.config.strict
end
build_single(object, property, name) click to toggle source
# File lib/open_graph_reader/builder.rb, line 90
def build_single object, property, name
  object[name] = property.content
end
build_subobject(object, property, name) click to toggle source
# File lib/open_graph_reader/builder.rb, line 85
def build_subobject object, property, name
  object[name] ||= Object::Registry[property.fullname].new
  object[name].content = property.content
end
collection?(object, name) click to toggle source
# File lib/open_graph_reader/builder.rb, line 66
def collection? object, name
  object.property?(name) && object.respond_to?("#{name}s")
end
drop_empty_children(base) click to toggle source
# File lib/open_graph_reader/builder.rb, line 141
def drop_empty_children base
  base = base.children
  base.each do |key, object|
    [*object].each do |object|
      if object.is_a? Object
        drop_empty_children object
        base.delete(key) if object.content.nil? && object.children.empty? && object.properties.empty?
      end
    end
  end
end
extra_properties(object, type, verticals) click to toggle source
# File lib/open_graph_reader/builder.rb, line 189
def extra_properties object, type, verticals
  valid_properties = verticals[type]
  set_properties   = object.class.available_properties.select {|property| object[property] }

  set_properties - valid_properties
end
object_and_name(base, property) click to toggle source
# File lib/open_graph_reader/builder.rb, line 58
def object_and_name base, property
  root, *path, name = property.path
  base[root] ||= Object::Registry[root].new
  object = resolve base[root], root, path

  [object, name]
end
resolve(object, last_namespace, path) click to toggle source
# File lib/open_graph_reader/builder.rb, line 94
def resolve object, last_namespace, path
  return object if path.empty?

  next_name = path.shift
  if object.property?(next_name) && object.respond_to?("#{next_name}s") # collection
    resolve_collection object, last_namespace, next_name
  else
    resolve_property object, last_namespace, next_name
  end
end
resolve_collection(object, last_namespace, next_name) click to toggle source
# File lib/open_graph_reader/builder.rb, line 105
def resolve_collection object, last_namespace, next_name
  collection = object.public_send("#{next_name}s")
  next_object = collection.last
  # Final namespace or missing previous declaration, create a new collection item
  if next_object.nil?
    next_object = Object::Registry[[*last_namespace, next_name].join(":")].new
    collection << next_object
  end

  next_object
end
resolve_property(object, last_namespace, next_name) click to toggle source
# File lib/open_graph_reader/builder.rb, line 117
def resolve_property object, last_namespace, next_name
  next_object = object[next_name]
  next_object || Object::Registry[[*last_namespace, next_name].join(":")].new
end
subobject?(property) click to toggle source
# File lib/open_graph_reader/builder.rb, line 81
def subobject? property
  Object::Registry.registered? property.fullname
end
synthesize_required_properties(base) click to toggle source
# File lib/open_graph_reader/builder.rb, line 122
def synthesize_required_properties base
  synthesize_url base
  synthesize_title base
end
synthesize_title(base) click to toggle source
# File lib/open_graph_reader/builder.rb, line 134
def synthesize_title base
  return unless OpenGraphReader.config.synthesize_title
  return if base.og.title

  base.og["title"] = @parser.title
end
synthesize_url(base) click to toggle source
# File lib/open_graph_reader/builder.rb, line 127
def synthesize_url base
  return unless OpenGraphReader.config.synthesize_url
  return if base.og.url

  base.og["url"] = OpenGraphReader.current_origin
end
validate(base) click to toggle source
# File lib/open_graph_reader/builder.rb, line 163
def validate base
  base.each do |object|
    validate_required object if OpenGraphReader.config.validate_required
    validate_verticals object, base.og.type
  end
end
validate_required(object) click to toggle source
# File lib/open_graph_reader/builder.rb, line 170
def validate_required object
  object.class.required_properties.each do |property|
    if object[property].nil?
      raise InvalidObjectError, "Missing required property #{property} on #{object.inspect}"
    end
  end
end
validate_type(type) click to toggle source
# File lib/open_graph_reader/builder.rb, line 153
def validate_type type
  return unless OpenGraphReader.config.strict

  return if KNOWN_TYPES.include?(type)
  return if @parser.additional_namespaces.include?(type)
  return if Object::Registry.verticals.include?(type)

  raise InvalidObjectError, "Undefined type #{type}"
end
validate_verticals(object, type) click to toggle source
# File lib/open_graph_reader/builder.rb, line 178
def validate_verticals object, type
  return unless type.include? "."

  verticals = object.class.verticals
  return unless verticals.has_key? type
  return if extra_properties(object, type, verticals).empty?

  raise InvalidObjectError, "Set invalid property #{extra_properties.first} for #{type} " \
    "in #{object.inspect}, valid properties are #{valid_properties.inspect}"
end