Module: OpenGraphReader::Object::DSL

Defined in:
lib/open_graph_reader/object/dsl.rb,
lib/open_graph_reader/object/dsl/types.rb

Overview

This module provides the methods to define new types and properties, as well as setting other metadata necessary to describe an object, such as its namespace.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#content_processorProc (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The processor for the content attribute.

Returns:

API:

  • private



103
104
105
# File 'lib/open_graph_reader/object/dsl.rb', line 103

def content_processor
  @content_processor
end

Class Method Details

.define_type(name) {|value, *args, options| ... } ⇒ Object

Defines a new DSL method for modeling a new type

Yields:

  • convert and validate

Yield Parameters:

  • value (::Object)

    the value to be converted and validated

  • *args (Array<::Object>)

    any additional arguments

  • options ({Symbol => Bool, Class, Array<String>})

    the options hash as last parameter



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/open_graph_reader/object/dsl.rb', line 32

def self.define_type(name, &processor)
  processors[name] = processor

  define_method(name) do |name, *args|
    options = args.pop if args.last.is_a? Hash
    options ||= {}

    register_property name, options
    register_verticals name, options[:verticals]

    if options[:collection]
      define_collection name, options
    else
      define_single name, options, args, processor
    end
  end
end

.processors{Symbol => Proc}

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

A map from type names to processing blocks.

Returns:

API:

  • private



158
159
160
# File 'lib/open_graph_reader/object/dsl.rb', line 158

def self.processors
  @processors ||= {}
end

Instance Method Details

#available_propertiesArray<String>

The list of defined properties on this object.

Returns:



143
144
145
# File 'lib/open_graph_reader/object/dsl.rb', line 143

def available_properties
  @available_properties ||= []
end

#boolean(name, options = {}) ⇒ Object

Options Hash (options):

  • :required (Bool) — default: false

    Make the property required.

  • :collection (Bool) — default: false

    This property can occur multiple times.

  • :to (Class)

    This property maps to the given object (optional). belongs to the given verticals of the object (optional).

  • :verticials (Array<String>)

    This property

  • :downcase (Bool) — default: false

    Normalize the contents case to lowercase.

Parameters:

  • the name of the property in the current namespace

  • (defaults to: {})

    additional options



90
91
92
93
94
95
96
97
# File 'lib/open_graph_reader/object/dsl/types.rb', line 90

define_type :boolean do |value, options|
  {"true" => true, "false" => false, "1" => true, "0" => false}[value].tap { |bool|
    if bool.nil?
      next unless options[:required] || !OpenGraphReader.config.discard_invalid_optional_properties
      raise InvalidObjectError, "Boolean expected, but was #{value.inspect}"
    end
  }
end

#content(type, *args, options = {}) ⇒ Object

Set the type for the content attribute

Options Hash (options):

  • :downcase (Bool) — default: false

    Normalize the contents case to lowercase.

Parameters:

  • one of the registered types.

  • Additional parameters for the type

  • (defaults to: {})


129
130
131
132
133
134
135
136
137
138
# File 'lib/open_graph_reader/object/dsl.rb', line 129

def content type, *args
  options = args.pop if args.last.is_a? Hash
  options ||= {}

  @content_processor = proc { |value|
    value.downcase! if options[:downcase]
    options[:to] ||= self
    DSL.processors[type].call(value, *args, options)
  }
end

#datetime(name, options = {}) ⇒ Object

Options Hash (options):

  • :required (Bool) — default: false

    Make the property required.

  • :collection (Bool) — default: false

    This property can occur multiple times.

  • :to (Class)

    This property maps to the given object (optional). belongs to the given verticals of the object (optional).

  • :verticials (Array<String>)

    This property

  • :downcase (Bool) — default: false

    Normalize the contents case to lowercase.

Parameters:

  • the name of the property in the current namespace

  • (defaults to: {})

    additional options



78
79
80
81
82
83
84
85
86
87
# File 'lib/open_graph_reader/object/dsl/types.rb', line 78

define_type :datetime do |value, options|
  if OpenGraphReader.config.guess_datetime_format
    DateTime.parse value
  else
    DateTime.iso8601 value
  end
