link_thumbnailer 1.1.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +5 -13
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +117 -104
  4. data/Gemfile +1 -1
  5. data/{LICENSE → LICENSE.txt} +21 -21
  6. data/README.md +153 -184
  7. data/lib/generators/link_thumbnailer/install_generator.rb +0 -4
  8. data/lib/generators/templates/initializer.rb +63 -41
  9. data/lib/link_thumbnailer/configuration.rb +52 -10
  10. data/lib/link_thumbnailer/exceptions.rb +6 -0
  11. data/lib/link_thumbnailer/grader.rb +37 -0
  12. data/lib/link_thumbnailer/graders/base.rb +32 -0
  13. data/lib/link_thumbnailer/graders/html_attribute.rb +49 -0
  14. data/lib/link_thumbnailer/graders/length.rb +19 -0
  15. data/lib/link_thumbnailer/graders/link_density.rb +21 -0
  16. data/lib/link_thumbnailer/graders/position.rb +11 -0
  17. data/lib/link_thumbnailer/image_comparator.rb +24 -0
  18. data/lib/link_thumbnailer/image_comparators/base.rb +17 -0
  19. data/lib/link_thumbnailer/image_comparators/size.rb +11 -0
  20. data/lib/link_thumbnailer/image_parser.rb +18 -0
  21. data/lib/link_thumbnailer/image_parsers/size.rb +15 -0
  22. data/lib/link_thumbnailer/image_parsers/type.rb +15 -0
  23. data/lib/link_thumbnailer/image_validator.rb +30 -0
  24. data/lib/link_thumbnailer/model.rb +16 -0
  25. data/lib/link_thumbnailer/models/description.rb +34 -0
  26. data/lib/link_thumbnailer/models/image.rb +54 -0
  27. data/lib/link_thumbnailer/models/title.rb +20 -0
  28. data/lib/link_thumbnailer/models/website.rb +39 -0
  29. data/lib/link_thumbnailer/page.rb +40 -0
  30. data/lib/link_thumbnailer/parser.rb +13 -0
  31. data/lib/link_thumbnailer/processor.rb +94 -0
  32. data/lib/link_thumbnailer/railtie.rb +9 -9
  33. data/lib/link_thumbnailer/scraper.rb +64 -0
  34. data/lib/link_thumbnailer/scrapers/base.rb +63 -0
  35. data/lib/link_thumbnailer/scrapers/default/base.rb +10 -0
  36. data/lib/link_thumbnailer/scrapers/default/description.rb +47 -0
  37. data/lib/link_thumbnailer/scrapers/default/images.rb +64 -0
  38. data/lib/link_thumbnailer/scrapers/default/title.rb +25 -0
  39. data/lib/link_thumbnailer/scrapers/opengraph/base.rb +43 -0
  40. data/lib/link_thumbnailer/scrapers/opengraph/description.rb +10 -0
  41. data/lib/link_thumbnailer/scrapers/opengraph/image.rb +30 -0
  42. data/lib/link_thumbnailer/scrapers/opengraph/images.rb +16 -0
  43. data/lib/link_thumbnailer/scrapers/opengraph/title.rb +10 -0
  44. data/lib/link_thumbnailer/version.rb +3 -3
  45. data/lib/link_thumbnailer.rb +36 -119
  46. data/link_thumbnailer.gemspec +26 -28
  47. data/spec/configuration_spec.rb +51 -0
  48. data/spec/examples/empty_og_image_example.html +9 -0
  49. data/spec/fixture_spec.rb +88 -0
  50. data/spec/fixtures/bar.png +2907 -0
  51. data/spec/fixtures/default_from_body.html +12 -0
  52. data/spec/fixtures/default_from_meta.html +11 -0
  53. data/spec/{examples → fixtures}/example.html +53 -53
  54. data/spec/fixtures/foo.png +0 -0
  55. data/spec/fixtures/og_not_valid_example.html +12 -0
  56. data/spec/fixtures/og_valid_example.html +12 -0
  57. data/spec/fixtures/og_valid_multi_image_example.html +13 -0
  58. data/spec/grader_spec.rb +24 -0
  59. data/spec/graders/base_spec.rb +12 -0
  60. data/spec/graders/html_attribute_spec.rb +48 -0
  61. data/spec/graders/length_spec.rb +81 -0
  62. data/spec/graders/link_density_spec.rb +22 -0
  63. data/spec/image_comparators/size_spec.rb +39 -0
  64. data/spec/image_parsers/size_spec.rb +34 -0
  65. data/spec/image_parsers/type_spec.rb +34 -0
  66. data/spec/image_validator_spec.rb +35 -0
  67. data/spec/model_spec.rb +17 -0
  68. data/spec/models/description_spec.rb +64 -0
  69. data/spec/models/image_spec.rb +71 -0
  70. data/spec/models/title_spec.rb +24 -0
  71. data/spec/models/website_spec.rb +49 -0
  72. data/spec/page_spec.rb +26 -0
  73. data/spec/processor_spec.rb +349 -0
  74. data/spec/scraper_spec.rb +95 -0
  75. data/spec/scrapers/base_spec.rb +67 -0
  76. data/spec/scrapers/opengraph/base_spec.rb +94 -0
  77. data/spec/spec_helper.rb +15 -13
  78. metadata +126 -120
  79. data/app/controllers/link_thumbnailer/application_controller.rb +0 -4
  80. data/app/controllers/link_thumbnailer/previews_controller.rb +0 -11
  81. data/lib/link_thumbnailer/doc.rb +0 -65
  82. data/lib/link_thumbnailer/doc_parser.rb +0 -15
  83. data/lib/link_thumbnailer/engine.rb +0 -4
  84. data/lib/link_thumbnailer/fetcher.rb +0 -34
  85. data/lib/link_thumbnailer/img_comparator.rb +0 -17
  86. data/lib/link_thumbnailer/img_parser.rb +0 -41
  87. data/lib/link_thumbnailer/img_url_filter.rb +0 -13
  88. data/lib/link_thumbnailer/object.rb +0 -41
  89. data/lib/link_thumbnailer/opengraph.rb +0 -20
  90. data/lib/link_thumbnailer/rails/routes/mapper.rb +0 -30
  91. data/lib/link_thumbnailer/rails/routes/mapping.rb +0 -33
  92. data/lib/link_thumbnailer/rails/routes.rb +0 -47
  93. data/lib/link_thumbnailer/web_image.rb +0 -19
  94. data/spec/doc_parser_spec.rb +0 -25
  95. data/spec/doc_spec.rb +0 -23
  96. data/spec/examples/empty_example.html +0 -11
  97. data/spec/examples/og_example.html +0 -12
  98. data/spec/fetcher_spec.rb +0 -97
  99. data/spec/img_comparator_spec.rb +0 -16
  100. data/spec/img_url_filter_spec.rb +0 -31
  101. data/spec/link_thumbnailer_spec.rb +0 -205
  102. data/spec/object_spec.rb +0 -130
  103. data/spec/opengraph_spec.rb +0 -7
  104. data/spec/web_image_spec.rb +0 -57
