open_graph_reader 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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