rescue ArgumentError
  next unless options[:required] || !OpenGraphReader.config.discard_invalid_optional_properties
  raise InvalidObjectError, "ISO8601 datetime expected, but was #{value.inspect}"
end

#define_collection(name, options) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/open_graph_reader/object/dsl.rb', line 67

def define_collection name, options
  define_method("#{name}s") do
    children[name.to_s]
  end

  define_method(name) do
    value = children[name.to_s].first
    # @todo figure out a sane way to distinguish subobject properties
    value.content if value&.is_a?(Object)
    value || options[:default]
  end
end

#define_single(name, options, args, processor) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/open_graph_reader/object/dsl.rb', line 81

def define_single name, options, args, processor
  define_method(name) do
    properties[name.to_s] || options[:default]
  end

  define_method("#{name}=") do |value|
    # @todo figure out a sane way to distinguish subobject properties
    unless value.is_a? Object
      value.downcase! if options[:downcase]
      value = processor.call(value, *args, options)
    end
    properties[name.to_s] = value
  end
end

#enum(name, allowed, options = {}) ⇒ Object

Options Hash (options):

  • :required (Bool) — default: false

    Make the property required.

  • :collection (Bool) — default: false

    This property can occur multiple times.

  • :to (Class)

    This property maps to the given object (optional). belongs to the given verticals of the object (optional).

  • :verticials (Array<String>)

    This property

  • :downcase (Bool) — default: false

    Normalize the contents case to lowercase.

See Also:

Parameters:

  • the list of allowed values

  • the name of the property in the current namespace

  • (defaults to: {})

    additional options



58
59
60
61
62
63
64
65
66
67
# File 'lib/open_graph_reader/object/dsl/types.rb', line 58

define_type_no_doc :enum do |value, allowed, options|
  value = value.to_s

  unless allowed.include? value
    next unless options[:required] || !OpenGraphReader.config.discard_invalid_optional_properties
    raise InvalidObjectError, "Expected one of #{allowed.inspect} but was #{value.inspect}"
  end

  value
end

#float(name, options = {}) ⇒ Object

Options Hash (options):

  • :required (Bool) — default: false

    Make the property required.

  • :collection (Bool) — default: false

    This property can occur multiple times.

  • :to (Class)

    This property maps to the given object (optional). belongs to the given verticals of the object (optional).

  • :verticials (Array<String>)

    This property

  • :downcase (Bool) — default: false

    Normalize the contents case to lowercase.

Parameters:

  • the name of the property in the current namespace

  • (defaults to: {})

    additional options



100
101
102
103
104
105
# File 'lib/open_graph_reader/object/dsl/types.rb', line 100

define_type :float do |value, options|
  Float(value)
rescue ArgumentError
  next unless options[:required] || !OpenGraphReader.config.discard_invalid_optional_properties
  raise InvalidObjectError, "Float expected, but was #{value.inspect}"
end

#integer(name, options = {}) ⇒ Object

Options Hash (options):

  • :required (Bool) — default: false

    Make the property required.

  • :collection (Bool) — default: false

    This property can occur multiple times.

  • :to (Class)

    This property maps to the given object (optional). belongs to the given verticals of the object (optional).

  • :verticials (Array<String>)

    This property

  • :downcase (Bool) — default: false

    Normalize the contents case to lowercase.

Parameters:

  • the name of the property in the current namespace

  • (defaults to: {})

    additional options



70
71
72
73
74
75
# File 'lib/open_graph_reader/object/dsl/types.rb', line 70

define_type :integer do |value, options|
  Integer(value)
rescue ArgumentError
  next unless options[:required] || !OpenGraphReader.config.discard_invalid_optional_properties
  raise InvalidObjectError, "Integer expected, but was #{value.inspect}"
end

#namespaceString #namespace(*names) ⇒ Object

Overloads:

  • #namespaceString

    Get the namespace of this object.

    Returns:

    • A colon separated namespace, for example og:image.

  • #namespace(*names) ⇒ Object

    Set the namespace of this object.

    Examples:

    namespace :og, :image
    

    Parameters:

    • The individual parts of the namespace as list



115
116
117
118
119
# File 'lib/open_graph_reader/object/dsl.rb', line 115