@@ -6,10 +6,6 @@ module LinkThumbnailer
6
6
 
7
7
  desc 'Creates a LinkThumbnailer initializer for your application.'
8
8
 
9
- def install
10
- route "use_link_thumbnailer"
11
- end
12
-
13
9
  def copy_initializer
14
10
  template 'initializer.rb', 'config/initializers/link_thumbnailer.rb'
15
11
  end
@@ -1,41 +1,63 @@
1
- # Use this hook to configure LinkThumbnailer bahaviors.
2
- LinkThumbnailer.configure do |config|
3
- # Set mandatory attributes require for the website to be valid.
4
- # You can set `strict` to false if you want to skip this validation.
5
- # config.mandatory_attributes = %w(url title image)
6
-
7
- # Whether you want to validate given website against mandatory attributes or not.
8
- # config.strict = true
9
-
10
- # Numbers of redirects before raising an exception when trying to parse given url.
11
- # config.redirect_limit = 3
12
-
13
- # List of blacklisted urls you want to skip when searching for images.
14
- # config.blacklist_urls = [
15
- # %r{^http://ad\.doubleclick\.net/},
16
- # %r{^http://b\.scorecardresearch\.com/},
17
- # %r{^http://pixel\.quantserve\.com/},
18
- # %r{^http://s7\.addthis\.com/}
19
- # ]
20
-
21
- # Included Rmagick attributes for images. See http://www.imagemagick.org/RMagick/doc/
22
- # for more details.
23
- # 'source_url' is a custom attribute and should always be included since this
24
- # is where you'll find the image url.
25
- # config.image_attributes = %w(source_url size type)
26
-
27
- # Fetch 10 images maximum.
28
- # config.limit = 10
29
-
30
- # Return top 5 images only.
31
- # config.top = 5
32
-
33
- # Set user agent
34
- # config.user_agent = 'linkthumbnailer'
35
-
36
- # Enable or disable SSL verification
37
- # config.verify_ssl = true
38
-
39
- # HTTP open_timeout: The amount of time in seconds to wait for a connection to be opened.
40
- # config.http_timeout = 5
41
- end
1
+ # Use this hook to configure LinkThumbnailer bahaviors.
2
+ LinkThumbnailer.configure do |config|
3
+ # Numbers of redirects before raising an exception when trying to parse given url.
4
+ #
5
+ # config.redirect_limit = 3
6
+
7
+ # Set user agent
8
+ #
9
+ # config.user_agent = 'link_thumbnailer'
10
+
11
+ # Enable or disable SSL verification
12
+ #
13
+ # config.verify_ssl = true
14
+
15
+ # The amount of time in seconds to wait for a connection to be opened.
16
+ # If the HTTP object cannot open a connection in this many seconds,
17
+ # it raises a Net::OpenTimeout exception.
18
+ #
19
+ # See http://www.ruby-doc.org/stdlib-2.1.1/libdoc/net/http/rdoc/Net/HTTP.html#open_timeout
20
+ #
21
+ # config.http_timeout = 5
22
+
23
+ # List of blacklisted urls you want to skip when searching for images.
24
+ #
25
+ # config.blacklist_urls = [
26
+ # %r{^http://ad\.doubleclick\.net/},
27
+ # %r{^http://b\.scorecardresearch\.com/},
28
+ # %r{^http://pixel\.quantserve\.com/},
29
+ # %r{^http://s7\.addthis\.com/}
30
+ # ]
31
+
32
+ # List of attributes you want LinkThumbnailer to fetch on a website.
33
+ #
34
+ # config.attributes = [:title, :images, :description]
35
+
36
+ # List of procedures used to rate the website description. Add you custom class
37
+ # here. Note that the order matter to compute the score. See wiki for more details
38
+ # on how to build your own graders.
39
+ #
40
+ # config.graders = [
41
+ # ->(description) { ::LinkThumbnailer::Graders::Length.new(description) },
42
+ # ->(description) { ::LinkThumbnailer::Graders::HtmlAttribute.new(description, :class) },
43
+ # ->(description) { ::LinkThumbnailer::Graders::HtmlAttribute.new(description, :id) },
44
+ # ->(description) { ::LinkThumbnailer::Graders::Position.new(description) },
45
+ # ->(description) { ::LinkThumbnailer::Graders::LinkDensity.new(description) }
46
+ # ]
47
+
48
+ # Minimum description length for a website.
49
+ #
50
+ # config.description_min_length = 25
51
+
52
+ # Regex of words considered positive to rate website description.
53
+ #
54
+ # config.positive_regex = /article|body|content|entry|hentry|main|page|pagination|post|text|blog|story/i
55
+
56
+ # Regex of words considered negative to rate website description.
57
+ #
58
+ # config.negative_regex = /combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|shoutbox|sidebar|sponsor|shopping|tags|tool|widget|modal/i
59
+
60
+ # Numbers of images to fetch. Fetching too many images will be slow.
61
+ #
62
+ # config.image_limit = 5
63
+ end
@@ -1,16 +1,58 @@
1
- require 'hashie'
2
-
3
1
  module LinkThumbnailer
