open_graph_reader 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6d74818ecdccf560bf131fdd804b161bc1ecfe7b
4
- data.tar.gz: 80764ab744e19b4a1e1aa5889082ae8c15d6e131
3
+ metadata.gz: 63380e971993a2baaa81d6d1189155a434fcf0fb
4
+ data.tar.gz: 84f9aa844498759914175ae984c86bb597a78669
5
5
  SHA512:
6
- metadata.gz: 60772e42741f8860027e0e24b5aa40471fe28ec0670293b9e395b99a5a7a4d8470432c19b1ef6d742f5344840452f8da3a55b1b351e23d71d00b13d940732917
7
- data.tar.gz: 05b1e4d14ca7e041b2a629ce2a0e72c76af733ca58e1e576039113de4c18421e4acb599e0483242666544b358dfc89d025bee943e1a87f9db6afb8fe68a5eea3
6
+ metadata.gz: 9747784896105a3b56891157c861a193dbb192ca8ebecee9152f908cac3f3d79ce2013179883022bcd3a40c95daf9ad2cc23d78656f92979af7f23c0acf008c4
7
+ data.tar.gz: b68f4cf4b9a1a9956b4dfe1003666f27ed736c00559716a6b0f9562b1f86137c7dc3ea6e3e66b698b8a5e5272919ce7d7cbcf2c5bc358ba52762623c9c961d77
@@ -1,13 +1,13 @@
1
- require 'uri'
1
+ require "uri"
2
2
 
3
- require 'open_graph_reader/base'
4
- require 'open_graph_reader/builder'
5
- require 'open_graph_reader/configuration'
6
- require 'open_graph_reader/definitions'
7
- require 'open_graph_reader/fetcher'
8
- require 'open_graph_reader/object'
9
- require 'open_graph_reader/parser'
10
- require 'open_graph_reader/version'
3
+ require "open_graph_reader/base"
4
+ require "open_graph_reader/builder"
5
+ require "open_graph_reader/configuration"
6
+ require "open_graph_reader/definitions"
7
+ require "open_graph_reader/fetcher"
8
+ require "open_graph_reader/object"
9
+ require "open_graph_reader/parser"
10
+ require "open_graph_reader/version"
11
11
 
12
12
  # @todo 1.1 compatibility mode?
13
13
  # This module provides the main entry to the library. Please see the
@@ -40,7 +40,7 @@ module OpenGraphReader
40
40
  def self.parse! html, origin=nil
41
41
  self.current_origin = origin
42
42
  parser = Parser.new html
