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:

  • (Proc)


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:

  • ({Symbol => Proc})


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:

  • (Array<String>)


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

def available_properties
  @available_properties ||= []
end

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

Parameters:

  • name (Symbol)

    the name of the property in the current namespace

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

    additional options

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.



94
95
96
97
98
99
100
101
# File 'lib/open_graph_reader/object/dsl/types.rb', line 94

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

Parameters:

  • type (Symbol)

    one of the registered types.

  • args (Array<Object>)

    Additional parameters for the type

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :downcase (Bool) — default: false

    Normalize the contents case to lowercase.



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

Parameters:

  • name (Symbol)

    the name of the property in the current namespace

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

    additional options

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.



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

define_type :datetime do |value, options|
  begin
    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
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.



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 && 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.



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

Parameters:

  • allowed (Array<String>)

    the list of allowed values

  • name (Symbol)

    the name of the property in the current namespace

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

    additional options

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:



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

Parameters:

  • name (Symbol)

    the name of the property in the current namespace

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

    additional options

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.



104
105
106
107
108
109
110
111
# File 'lib/open_graph_reader/object/dsl/types.rb', line 104

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

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

Parameters:

  • name (Symbol)

    the name of the property in the current namespace

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

    additional options

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.



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

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

#namespaceString #namespace(*names) ⇒ Object

Overloads:

  • #namespaceString

    Get the namespace of this object.

    Returns:

    • (String)

      A colon separated namespace, for example og:image.

  • #namespace(*names) ⇒ Object

    Set the namespace of this object.

    Examples:

    namespace :og, :image

    Parameters:

    • *names (Array<#to_s>)

      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.



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.



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])

    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

Parameters:

  • name (Symbol)

    the name of the property in the current namespace

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

    additional options

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.



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

Parameters:

  • name (Symbol)

    the name of the property in the current namespace

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

    additional options

Options Hash (options):

  • :image (Bool) — default: false

    Mark attribute as image to be eligible for URL synthesization. See Configuration#synthesize_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:



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_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:

  • ({String => Array<Strin>})


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

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