4
- class Configuration < Hashie::Mash
5
2
 
6
- def rmagick_attributes
7
- LinkThumbnailer.logger.info "[DEPRECATION] rmagick_attributes is deprecated. Use image_attributes instead."
8
- image_attributes
9
- end
3
+ # Access point for the gem configurations.
4
+ #
5
+ # @return [LinkThumbnailer::Configuration] a configuration instance.
6
+ def self.config
7
+ @config ||= Configuration.new
8
+ end
9
+
10
+ # Configure hook used in the gem initializer. Convinient way to set all the
11
+ # gem configurations.
12
+ #
13
+ # @example inside config/initializers/link_thumbnaler.rb
14
+ # LinkThumbnailer.configure do |config|
15
+ # config.user_agent = 'link_thumbnailer'
16
+ # end
17
+ #
18
+ # @return [void]
19
+ def self.configure
20
+ yield config if block_given?
21
+ end
22
+
23
+ class Configuration
24
+
25
+ attr_accessor :redirect_limit, :blacklist_urls, :user_agent,
26
+ :verify_ssl, :http_timeout, :attributes, :graders,
27
+ :description_min_length, :positive_regex, :negative_regex,
28
+ :image_limit
10
29
 
11
- def rmagick_attributes=(value)
12
- LinkThumbnailer.logger.info "[DEPRECATION] rmagick_attributes is deprecated. Use image_attributes instead."
13
- self.image_attributes = value
30
+ # Create a new instance.
31
+ #
32
+ # @return [LinkThumbnailer::Configuration]
33
+ def initialize
34
+ @redirect_limit = 3
35
+ @user_agent = 'link_thumbnailer'
36
+ @verify_ssl = true
37
+ @http_timeout = 5
38
+ @blacklist_urls = [
39
+ %r{^http://ad\.doubleclick\.net/},
40
+ %r{^http://b\.scorecardresearch\.com/},
41
+ %r{^http://pixel\.quantserve\.com/},
42
+ %r{^http://s7\.addthis\.com/}
43
+ ]
44
+ @attributes = [:title, :images, :description]
45
+ @graders = [
46
+ ->(description) { ::LinkThumbnailer::Graders::Length.new(description) },
47
+ ->(description) { ::LinkThumbnailer::Graders::HtmlAttribute.new(description, :class) },
48
+ ->(description) { ::LinkThumbnailer::Graders::HtmlAttribute.new(description, :id) },
49
+ ->(description) { ::LinkThumbnailer::Graders::Position.new(description) },
50
+ ->(description) { ::LinkThumbnailer::Graders::LinkDensity.new(description) }
51
+ ]
52
+ @description_min_length = 25
53
+ @positive_regex = /article|body|content|entry|hentry|main|page|pagination|post|text|blog|story/i
54
+ @negative_regex = /combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|shoutbox|sidebar|sponsor|shopping|tags|tool|widget|modal/i
55
+ @image_limit = 5
14
56
  end
15
57
 
16
58
  end
@@ -0,0 +1,6 @@
1
+ module LinkThumbnailer
2
+ class Exceptions < StandardError; end
3
+ class RedirectLimit < Exceptions; end
4
+ class BadUriFormat < Exceptions; end
5
+ class ScraperInvalid < Exceptions; end
6
+ end
@@ -0,0 +1,37 @@
1
+ require 'delegate'
2
+ require 'link_thumbnailer/graders/base'
3
+ require 'link_thumbnailer/graders/length'
4
+ require 'link_thumbnailer/graders/html_attribute'
5
+ require 'link_thumbnailer/graders/link_density'
6
+ require 'link_thumbnailer/graders/position'
7
+
8
+ module LinkThumbnailer
9
+ class Grader < ::SimpleDelegator
10
+
11
+ attr_reader :config, :description
12
+
13
+ def initialize(description)
14
+ @config = ::LinkThumbnailer.page.config
15
+ @description = description
16
+
17
+ super(config)
18
+ end
19
+
20
+ def call
21
+ score = 0
22
+ graders.each do |lambda|
23
+ instance = lambda.call(description)
24
+ score += instance.call(score)
25
+ end
26
+
27
+ score
28
+ end
29
+
30
+ private
31
+
32
+ def graders
33
+ config.graders
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,32 @@
1
+ require 'delegate'
2
+
3
+ module LinkThumbnailer
4
+ module Graders
5
+ class Base < ::SimpleDelegator
6
+
7
+ attr_reader :config, :description
8
+
9
+ def initialize(description)
10
+ @config = ::LinkThumbnailer.page.config
11
+ @description = description
12
+
13
+ super(config)
14
+ end
15
+
16
+ def call(current_score)
17
+ raise 'must implement'
18
+ end
19
+
20
+ private
21
+
22
+ def node
23
+ description.node
24
+ end
25
+
26
+ def text
27
+ node.text
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,49 @@
1
+ module LinkThumbnailer
2
+ module Graders
3
+ class HtmlAttribute < ::LinkThumbnailer::Graders::Base
4
+
5
+ attr_reader :attribute_name
6
+
7
+ def initialize(description, attribute_name)
8
+ super(description)
9
+ @attribute_name = attribute_name.to_sym
10
+ end
11
+
12
+ def call(current_score)
13
+ return 0 unless attribute?
14
+
15
+ score = 0
16
+ score -= 25 if negative?
17
+ score += 25 if positive?
18
+ score
19
+ end
20
+
21
+ private
22
+
23
+ def attribute
24
+ node[attribute_name]
25
+ end
26
+
27
+ def attribute?
28
+ attribute && !attribute.empty?
29
+ end
30
+
31
+ def negative?
32
+ attribute =~ negative_regex
33
+ end
34
+
35
+ def positive?
36
+ attribute =~ positive_regex
37
+ end
38
+
39
+ def negative_regex
40
+ config.negative_regex
41
+ end
42
+
43
+ def positive_regex
44
+ config.positive_regex
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ module LinkThumbnailer
2
+ module Graders
3
+ class Length < ::LinkThumbnailer::Graders::Base
4
+
5
+ def call(current_score)
6
+ return -Float::INFINITY if too_short?
7
+
8
+ [(text.length / 100).to_i, 3].min
9
+ end
10
+
11
+ private
12
+
13
+ def too_short?
14
+ text.length < config.description_min_length
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module LinkThumbnailer
2
+ module Graders
3
+ class LinkDensity < ::LinkThumbnailer::Graders::Base
4
+
5
+ def call(current_score)
6
+ current_score *= (1 - density)
7
+ end
8
+
9
+ private
10
+
11
+ def density
12
+ links.length / text.length.to_f
13
+ end
14
+
15
+ def links
16
+ node.css('a').map(&:text)
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module LinkThumbnailer
2
+ module Graders
3
+ class Position < ::LinkThumbnailer::Graders::Base
4
+
5
+ def call(current_score)
6
+ 2.0 / description.position
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ require 'link_thumbnailer/image_comparators/base'
2
+ require 'link_thumbnailer/image_comparators/size'
3
+
4
+ module LinkThumbnailer
5
+ class ImageComparator
6
+
7
+ attr_reader :image
8
+
9
+ def initialize(image)
10
+ @image = image
11
+ end
12
+
13
+ def call(other)
14
+ size_comparator.call(other)
15
+ end
16
+
17
+ private
18
+
19
+ def size_comparator
20
+ ::LinkThumbnailer::ImageComparators::Size.new(image)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ module LinkThumbnailer
2
+ module ImageComparators
3
+ class Base
4
+
5
+ attr_reader :image
6
+
7
+ def initialize(image)
8
+ @image = image
9
+ end
10
+
11
+ def call
12
+ raise 'you must implement this method'
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module LinkThumbnailer
2
+ module ImageComparators
3
+ class Size < ::LinkThumbnailer::ImageComparators::Base
4
+
5
+ def call(other)
6
+ (other.size.min ** 2) <=> (image.size.min ** 2)
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ require 'link_thumbnailer/image_parsers/size'
2
+ require 'link_thumbnailer/image_parsers/type'
3
+
4
+ module LinkThumbnailer
5
+ class ImageParser
6
+ class << self
7
+
8
+ def size(image)
9
+ ::LinkThumbnailer::ImageParsers::Size.perform(image)
10
+ end
11
+
12
+ def type(image)
13
+ ::LinkThumbnailer::ImageParsers::Type.perform(image)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ require 'fastimage'
2
+
3
+ module LinkThumbnailer
4
+ module ImageParsers
5
+ class Size
6
+
7
+ def self.perform(image)
8
+ ::FastImage.size(image.src, raise_on_failure: true)
9
+ rescue ::FastImage::FastImageException
10
+ [0, 0]
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'fastimage'
2
+
3
+ module LinkThumbnailer
4
+ module ImageParsers
5
+ class Type
6
+
7
+ def self.perform(image)
8
+ ::FastImage.type(image.src, raise_on_failure: true)
9
+ rescue ::FastImage::FastImageException
10
+ :jpg
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ require 'delegate'
2
+
3
+ module LinkThumbnailer
4
+ class ImageValidator < ::SimpleDelegator
5
+
6
+ attr_reader :config, :image
7
+
8
+ def initialize(image)
9
+ @config = ::LinkThumbnailer.page.config
10
+ @image = image
11
+
12
+ super(config)
13
+ end
14
+
15
+ def call
16
+ blacklist_urls.each do |url|
17
+ return false if image.src && image.src.to_s[url]
18
+ end
19
+
20
+ true
21
+ end
22
+
23
+ private
24
+
25
+ def blacklist_urls
26
+ config.blacklist_urls
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ module LinkThumbnailer
2
+ class Model
3
+
4
+ def to_json(*args)
5
+ as_json.to_json(*args)
6
+ end
7
+
8
+ private
9
+
10
+ def sanitize(str)
11
+ return unless str
12
+ str.strip.gsub(/[\r\n\f]+/, "\n")
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,34 @@
1
+ require 'link_thumbnailer/model'
2
+ require 'link_thumbnailer/grader'
3
+
4
+ module LinkThumbnailer
5
+ module Models
6
+ class Description < ::LinkThumbnailer::Model
7
+
8
+ attr_reader :node, :text, :position
9
+ attr_accessor :score
10
+
11
+ def initialize(node, text, position = 1)
12
+ @node = node
13
+ @text = sanitize(text)
14
+ @position = position
15
+ @score = compute_score
16
+ end
17
+
18
+ def to_s
19
+ text
20
+ end
21
+
22
+ def <=>(other)
23
+ score <=> other.score
24
+ end
25
+
26
+ private
27
+
28
+ def compute_score
29
+ ::LinkThumbnailer::Grader.new(self).call
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,54 @@
1
+ require 'link_thumbnailer/model'
2
+ require 'link_thumbnailer/image_parser'
3
+ require 'link_thumbnailer/image_comparator'
4
+ require 'link_thumbnailer/image_validator'
5
+
6
+ module LinkThumbnailer
7
+ module Models
8
+ class Image < ::LinkThumbnailer::Model
9
+
10
+ attr_reader :src, :type, :size
11
+
12
+ def initialize(src)
13
+ @src = src
14
+ @size = parser.size(self)
15
+ @type = parser.type(self)
16
+ end
17
+
18
+ def to_s
19
+ src.to_s
20
+ end
21
+
22
+ def <=>(other)
23
+ comparator.call(other)
24
+ end
25
+
26
+ def valid?
27
+ validator.call
28
+ end
29
+
30
+ def as_json(*)
31
+ {
32
+ src: src.to_s,
33
+ size: size,
34
+ type: type
35
+ }
36
+ end
37
+
38
+ private
39
+
40
+ def parser
41
+ ::LinkThumbnailer::ImageParser
42
+ end
43
+
44
+ def validator
45
+ ::LinkThumbnailer::ImageValidator.new(self)
46
+ end
47
+
48
+ def comparator
49
+ ::LinkThumbnailer::ImageComparator.new(self)
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,20 @@
1
+ require 'link_thumbnailer/model'
2
+
3
+ module LinkThumbnailer
4
+ module Models
5
+ class Title < ::LinkThumbnailer::Model
6
+
7
+ attr_reader :node, :text
8
+
9
+ def initialize(node, text = nil)
10
+ @node = node
11
+ @text = sanitize(text || node.text)
12
+ end
13
+
14
+ def to_s
15
+ text
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,39 @@
1
+ require 'link_thumbnailer/model'
2
+
3
+ module LinkThumbnailer
4
+ module Models
5
+ class Website < ::LinkThumbnailer::Model
6
+
7
+ attr_accessor :url, :title, :description, :images
8
+
9
+ def initialize
10
+ @images = []
11
+ end
12
+
13
+ def image=(image)
14
+ self.images = image
15
+ end
16
+
17
+ def images=(images)
18
+ Array(images).each do |image|
19
+ next unless image.valid?
20
+ @images << image
21
+ end
22
+ end
23
+
24
+ def images
25
+ @images.sort!
26
+ end
27
+
28
+ def as_json(*)
29
+ {
30
+ url: url.to_s,
31
+ title: title,
32
+ description: description,
33
+ images: images
34
+ }
35
+ end
36
+
37
+ end
38
+ end
39
+ end