43
- raise NoOpenGraphDataError, "#{origin || html} does not contain any OpenGraph tags" unless parser.has_tags?
43
+ raise NoOpenGraphDataError, "#{origin || html} does not contain any OpenGraph tags" unless parser.any_tags?
44
44
  Builder.new(parser).base.tap {|base|
45
45
  base.origin = origin.to_s if origin
46
46
  self.current_origin = nil
@@ -1,4 +1,4 @@
1
- require 'forwardable'
1
+ require "forwardable"
2
2
 
3
3
  module OpenGraphReader
4
4
  # You get an instance of this class as result of your quest to obtain
@@ -39,13 +39,20 @@ module OpenGraphReader
39
39
  # @see #origin
40
40
  attr_writer :origin
41
41
 
42
+ # Return the stored root objects as a hash.
43
+ #
44
+ # @api private
45
+ # @return [String => Object]
46
+ attr_reader :bases
47
+ alias_method :children, :bases
48
+
42
49
  # @api private
43
50
  def initialize
44
51
  @bases = {}
45
52
  end
46
53
 
47
54
  # @private
48
- def respond_to_missing?(method, include_private=false)
55
+ def respond_to_missing?(method, _include_private=false)
49
56
  @bases.has_key? method.to_s
50
57
  end
51
58
 
@@ -24,7 +24,7 @@ module OpenGraphReader
24
24
  def base
25
25
  base = Base.new
26
26
 
27
- type = @parser.graph.fetch('og:type', 'website').downcase
27
+ type = @parser.graph.fetch("og:type", "website").downcase
28
28
 
29
29
  validate_type type
30
30
 
@@ -33,6 +33,7 @@ module OpenGraphReader
33
33
  end
34
34
 
35
35
  synthesize_required_properties base
36
+ drop_empty_children base
36
37
  validate base
37
38
 
38
39
  base
@@ -41,62 +42,110 @@ module OpenGraphReader
41
42
  private
42
43
 
43
44
  def build_property base, property
44
- root, *path, name = property.path
45
- base[root] ||= Object::Registry[root].new
46
- object = resolve base[root], root, path
45
+ object, name = object_and_name base, property
47
46
 
48
- if object.has_property?(name) && object.respond_to?("#{name}s") # Collection
49
- collection = object.public_send "#{name}s"
50
- if Object::Registry.registered? property.fullname # of subobjects
51
- object = Object::Registry[property.fullname].new
52
- collection << object
53
- object.content = property.content
54
- else # of type
55
- collection << property.content
56
- end
57
- elsif Object::Registry.registered? property.fullname # Subobject
58
- object[name] ||= Object::Registry[property.fullname].new
59
- object[name].content = property.content
47
+ if collection? object, name
48
+ build_collection object, property, name
49
+ elsif subobject? property
50
+ build_subobject object, property, name
60
51
  else # Direct attribute
61
- object[name] = property.content
52
+ build_single object, property, name
62
53
  end
63
54
  rescue UnknownNamespaceError, UndefinedPropertyError => e
64
55
  raise InvalidObjectError, e.message if OpenGraphReader.config.strict
65
56
  end
66
57
 
58
+ def object_and_name base, property
59
+ root, *path, name = property.path
60
+ base[root] ||= Object::Registry[root].new
61
+ object = resolve base[root], root, path
62
+
63
+ [object, name]
64
+ end
65
+
66
+ def collection? object, name
67
+ object.property?(name) && object.respond_to?("#{name}s")
68
+ end
69
+
70
+ def build_collection object, property, name
71
+ collection = object.public_send "#{name}s"
72
+ if Object::Registry.registered? property.fullname # of subobjects
73
+ object = Object::Registry[property.fullname].new
74
+ collection << object
75
+ object.content = property.content
76
+ else # of type
77
+ collection << property.content
78
+ end
79
+ end
80
+
81
+ def subobject? property
82
+ Object::Registry.registered? property.fullname
83
+ end
84
+
85
+ def build_subobject object, property, name
86
+ object[name] ||= Object::Registry[property.fullname].new
87
+ object[name].content = property.content
88
+ end
89
+
90
+ def build_single object, property, name
91
+ object[name] = property.content
92
+ end
93
+
67
94
  def resolve object, last_namespace, path
68
95
  return object if path.empty?
69
96
 
70
97
  next_name = path.shift
71
- if object.has_property?(next_name) && object.respond_to?("#{next_name}s") # collection
72
- collection = object.public_send("#{next_name}s")
73
- next_object = collection.last
74
- if next_object.nil? # Final namespace or missing previous declaration, create a new collection item
75
- next_object = Object::Registry[[*last_namespace, next_name].join(':')].new
76
- collection << next_object
77
- end
98
+ if object.property?(next_name) && object.respond_to?("#{next_name}s") # collection
99
+ resolve_collection object, last_namespace, next_name
78
100
  else
79
- next_object = object[next_name]
80
- next_object ||= Object::Registry[[*last_namespace, next_name].join(':')].new
101
+ resolve_property object, last_namespace, next_name
102
+ end
103
+ end
104
+
105
+ def resolve_collection object, last_namespace, next_name
106
+ collection = object.public_send("#{next_name}s")
107
+ next_object = collection.last
108
+ # Final namespace or missing previous declaration, create a new collection item
109
+ if next_object.nil?
110
+ next_object = Object::Registry[[*last_namespace, next_name].join(":")].new
111
+ collection << next_object
81
112
  end
82
113
 
83
114
  next_object
84
115
  end
85
116
 
117
+ def resolve_property object, last_namespace, next_name
118
+ next_object = object[next_name]
119
+ next_object || Object::Registry[[*last_namespace, next_name].join(":")].new
120
+ end
121
+
86
122
  def synthesize_required_properties base
87
- if OpenGraphReader.config.synthesize_title && base.og.title.nil?
88
- base.og['title'] = @parser.title
123
+ return unless OpenGraphReader.config.synthesize_title
124
+ return if base.og.title
125
+
126
+ base.og["title"] = @parser.title
127
+ end
128
+
129
+ def drop_empty_children base
130
+ base = base.children
131
+ base.each do |key, object|
132
+ [*object].each do |object|
133
+ if object.is_a? Object
134
+ drop_empty_children object
135
+ base.delete(key) if object.content.nil? && object.children.empty? && object.properties.empty?
136
+ end
137
+ end
89
138
  end
90
139
  end
91
140
 
92
141
  def validate_type type
93
142
  return unless OpenGraphReader.config.strict
94
143
 
95
- unless KNOWN_TYPES.include?(type) ||
96
- @parser.additional_namespaces.include?(type) ||
97
- Object::Registry.verticals.include?(type)
98
- raise InvalidObjectError, "Undefined type #{type}"
99
- end
144
+ return if KNOWN_TYPES.include?(type)
145
+ return if @parser.additional_namespaces.include?(type)
146
+ return if Object::Registry.verticals.include?(type)
147
+
148
+ raise InvalidObjectError, "Undefined type #{type}"
100
149
  end
101
150
 
102
151
  def validate base
@@ -115,18 +164,21 @@ module OpenGraphReader
115
164
  end
116
165
 
117
166
  def validate_verticals object, type
118
- return unless type.include? '.'
167
+ return unless type.include? "."
168
+
119
169
  verticals = object.class.verticals
120
- if verticals.has_key? type
121
- valid_properties = verticals[type]
122
- set_properties = object.class.available_properties.select {|property| object[property] }
123
- extra_properties = set_properties-valid_properties
124
-
125
- unless extra_properties.empty?
126
- raise InvalidObjectError, "Set invalid property #{extra_properties.first} for #{type} " \
127
- "in #{object.inspect}, valid properties are #{valid_properties.inspect}"
128
- end
129
- end
170
+ return unless verticals.has_key? type
171
+ return if extra_properties(object, type, verticals).empty?
172
+
173
+ raise InvalidObjectError, "Set invalid property #{extra_properties.first} for #{type} " \
174
+ "in #{object.inspect}, valid properties are #{valid_properties.inspect}"
175
+ end
176
+
177
+ def extra_properties object, type, verticals
178
+ valid_properties = verticals[type]
179
+ set_properties = object.class.available_properties.select {|property| object[property] }
180
+
181
+ set_properties - valid_properties
130
182
  end
131
183
  end
132
184
  end
@@ -1,4 +1,4 @@
1
- require 'singleton'
1
+ require "singleton"
2
2
 
3
3
  module OpenGraphReader
4
4
  # The behavior of this library can be tweaked with some parameters.
@@ -38,6 +38,14 @@ module OpenGraphReader
38
38
  # @return [Bool]
39
39
  attr_accessor :validate_references
40
40
 
41
+ # Discard invalid optional properties (default: <tt>false</tt>).
42
+ #
43
+ # Instead of rendering the entire object invalid, discard
44
+ # invalid optional properties.
45
+ #
46
+ # @return [Bool]
47
+ attr_accessor :discard_invalid_optional_properties
48
+
41
49
  # Fallback to the title tag if og:title is missing (default: <tt>false</tt>).
42
50
  #
43
51
  # The standard makes defining og:title required, but it's
@@ -47,18 +55,33 @@ module OpenGraphReader
47
55
  # @return [Bool]
48
56
  attr_accessor :synthesize_title
49
57
 
50
-
51
- # Guess image URL when it looks like a path (default: <tt>false</tt>).
58
+ # Guess object URL when it looks like a path (default: <tt>false</tt>).
52
59
  #
53
- # The standard requires og:image, og:image:url and og:image:secure_url
54
- # to be a full URL. However it's common practice to put a path relative
60
+ # The standard requires the url type to point to a full http or https URL.
61
+ # However it's common practice to put a path relative
55
62
  # to the domain URL. When enabled, the library tries to guess the full
56
63
  # URL from such a path. Note the object can still turn invalid if it fails
57
64
  # to do so.
58
65
  #
59
66
  # @return [Bool]
67
+ attr_accessor :synthesize_url
68
+
69
+ # Guess image URL when it looks like a path (default: <tt>false</tt>).
70
+ #
71
+ # See {#synthesize_url}
72
+ #
73
+ # @return [Bool]
60
74
  attr_accessor :synthesize_image_url
61
75
 
76
+ # Parse non ISO8601 datetimes (default: <tt>false</tt>).
77
+ #
78
+ # The standard clearly requires ISO8601 as format for
79
+ # datetime properties. However other formats are seen in the wild.
80
+ # With this setting enabled, the format is guessed.
81
+ #
82
+ # @return [Bool]
83
+ attr_accessor :guess_datetime_format
84
+
62
85
  # @private
63
86
  def initialize
64
87
  reset_to_defaults!
@@ -66,11 +89,14 @@ module OpenGraphReader
66
89
 
67
90
  # Reset configuration to their defaults
68
91
  def reset_to_defaults!
69
- @strict = false
70
- @validate_required = true
71
- @validate_references = true
72
- @synthesize_title = false
73
- @synthesize_image_url = false
92
+ @strict = false
93
+ @validate_required = true
94
+ @validate_references = true
95
+ @discard_invalid_optional_properties = false
96
+ @synthesize_title = false
97
+ @synthesize_url = false
98
+ @synthesize_image_url = false
99
+ @guess_datetime_format = false
74
100
  end
75
101
  end
76
102
  end
@@ -1,4 +1,4 @@
1
- require 'open_graph_reader/object'
1
+ require "open_graph_reader/object"
2
2
 
3
3
  module OpenGraphReader
4
4
  # @see http://ogp.me/#metadata
@@ -9,7 +9,7 @@ module OpenGraphReader
9
9
 
10
10
  # @!macro property
11
11
  # @return [String]
12
- string :type, required: true, downcase: true, default: 'website'
12
+ string :type, required: true, downcase: true, default: "website"
13
13
 
14
14
  # @!macro property
15
15
  # @return [String]
@@ -19,15 +19,15 @@ module OpenGraphReader
19
19
  # @return [Array<Image>]
20
20
  # @!macro property
21
21
  # @return [Image]
22
- url :image, required: true, collection: true
22
+ url :image, required: true, collection: true
23
23
 
24
24
  # @!macro property
25
25
  # @return [String, nil]
26
- url :url
26
+ url :url
27
27
 
28
28
  # @!macro property
29
29
  # @return [Audio, nil]
30
- url :audio
30
+ url :audio
31
31
 
32
32
  # @!macro property
33
33
  # @return [String, nil]
@@ -35,7 +35,7 @@ module OpenGraphReader
35
35
 
36
36
  # @!macro property
37
37
  # @return [String]
38
- enum :determiner, ['', 'a', 'an', 'the', 'auto'], default: ''
38
+ enum :determiner, ["", "a", "an", "the", "auto"], default: ""
39
39
 
40
40
  # @!macro property
41
41
  # @return [Locale, nil]
@@ -47,7 +47,7 @@ module OpenGraphReader
47
47
 
48
48
  # @!macro property
49
49
  # @return [Video, nil]
50
- url :video
50
+ url :video
51
51
 
52
52
  # @see http://ogp.me/#structured
53
53
  class Image
@@ -56,15 +56,15 @@ module OpenGraphReader
56
56
  namespace :og, :image
57
57
  content :url, image: true
58
58
 
59
- url :url
59
+ url :url
60
60
 
61
61
  # @!macro property
62
62
  # @return [String, nil]
63
- url :secure_url
63
+ url :secure_url
64
64
 
65
65
  # @!macro property
66
66
  # @return [String, nil]
67
- string :type
67
+ string :type
68
68
 
69
69
  # @!macro property
70
70
  # @return [Integer, nil]
@@ -88,11 +88,11 @@ module OpenGraphReader
88
88
  content :url
89
89
 
90
90
  # This property is not listed on http://ogp.me, but commonly found
91
- url :url
91
+ url :url
92
92
 
93
93
  # @!macro property
94
94
  # @return [String, nil]
95
- url :secure_url
95
+ url :secure_url
96
96
 
97
97
  # @!macro property
98
98
  # @return [String, nil]
@@ -127,11 +127,11 @@ module OpenGraphReader
127
127
 
128
128
  # @!macro property
129
129
  # @return [String, nil]
130
- url :secure_url
130
+ url :secure_url
131
131
 
132
132
  # @!macro property
133
133
  # @return [String, nil]
134
- string :type
134
+ string :type
135
135
 
136
136
  # @!macro property
137
137
  # @return [Integer, nil]
@@ -169,7 +169,7 @@ module OpenGraphReader
169
169
 
170
170
  # @!macro property
171
171
  # @return [String, nil]
172
- enum :gender, %w(male female)
172
+ enum :gender, %w(male female)
173
173
 
174
174
  # @!macro property
175
175
  # @return [String, nil]
@@ -201,17 +201,17 @@ module OpenGraphReader
201
201
  # @return [Array<Profile>]
202
202
  # @!macro property
203
203
  # @return [Profile, nil]
204
- url :author, collection: true, to: Profile
204
+ url :author, collection: true, to: Profile
205
205
 
206
206
  # @!macro property
207
207
  # @return [String, nil]
208
- string :section
208
+ string :section
209
209
 
210
210
  # @!attribute [r] tags
211
211
  # @return [Array<String>]
212
212
  # @!macro property
213
213
  # @return [String, nil]
214
- string :tag, collection: true
214
+ string :tag, collection: true
215
215
  end
216
216
 
217
217
  # @see http://ogp.me/#type_video
@@ -224,38 +224,38 @@ module OpenGraphReader
224
224
  # @return [Array<Profile>]
225
225
  # @!macro property
226
226
  # @return [Profile, nil]
227
- url :actor, to: Profile, verticals: %w(movie episode tv_show other), collection: true
227
+ url :actor, to: Profile, verticals: %w(movie episode tv_show other), collection: true
228
228
 
229
229
  # @!attribute [r] directors
230
230
  # @return [Array<Profile>]
231
231
  # @!macro property
232
232
  # @return [Profile, nil]
233
- url :director, to: Profile, verticals: %w(movie episode tv_show other), collection: true
233
+ url :director, to: Profile, verticals: %w(movie episode tv_show other), collection: true
234
234
 
235
235
  # @!attribute [r] writers
236
236
  # @return [Array<Profile>]
237
237
  # @!macro property
238
238
  # @return [Profile, nil]
239
- url :writer, to: Profile, verticals: %w(movie episode tv_show other), collection: true
239
+ url :writer, to: Profile, verticals: %w(movie episode tv_show other), collection: true
240
240
 
241
241
  # @!macro property
242
242
  # @return [Integer, nil]
243
- integer :duration, verticals: %w(movie episode tv_show other)
243
+ integer :duration, verticals: %w(movie episode tv_show other)
244
244
 
245
245
  # @!macro property
246
246
  # @return [DateTime, nil]
247
- datetime :release_date, verticals: %w(movie episode tv_show other)
247
+ datetime :release_date, verticals: %w(movie episode tv_show other)
248
248
 
249
249
  # @!attribute [r] tags
250
250
  # @return [Array<String>]
251
251
  # @!macro property
252
252
  # @return [String, nil]
253
- string :tag, verticals: %w(movie episode tv_show other), collection: true
253
+ string :tag, verticals: %w(movie episode tv_show other), collection: true
254
254
 
255
255
  # @todo validate that target vertical is video.tv_show ?
256
256
  # @!macro property
257
257
  # @return [Sring, nil]
258
- url :series, to: Video, verticals: %w(episode)
258
+ url :series, to: Video, verticals: %w(episode)
259
259
  end
260
260
 
261
261
  # @see http://ogp.me/#type_book
@@ -296,38 +296,37 @@ module OpenGraphReader
296
296
  # @return [Integer, nil]
297
297
  integer :duration, verticals: %w(song)
298
298
 
299
-
300
299
  # @todo validate that target vertical is music.album/music.song ?
301
300
  # @!attribute [r] albums
302
301
  # @return [Array<Music>]
303
302
  # @macro property
304
303
  # @return [Music, nil]
305
- url :album, to: Music, verticals: %w(song), collection: true
304
+ url :album, to: Music, verticals: %w(song), collection: true
306
305
 
307
306
  # @macro property
308
307
  # @return [Integer, nil]
309
- integer :disc, verticals: %w(song album playlist)
308
+ integer :disc, verticals: %w(song album playlist)
310
309
 
311
310
  # @macro property
312
311
  # @return [Integer, nil]
313
- integer :track, verticals: %w(song album playlist)
312
+ integer :track, verticals: %w(song album playlist)
314
313
 
315
314
  # @!attribute [r] musicians
316
315
  # @return [Array<Profile>]
317
316
  # @!macro property
318
317
  # @return [Profile, nil]
319
- url :musician, to: Profile, verticals: %w(song album), collection: true
318
+ url :musician, to: Profile, verticals: %w(song album), collection: true
320
319
 
321
320
  # @macro property
322
321
  # @return [Music, nil]
323
- url :song, to: Music, verticals: %w(album playlist)
322
+ url :song, to: Music, verticals: %w(album playlist)
324
323
 
325
324
  # @macro property
326
325
  # @return [DateTime, nil]
327
- datetime :release_date, verticals: %w(album)
326
+ datetime :release_date, verticals: %w(album)
328
327
 
329
328
  # @macro property
330
329
  # @return [Profile, nil]
331
- url :creator, to: Profile, verticals: %w(playlist radio_station)
330
+ url :creator, to: Profile, verticals: %w(playlist radio_station)
332
331
  end
333
332
  end