link_thumbnailer 3.3.2

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.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +5 -0
  6. data/CHANGELOG.md +334 -0
  7. data/Gemfile +12 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +210 -0
  10. data/Rakefile +9 -0
  11. data/lib/generators/link_thumbnailer/install_generator.rb +17 -0
  12. data/lib/generators/templates/initializer.rb +89 -0
  13. data/lib/link_thumbnailer.rb +38 -0
  14. data/lib/link_thumbnailer/configuration.rb +72 -0
  15. data/lib/link_thumbnailer/exceptions.rb +11 -0
  16. data/lib/link_thumbnailer/grader.rb +43 -0
  17. data/lib/link_thumbnailer/graders/base.rb +39 -0
  18. data/lib/link_thumbnailer/graders/html_attribute.rb +48 -0
  19. data/lib/link_thumbnailer/graders/length.rb +37 -0
  20. data/lib/link_thumbnailer/graders/link_density.rb +20 -0
  21. data/lib/link_thumbnailer/graders/position.rb +13 -0
  22. data/lib/link_thumbnailer/image_comparator.rb +26 -0
  23. data/lib/link_thumbnailer/image_comparators/base.rb +19 -0
  24. data/lib/link_thumbnailer/image_comparators/size.rb +13 -0
  25. data/lib/link_thumbnailer/image_parser.rb +62 -0
  26. data/lib/link_thumbnailer/image_validator.rb +32 -0
  27. data/lib/link_thumbnailer/model.rb +20 -0
  28. data/lib/link_thumbnailer/models/description.rb +37 -0
  29. data/lib/link_thumbnailer/models/favicon.rb +27 -0
  30. data/lib/link_thumbnailer/models/image.rb +56 -0
  31. data/lib/link_thumbnailer/models/title.rb +22 -0
  32. data/lib/link_thumbnailer/models/video.rb +44 -0
  33. data/lib/link_thumbnailer/models/website.rb +54 -0
  34. data/lib/link_thumbnailer/page.rb +43 -0
  35. data/lib/link_thumbnailer/parser.rb +15 -0
  36. data/lib/link_thumbnailer/processor.rb +128 -0
  37. data/lib/link_thumbnailer/railtie.rb +6 -0
  38. data/lib/link_thumbnailer/response.rb +39 -0
  39. data/lib/link_thumbnailer/scraper.rb +62 -0
  40. data/lib/link_thumbnailer/scrapers/base.rb +69 -0
  41. data/lib/link_thumbnailer/scrapers/default/base.rb +12 -0
  42. data/lib/link_thumbnailer/scrapers/default/description.rb +49 -0
  43. data/lib/link_thumbnailer/scrapers/default/favicon.rb +38 -0
  44. data/lib/link_thumbnailer/scrapers/default/images.rb +78 -0
  45. data/lib/link_thumbnailer/scrapers/default/title.rb +27 -0
  46. data/lib/link_thumbnailer/scrapers/default/videos.rb +18 -0
  47. data/lib/link_thumbnailer/scrapers/opengraph/base.rb +45 -0
  48. data/lib/link_thumbnailer/scrapers/opengraph/description.rb +12 -0
  49. data/lib/link_thumbnailer/scrapers/opengraph/favicon.rb +17 -0
  50. data/lib/link_thumbnailer/scrapers/opengraph/image.rb +107 -0
  51. data/lib/link_thumbnailer/scrapers/opengraph/images.rb +18 -0
  52. data/lib/link_thumbnailer/scrapers/opengraph/title.rb +12 -0
  53. data/lib/link_thumbnailer/scrapers/opengraph/video.rb +115 -0
  54. data/lib/link_thumbnailer/scrapers/opengraph/videos.rb +18 -0
  55. data/lib/link_thumbnailer/uri.rb +20 -0
  56. data/lib/link_thumbnailer/version.rb +5 -0
  57. data/lib/link_thumbnailer/video_parser.rb +47 -0
  58. data/link_thumbnailer.gemspec +29 -0
  59. data/spec/configuration_spec.rb +61 -0
  60. data/spec/fixture_spec.rb +114 -0
  61. data/spec/fixtures/bar.png +2907 -0
  62. data/spec/fixtures/default_from_body.html +13 -0
  63. data/spec/fixtures/default_from_meta.html +12 -0
  64. data/spec/fixtures/foo.png +0 -0
  65. data/spec/fixtures/google_shift_jis.html +6 -0
  66. data/spec/fixtures/google_utf8.html +6 -0
  67. data/spec/fixtures/og_not_valid_example.html +12 -0
  68. data/spec/fixtures/og_valid_example.html +18 -0
  69. data/spec/fixtures/og_valid_multi_image_example.html +13 -0
  70. data/spec/fixtures/og_valid_multi_video_example.html +13 -0
  71. data/spec/grader_spec.rb +27 -0
  72. data/spec/graders/base_spec.rb +14 -0
  73. data/spec/graders/html_attribute_spec.rb +50 -0
  74. data/spec/graders/length_spec.rb +93 -0
  75. data/spec/graders/link_density_spec.rb +52 -0
  76. data/spec/graders/position_spec.rb +49 -0
  77. data/spec/image_comparators/size_spec.rb +58 -0
  78. data/spec/image_validator_spec.rb +37 -0
  79. data/spec/model_spec.rb +27 -0
  80. data/spec/models/description_spec.rb +66 -0
  81. data/spec/models/favicon_spec.rb +12 -0
  82. data/spec/models/image_spec.rb +95 -0
  83. data/spec/models/title_spec.rb +26 -0
  84. data/spec/models/video_spec.rb +49 -0
  85. data/spec/models/website_spec.rb +51 -0
  86. data/spec/page_spec.rb +28 -0
  87. data/spec/processor_spec.rb +410 -0
  88. data/spec/response_spec.rb +62 -0
  89. data/spec/scraper_spec.rb +70 -0
  90. data/spec/scrapers/base_spec.rb +69 -0
  91. data/spec/scrapers/opengraph/base_spec.rb +96 -0
  92. data/spec/spec_helper.rb +11 -0
  93. data/spec/uri_spec.rb +44 -0
  94. data/spec/video_parser_spec.rb +148 -0
  95. metadata +271 -0
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe LinkThumbnailer::Response do
6
+ let(:url) { 'https://www.google.co.jp' }
7
+ let(:page) { ::LinkThumbnailer::Page.new(url, {}) }
8
+
9
+ let(:response) do
10
+ r = ::Net::HTTPSuccess.new('', 200, body_shift_jis)
11
+ r['Content-Type'] = 'text/html'
12
+ r.body = body_shift_jis
13
+ r.instance_variable_set(:@read, true)
14
+ r
15
+ end
16
+
17
+ let(:instance) { described_class.new(response) }
18
+
19
+ let(:body_shift_jis) do
20
+ File.read(File.expand_path('fixtures/google_shift_jis.html', File.dirname(__FILE__)))
21
+ end
22
+
23
+ let(:body_utf8) do
24
+ File.read(File.expand_path('fixtures/google_utf8.html', File.dirname(__FILE__)))
25
+ end
26
+
27
+ before do
28
+ allow(LinkThumbnailer).to receive(:page).and_return(page)
29
+ end
30
+
31
+ describe '#charset' do
32
+ context 'when charset provided in content-type' do
33
+ before do
34
+ response['Content-Type'] = 'text/html; charset=Shift_JIS'
35
+ end
36
+
37
+ it { expect(instance.charset).to eq 'Shift_JIS' }
38
+ end
39
+
40
+ context 'when no charset available in content-type' do
41
+ it { expect(instance.charset).to eq '' }
42
+ end
43
+ end
44
+
45
+ describe '#body' do
46
+ context 'when provide valid charset' do
47
+ before do
48
+ response['Content-Type'] = 'text/html; charset=Shift_JIS'
49
+ end
50
+
51
+ it { expect(instance.body).to eq body_utf8 }
52
+ end
53
+
54
+ context 'when provide invalid charset' do
55
+ before do
56
+ response['Content-Type'] = 'text/html; charset=Shift-JIS'
57
+ end
58
+
59
+ it { expect(instance.body).to eq body_shift_jis }
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe LinkThumbnailer::Scraper do
6
+
7
+ let(:source) { '' }
8
+ let(:url) { 'http://foo.com' }
9
+ let(:document) { double('document') }
10
+ let(:website) { double('website') }
11
+ let(:instance) { described_class.new(source, url) }
12
+
13
+ before do
14
+ allow(instance).to receive(:document).and_return(document)
15
+ allow(instance).to receive(:website).and_return(website)
16
+ end
17
+
18
+ describe '#call' do
19
+
20
+ let(:prefix_1) { 'prefix_1' }
21
+ let(:prefix_2) { 'prefix_2' }
22
+ let(:scraper_class) { double('scraper_class') }
23
+ let(:scraper) { double('scraper', call: true) }
24
+ let(:attributes) { [:bar] }
25
+ let(:scrapers) { [prefix_1, prefix_2] }
26
+ let(:action) { instance.call }
27
+ let(:config) { double(attributes: attributes, scrapers: scrapers) }
28
+
29
+ before do
30
+ allow(instance).to receive(:config).and_return(config)
31
+ end
32
+
33
+ context 'when first one return a result' do
34
+
35
+ let(:valid_scraper) { double('scraper') }
36
+ let(:not_valid_scraper) { double('scraper') }
37
+
38
+ before do
39
+ expect(website).to receive(:bar).once.and_return('bar')
40
+ expect(valid_scraper).to receive(:call).once.with('bar')
41
+ expect(not_valid_scraper).to_not receive(:call).with('bar')
42
+ expect(scraper_class).to receive(:new).with(document, website).once.and_return(valid_scraper)
43
+ expect(instance).to receive(:scraper_class).with(prefix_1, :bar).and_return(scraper_class)
44
+ end
45
+
46
+ it { expect(action).to eq(website) }
47
+
48
+ end
49
+
50
+ context 'when first one does not return any result' do
51
+
52
+ let(:valid_scraper) { double('scraper') }
53
+ let(:not_valid_scraper) { double('scraper') }
54
+
55
+ before do
56
+ expect(website).to receive(:bar).and_return('', 'bar')
57
+ expect(valid_scraper).to receive(:call).once.with('bar')
58
+ expect(not_valid_scraper).to receive(:call).once.with('bar')
59
+ expect(scraper_class).to receive(:new).with(document, website).and_return(not_valid_scraper, valid_scraper)
60
+ expect(instance).to receive(:scraper_class).with(prefix_1, :bar).and_return(scraper_class)
61
+ expect(instance).to receive(:scraper_class).with(prefix_2, :bar).and_return(scraper_class)
62
+ end
63
+
64
+ it { expect(action).to eq(website) }
65
+
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe LinkThumbnailer::Scrapers::Base do
6
+
7
+ let(:document) { double('document') }
8
+ let(:website) { LinkThumbnailer::Models::Website.new }
9
+ let(:instance) { described_class.new(document, website) }
10
+
11
+ describe '#call' do
12
+
13
+ let(:attr) { :title }
14
+ let(:value) { 'foo' }
15
+ let(:action) { instance.call(attr) }
16
+
17
+ before do
18
+ allow(instance).to receive(:value).and_return(value)
19
+ end
20
+
21
+ it { expect { action }.to change { website.title }.from(nil).to(value) }
22
+
23
+ end
24
+
25
+ describe '#model_class' do
26
+
27
+ let(:action) { instance.send(:model_class) }
28
+
29
+ before do
30
+ allow(instance).to receive(:attribute_name).and_return(attr)
31
+ end
32
+
33
+ context 'when internal class exists' do
34
+
35
+ let(:attr) { :title }
36
+
37
+ it { expect(action).to eq(::LinkThumbnailer::Models::Title) }
38
+
39
+ end
40
+
41
+ context 'when internal class does not exists' do
42
+
43
+ let(:attr) { :foo }
44
+
45
+ it { expect { action }.to raise_error(NameError) }
46
+
47
+ end
48
+
49
+ end
50
+
51
+ describe '#modelize' do
52
+
53
+ let(:node) { double('node') }
54
+ let(:text) { 'foo' }
55
+ let(:model_class) { double('model_class') }
56
+ let(:action) { instance.send(:modelize, node, text) }
57
+
58
+ before do
59
+ allow(instance).to receive(:model_class).and_return(model_class)
60
+ end
61
+
62
+ it 'instantiates a new model' do
63
+ expect(model_class).to receive(:new).with(node, text)
64
+ action
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe LinkThumbnailer::Scrapers::Opengraph::Base do
6
+
7
+ let(:node) { double('node') }
8
+ let(:document) { double('document') }
9
+ let(:instance) { described_class.new(document) }
10
+
11
+ describe '#applicable?' do
12
+
13
+ let(:meta) { [node, node] }
14
+ let(:action) { instance.applicable? }
15
+
16
+ before do
17
+ allow(instance).to receive(:meta).and_return(meta)
18
+ end
19
+
20
+ context 'when all node is an opengraph' do
21
+
22
+ before do
23
+ allow(instance).to receive(:opengraph_node?).and_return(true, true)
24
+ end
25
+
26
+ it { expect(action).to be_truthy }
27
+
28
+ end
29
+
30
+ context 'when any node is an opengraph' do
31
+
32
+ before do
33
+ allow(instance).to receive(:opengraph_node?).and_return(true, false)
34
+ end
35
+
36
+ it { expect(action).to be_truthy }
37
+
38
+ end
39
+
40
+ context 'when no node is an opengraph' do
41
+
42
+ before do
43
+ allow(instance).to receive(:opengraph_node?).and_return(false, false)
44
+ end
45
+
46
+ it { expect(action).to be_falsey }
47
+
48
+ end
49
+
50
+ end
51
+
52
+ describe '#opengraph_node?' do
53
+
54
+ let(:action) { instance.send(:opengraph_node?, node) }
55
+
56
+ before do
57
+ allow(node).to receive(:attribute).with('name').and_return(attribute_from_name)
58
+ end
59
+
60
+ context 'with attribute from name valid' do
61
+
62
+ let(:attribute_from_name) { 'og:foo' }
63
+
64
+ it { expect(action).to be_truthy }
65
+
66
+ end
67
+
68
+ context 'with attribute from name not valid' do
69
+
70
+ let(:attribute_from_name) { 'foo' }
71
+
72
+ before do
73
+ allow(node).to receive(:attribute).with('property').and_return(attribute_from_property)
74
+ end
75
+
76
+ context 'and attribute from property valid' do
77
+
78
+ let(:attribute_from_property) { 'og:bar' }
79
+
80
+ it { expect(action).to be_truthy }
81
+
82
+ end
83
+
84
+ context 'and attribute from property not valid' do
85
+
86
+ let(:attribute_from_property) { 'bar' }
87
+
88
+ it { expect(action).to be_falsey }
89
+
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'link_thumbnailer'
4
+ require 'rspec'
5
+ require 'webmock/rspec'
6
+
7
+ RSpec.configure do |config|
8
+ config.expect_with :rspec do |c|
9
+ c.syntax = :expect
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe LinkThumbnailer::URI do
6
+
7
+ let(:uri) { 'http://foo.com' }
8
+ let(:instance) { described_class.new(uri) }
9
+
10
+ describe '#valid?' do
11
+
12
+ let(:action) { instance.send(:valid?) }
13
+
14
+ context 'when bad format' do
15
+
16
+ before do
17
+ allow(instance).to receive(:attribute).and_return("/invalid/path")
18
+ end
19
+
20
+ it { expect(action).to be_falsey }
21
+
22
+ end
23
+
24
+ context 'when valid format' do
25
+
26
+ before do
27
+ allow(instance).to receive(:attribute).and_return("http://foo.com")
28
+ end
29
+
30
+ it { expect(action).to be_truthy }
31
+
32
+ end
33
+
34
+ end
35
+
36
+ describe '#to_s' do
37
+
38
+ let(:action) { instance.to_s }
39
+
40
+ it { expect(action).to eq(uri) }
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe LinkThumbnailer::VideoParser do
6
+
7
+ let(:src) { 'http://foo.com/foo.swf' }
8
+ let(:video) { double(src: src) }
9
+ let(:parser) { double('parser') }
10
+ let(:instance) { described_class.new(video) }
11
+
12
+ before do
13
+ allow(instance).to receive(:parser).and_return(parser)
14
+ end
15
+
16
+ describe '#id' do
17
+
18
+ let(:action) { instance.id }
19
+
20
+ context 'when respond to video_id' do
21
+
22
+ before do
23
+ allow(parser).to receive(:video_id).and_return(1)
24
+ end
25
+
26
+ it { expect(action).to eq(parser.video_id) }
27
+
28
+ end
29
+
30
+ context 'when do not respond to video_id' do
31
+
32
+ before do
33
+ allow(parser).to receive(:video_id).and_raise(NoMethodError)
34
+ end
35
+
36
+ it { expect(action).to be_nil }
37
+
38
+ end
39
+
40
+ end
41
+
42
+ describe '#size' do
43
+
44
+ let(:action) { instance.size }
45
+
46
+ context 'when respond to width and height' do
47
+
48
+ before do
49
+ allow(parser).to receive(:width).and_return(1)
50
+ allow(parser).to receive(:height).and_return(1)
51
+ end
52
+
53
+ it { expect(action).to eq([parser.width, parser.height]) }
54
+
55
+ end
56
+
57
+ context 'when do not respond to width and height' do
58
+
59
+ before do
60
+ allow(parser).to receive(:width).and_raise(NoMethodError)
61
+ allow(parser).to receive(:height).and_raise(NoMethodError)
62
+ end
63
+
64
+ it { expect(action).to be_empty }
65
+
66
+ end
67
+
68
+ end
69
+
70
+ describe '#duration' do
71
+
72
+ let(:action) { instance.duration }
73
+
74
+ context 'when respond to duration' do
75
+
76
+ before do
77
+ allow(parser).to receive(:duration).and_return(1)
78
+ end
79
+
80
+ it { expect(action).to eq(parser.duration) }
81
+
82
+ end
83
+
84
+ context 'when do not respond to duration' do
85
+
86
+ before do
87
+ allow(parser).to receive(:duration).and_raise(NoMethodError)
88
+ end
89
+
90
+ it { expect(action).to be_nil }
91
+
92
+ end
93
+
94
+ end
95
+
96
+ describe '#provider' do
97
+
98
+ let(:action) { instance.provider }
99
+
100
+ context 'when respond to provider' do
101
+
102
+ before do
103
+ allow(parser).to receive(:provider).and_return(1)
104
+ end
105
+
106
+ it { expect(action).to eq(parser.provider) }
107
+
108
+ end
109
+
110
+ context 'when do not respond to provider' do
111
+
112
+ before do
113
+ allow(parser).to receive(:provider).and_raise(NoMethodError)
114
+ end
115
+
116
+ it { expect(action).to be_nil }
117
+
118
+ end
119
+
120
+ end
121
+
122
+ describe '#embed_code' do
123
+
124
+ let(:action) { instance.embed_code }
125
+
126
+ context 'when respond to embed_code' do
127
+
128
+ before do
129
+ allow(parser).to receive(:embed_code).and_return('')
130
+ end
131
+
132
+ it { expect(action).to eq(parser.embed_code) }
133
+
134
+ end
135
+
136
+ context 'when do not respond to embed_code' do
137
+
138
+ before do
139
+ allow(parser).to receive(:embed_code).and_raise(NoMethodError)
140
+ end
141
+
142
+ it { expect(action).to be_nil }
143
+
144
+ end
145
+
146
+ end
147
+
148
+ end