def namespace *names
  return @namespace if names.empty?
  @namespace = names.join(":")
  Registry.register @namespace, self
end

#register_property(name, options) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



51
52
53
54
55
# File 'lib/open_graph_reader/object/dsl.rb', line 51

def register_property name, options
  available_properties << name.to_s
  required_properties << name.to_s if options[:required]
  Registry.register [namespace, name].join(":"), options[:to] if options[:to]
end

#register_verticals(name, assigned_verticals) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



58
59
60
61
62
63
64
# File 'lib/open_graph_reader/object/dsl.rb', line 58

def register_verticals name, assigned_verticals
  [*assigned_verticals].each do |vertical|
    vertical = [namespace, vertical].join(".")
    verticals[vertical] << name.to_s
    Registry.verticals << vertical
  end
end

#required_propertiesArray<String]

The list of required properties on this object.

Returns:

  • Array<String]



150
151
152
# File 'lib/open_graph_reader/object/dsl.rb', line 150

def required_properties
  @required_properties ||= []
end

#string(name, options = {}) ⇒ Object

Options Hash (options):

  • :required (Bool) — default: false

    Make the property required.

  • :collection (Bool) — default: false

    This property can occur multiple times.

  • :to (Class)

    This property maps to the given object (optional). belongs to the given verticals of the object (optional).

  • :verticials (Array<String>)

    This property

  • :downcase (Bool) — default: false

    Normalize the contents case to lowercase.

Parameters:

  • the name of the property in the current namespace

  • (defaults to: {})

    additional options



10
11
12
# File 'lib/open_graph_reader/object/dsl/types.rb', line 10

define_type :string do |value|
  value.to_s
end

#url(name, options = {}) ⇒ Object

Options Hash (options):

  • :image (Bool) — default: false

    Mark attribute as image to be eligible for URL synthesization. See Configuration#synthesize_full_image_url.

  • :required (Bool) — default: false

    Make the property required.

  • :collection (Bool) — default: false

    This property can occur multiple times.

  • :to (Class)

    This property maps to the given object (optional). belongs to the given verticals of the object (optional).

  • :verticials (Array<String>)

    This property

  • :downcase (Bool) — default: false

    Normalize the contents case to lowercase.

See Also:

Parameters:

  • the name of the property in the current namespace

  • (defaults to: {})

    additional options



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/open_graph_reader/object/dsl/types.rb', line 19

define_type_no_doc :url do |value, options|
  value = value.to_s

  next value if value.start_with?("http://") || value.start_with?("https://")

  if options[:image] && OpenGraphReader.config.synthesize_full_image_url || OpenGraphReader.config.synthesize_full_url
    unless OpenGraphReader.current_origin
      next unless options[:required] || !OpenGraphReader.config.discard_invalid_optional_properties

      raise ArgumentError, "Enabled image url synthesization but didn't pass an origin"
    end

    # Synthesize scheme hack to https (//example.org/foo/bar.png)
    next "https:#{value}" if value.start_with?("//") && value.split("/", 4)[2] =~ URI::HOST

    # Synthesize absolute path (/foo/bar.png)
    begin
      value = "/#{value}" unless value.start_with? "/" # Normalize to absolute path
      uri = URI.parse(OpenGraphReader.current_origin)
      uri.path = value
      value = uri.to_s
    rescue
      next unless options[:required] || !OpenGraphReader.config.discard_invalid_optional_properties
      raise InvalidObjectError,
        "URL #{value.inspect} does not start with http:// or https:// and failed to " \
        "synthesize a full URL"
    end
  elsif options.has_key?(:to) && OpenGraphReader.config.validate_references
    next unless options[:required] || !OpenGraphReader.config.discard_invalid_optional_properties
    raise InvalidObjectError, "URL #{value.inspect} does not start with http:// or https://"
  end

  value
end

#verticals{String => Array<Strin>}

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

A map from vertical names to attributes that belong to them.

Returns:

API:

  • private



166
167
168
# File 'lib/open_graph_reader/object/dsl.rb', line 166

def verticals
  @verticals ||= Hash.new { |h, k| h[k] = [] }
end