link_thumbnailer 3.3.0 → 3.3.1

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: 62e43acf3460b4ef3da648fa16fb8f3f970d88b8
4
- data.tar.gz: 4768729820579a8387d692ddba91a3557f548d60
3
+ metadata.gz: fef68fdf205078290139fd831a9b8d46581e64eb
4
+ data.tar.gz: 27a3e86b0181068e06bd80e8f053fca17d3a906b
5
5
  SHA512:
6
- metadata.gz: 1e4a5a30c0166b19f57a0e2dbc57fda86074ad26caa28fde4ad8c15e1afe278478c4ca27223a155b66ce777765a729e78f5a95ddd080abb535fa5b806eaeafbb
7
- data.tar.gz: 93464538468ced5cb85119c2e85219f592c33a91733bf1e89741d074253e9a540f949355258a723db38698e712c7c2d079ec6d75539fb249f48cb25109ab772b
6
+ metadata.gz: 5dcfa7683c65f546ce8e794d51c9d7103736fb3cf9f5919ddbcea611fbe7243faf3ef76ed372d99ea316a6d193032d9b47e48411dc9c0fb1c972d77c29bc2a2a
7
+ data.tar.gz: e041d9174be5b066fac70b70b965bc28b053235bffa808c0a109c3c1f10512643ae58dc21b3f8691ca3ff6a3b9f5346e31c4b0cf1430d16ac829244d3252ab96
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.4.0
data/.travis.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  bundler_args: --without development
2
2
  language: ruby
3
3
  rvm:
4
- - 2.2.0
4
+ - 2.2.2
5
+ - 2.4.0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 3.3.1
2
+
3
+ Gem upgrade (json)
4
+
1
5
  # 3.3.0
2
6
 
3
7
  - Allows to configure overrided http headers
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :development, :test do
7
- gem 'rspec', '~> 2.14'
8
- gem 'webmock', '~> 1.14'
9
- gem 'pry', '~> 0.9'
7
+ gem 'rspec', '~> 3.5.0'
8
+ gem 'webmock', '~> 2.3.2'
9
+ gem 'pry', '~> 0.10.4'
10
10
  end
data/README.md CHANGED
@@ -165,6 +165,10 @@ LinkThumbnailer.configure do |config|
165
165
  # Sets number of concurrent http connections that can be opened to fetch images informations such as size and type.
166
166
  #
167
167
  # config.max_concurrency = 20
168
+
169
+ # Sets the default encoding.
170
+ #
171
+ # config.encoding = 'utf-8'
168
172
  end
169
173
  ```
170
174
 
@@ -80,4 +80,8 @@ LinkThumbnailer.configure do |config|
80
80
  # Defines the strategies to use to scrap the website. See the [Open Graph Protocol](http://ogp.me/) for more information.
81
81
  #
82
82
  # config.scrapers = [:opengraph, :default]
83
+
84
+ # Sets the default encoding.
85
+ #
86
+ # config.encoding = 'utf-8'
83
87
  end
@@ -26,7 +26,7 @@ module LinkThumbnailer
26
26
  :verify_ssl, :http_open_timeout, :http_read_timeout, :attributes,
27
27
  :graders, :description_min_length, :positive_regex, :negative_regex,
28
28
  :image_limit, :image_stats, :raise_on_invalid_format, :max_concurrency,
29
- :scrapers, :http_override_headers
29
+ :scrapers, :http_override_headers, :encoding
30
30
 
31
31
  alias_method :http_timeout, :http_open_timeout
32
32
  alias_method :http_timeout=, :http_open_timeout=
@@ -63,6 +63,7 @@ module LinkThumbnailer
63
63
  @max_concurrency = 20
64
64
  @scrapers = [:opengraph, :default]
65
65
  @http_override_headers = { 'Accept-Encoding' => 'none' }
66
+ @encoding = 'utf-8'
66
67
  end
67
68
 
68
69
  end
@@ -1,3 +1,4 @@
1
+ require 'link_thumbnailer/response'
1
2
  require 'link_thumbnailer/processor'
2
3
  require 'link_thumbnailer/scraper'
3
4
 
@@ -4,7 +4,7 @@ module LinkThumbnailer
4
4
  class Parser
5
5
 
6
6
  def call(source)
7
- ::Nokogiri::HTML(source)
7
+ ::Nokogiri::HTML(source, nil, LinkThumbnailer.page.config.encoding)
8
8
  rescue ::Nokogiri::XML::SyntaxError => e
9
9
  raise ::LinkThumbnailer::SyntaxError.new(e.message)
10
10
  end
@@ -59,7 +59,7 @@ module LinkThumbnailer
59
59
 
60
60
  case response
61
61
  when ::Net::HTTPSuccess
62
- response.body
62
+ Response.new(response).body
63
63
  when ::Net::HTTPRedirection
64
64
  call(
65
65
  resolve_relative_url(response['location'].to_s),
@@ -0,0 +1,37 @@
1
+ module LinkThumbnailer
2
+ class Response
3
+ def initialize(response)
4
+ @response = response
5
+ end
6
+
7
+ def charset
8
+ @charset ||= extract_charset
9
+ end
10
+
11
+ def body
12
+ @body ||= extract_body
13
+ end
14
+
15
+ private
16
+
17
+ def extract_charset
18
+ content_type = @response['Content-Type'] || ''
19
+ m = content_type.match(/charset=(\w+)/)
20
+ (m && m[1]) || ''
21
+ end
22
+
23
+ def extract_body
24
+ should_convert_body_to_utf8? ? convert_encoding_to_utf8(@response.body, charset) : @response.body
25
+ end
26
+
27
+ def should_convert_body_to_utf8?
28
+ charset != '' && charset != 'utf-8'
29
+ end
30
+
31
+ def convert_encoding_to_utf8(body, from)
32
+ Encoding::Converter.new(from, 'utf-8').convert(body)
33
+ rescue EncodingError
34
+ body
35
+ end
36
+ end
37
+ end
@@ -1,3 +1,3 @@
1
1
  module LinkThumbnailer
2
- VERSION = '3.3.0'
2
+ VERSION = '3.3.1'
3
3
  end
@@ -18,10 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ['lib']
19
19
 
20
20
  spec.add_dependency 'activesupport', '>= 3.0'
21
- spec.add_dependency 'json', ['>= 1.7.7', '~> 1.8']
22
- spec.add_dependency 'rake', '>= 0.9'
23
- spec.add_dependency 'nokogiri', '~> 1.6'
24
- spec.add_dependency 'net-http-persistent', '~> 2.9'
25
- spec.add_dependency 'video_info', '~> 2.6'
26
- spec.add_dependency 'image_info', '~> 1.0'
21
+ spec.add_dependency 'json', '~> 2.1'
22
+ spec.add_dependency 'rake', ['>= 0.9']
23
+ spec.add_dependency 'nokogiri', '~> 1.7'
24
+ spec.add_dependency 'net-http-persistent', '~> 3.0'
25
+ spec.add_dependency 'video_info', '~> 2.7'
26
+ spec.add_dependency 'image_info', '~> 1.1'
27
27
  end
@@ -18,6 +18,7 @@ describe LinkThumbnailer::Configuration do
18
18
  it { expect(instance.image_limit).to eq(5) }
19
19
  it { expect(instance.image_stats).to eq(true) }
20
20
  it { expect(instance.max_concurrency).to eq(20) }
21
+ it { expect(instance.encoding).to eq('utf-8') }
21
22
 
22
23
  describe "#http_timeout" do
23
24
  it { expect(instance.method(:http_timeout)).to eq(instance.method(:http_open_timeout)) }
@@ -33,7 +34,7 @@ describe LinkThumbnailer::Configuration do
33
34
  describe '.configure' do
34
35
 
35
36
  before do
36
- LinkThumbnailer.stub(:config).and_return(instance)
37
+ allow(LinkThumbnailer).to receive(:config).and_return(instance)
37
38
  end
38
39
 
39
40
  context 'when block given' do
@@ -56,4 +57,3 @@ describe LinkThumbnailer::Configuration do
56
57
  end
57
58
 
58
59
  end
59
-
@@ -0,0 +1,6 @@
1
+ <!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="���E���̂���������������邽�߂̃c�[����񋟂��Ă��܂��B���܂��܂Ȍ����@�\�����p���āA���T���̏������‚��Ă��������B" name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script>(function(){window.google={kEI:'716VWJL3JYq18QWo_qzoAg',kEXPI:'750722,1351903,1352241,1352381,3700253,3700347,4028875,4029815,4032677,4038012,4043492,4045839,4048347,4062666,4065787,4068816,4069773,4069838,4069840,4070138,4072773,4073405,4073726,4073959,4076096,4076931,4076999,4077777,4078438,4079081,4079105,4079894,4081038,4081485,4082194,4082201,4082298,4082619,4083044,4083476,4084343,4084673,4085336,4085412,4085683,4086011,4089003,4089144,4089183,4089427,4089538,4089913,4090414,4090547,4090549,4090598,4090657,4090806,4090893,4091966,4092028,4092182,4092218,4092474,4092478,4092598,4092864,4092867,4092875,4092897,4092934,4093073,4093948,4094169,4094250,4094769,4094987,4094997,4095554,4095771,4095907,4095998,8300096,8300272,8507380,8507419,8507861,8507940,8508624,8510023,10200083,13500022,13500024',authuser:0,kscs:'c9c918f0_24'};google.kHL='ja';})();(function(){google.lc=[];google.li=0;google.getEI=function(a){for(var b;a&&(!a.getAttribute||!(b=a.getAttribute("eid")));)a=a.parentNode;return b||google.kEI};google.getLEI=function(a){for(var b=null;a&&(!a.getAttribute||!(b=a.getAttribute("leid")));)a=a.parentNode;return b};google.https=function(){return"https:"==window.location.protocol};google.ml=function(){return null};google.wl=function(a,b){try{google.ml(Error(a),!1,b)}catch(c){}};google.time=function(){return(new Date).getTime()};google.log=function(a,b,c,d,g){a=google.logUrl(a,b,c,d,g);if(""!=a){b=new Image;var e=google.lc,f=google.li;e[f]=b;b.onerror=b.onload=b.onabort=function(){delete e[f]};window.google&&window.google.vel&&window.google.vel.lu&&window.google.vel.lu(a);b.src=a;google.li=f+1}};google.logUrl=function(a,b,c,d,g){var e="",f=google.ls||"";c||-1!=b.search("&ei=")||(e="&ei="+google.getEI(d),-1==b.search("&lei=")&&(d=google.getLEI(d))&&(e+="&lei="+d));a=c||"/"+(g||"gen_204")+"?atyp=i&ct="+a+"&cad="+b+e+f+"&zx="+google.time();/^http:/i.test(a)&&google.https()&&(google.ml(Error("a"),!1,{src:a,glmm:1}),a="");return a};google.y={};google.x=function(a,b){google.y[a.id]=[a,b];return!1};google.lq=[];google.load=function(a,b,c){google.lq.push([[a],b,c])};google.loadAll=function(a,b){google.lq.push([a,b])};}).call(this);var a=window.location,b=a.href.indexOf("#");if(0<=b){var c=a.href.substring(b+1);/(^|&)q=/.test(c)&&-1==c.indexOf("#")&&a.replace("/search?"+c.replace(/(^|&)fp=[^&]*/g,"")+"&cad=h")};</script><style>#gbar,#guser{font-size:13px;padding-top:1px !important;}#gbar{height:22px}#guser{padding-bottom:7px !important;text-align:right}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}@media all{.gb1{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb4{text-decoration:underline !important}a.gb1,a.gb4{color:#00c !important}.gbi .gb4{color:#dd8e27 !important}.gbf .gb4{color:#900 !important}
2
+ </style><style>body,td,a,p,.h{font-family:arial,sans-serif}body{margin:0;overflow-y:scroll}#gog{padding:3px 8px 0}td{line-height:.8em}.gac_m td{line-height:17px}form{margin-bottom:20px}.h{color:#36c}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{height:25px;width:496px}.gsfi,.lst{font:18px arial,sans-serif}.gsfs{font:17px arial,sans-serif}.ds{display:inline-box;display:inline-block;margin:3px 0 4px;margin-left:4px}input{font-family:inherit}a.gb1,a.gb2,a.gb3,a.gb4{color:#11c !important}body{background:#fff;color:black}a{color:#11c;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#36c}a:visited{color:#551a8b}a.gb1,a.gb4{text-decoration:underline}a.gb3:hover{text-decoration:none}#ghead a.gb2:hover{color:#fff !important}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px}.lsbb{background:#eee;border:solid 1px;border-color:#ccc #999 #999 #ccc;height:30px}.lsbb{display:block}.ftl,#fll a{display:inline-block;margin:0 12px}.lsb{background:url(/images/nav_logo229.png) 0 -261px repeat-x;border:none;color:#000;cursor:pointer;height:30px;margin:0;outline:0;font:15px arial,sans-serif;vertical-align:top}.lsb:active{background:#ccc}.lst:focus{outline:none}</style><script></script><link href="/images/branding/product/ico/googleg_lodp.ico" rel="shortcut icon"></head><body bgcolor="#fff"><script>(function(){var src='/images/nav_logo229.png';var iesg=false;document.body.onload = function(){window.n && window.n();if (document.images){new Image().src=src;}
3
+ if (!iesg){document.f&&document.f.q.focus();document.gbqf&&document.gbqf.q.focus();}
4
+ }
5
+ })();</script><div id="mngb"> <div id=gbar><nobr><b class=gb1>����</b> <a class=gb1 href="https://www.google.co.jp/imghp?hl=ja&tab=wi">�摜</a> <a class=gb1 href="https://maps.google.co.jp/maps?hl=ja&tab=wl">�}�b�v</a> <a class=gb1 href="https://play.google.com/?hl=ja&tab=w8">Play</a> <a class=gb1 href="https://www.youtube.com/?gl=JP&tab=w1">YouTube</a> <a class=gb1 href="https://news.google.co.jp/nwshp?hl=ja&tab=wn">�j���[�X</a> <a class=gb1 href="https://mail.google.com/mail/?tab=wm">Gmail</a> <a class=gb1 href="https://drive.google.com/?tab=wo">�h���C�u</a> <a class=gb1 style="text-decoration:none" href="https://www.google.co.jp/intl/ja/options/"><u>�����ƌ���</u> &raquo;</a></nobr></div><div id=guser width=100%><nobr><span id=gbn class=gbi></span><span id=gbf class=gbf></span><span id=gbe></span><a href="http://www.google.co.jp/history/optout?hl=ja" class=gb4>�E�F�u����</a> | <a href="/preferences?hl=ja" class=gb4>�ݒ�</a> | <a target=_top id=gb_70 href="https://accounts.google.com/ServiceLogin?hl=ja&passive=true&continue=https://www.google.co.jp/" class=gb4>���O�C��</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div> </div><center><br clear="all" id="lgpd"><div id="lga"><div style="padding:28px 0 3px"><div style="height:110px;width:276px;background:url(/images/branding/googlelogo/1x/googlelogo_white_background_color_272x92dp.png) no-repeat" title="Google" align="left" id="hplogo" onload="window.lol&&lol()"><div style="color:#777;font-size:16px;font-weight:bold;position:relative;top:70px;left:218px" nowrap="">���{</div></div></div><br></div><form action="/search" name="f"><table cellpadding="0" cellspacing="0"><tr valign="top"><td width="25%">&nbsp;</td><td align="center" nowrap=""><input name="ie" value="Shift_JIS" type="hidden"><input value="ja" name="hl" type="hidden"><input name="source" type="hidden" value="hp"><input name="biw" type="hidden"><input name="bih" type="hidden"><div class="ds" style="height:32px;margin:4px 0"><input style="color:#000;margin:0;padding:5px 8px 0 6px;vertical-align:top" autocomplete="off" class="lst" value="" title="Google ����" maxlength="2048" name="q" size="57"></div><br style="line-height:0"><span class="ds"><span class="lsbb"><input class="lsb" value="Google ����" name="btnG" type="submit"></span></span><span class="ds"><span class="lsbb"><input class="lsb" value="I'm Feeling Lucky" name="btnI" onclick="if(this.form.q.value)this.checked=1; else top.location='/doodles/'" type="submit"></span></span></td><td class="fl sblc" align="left" nowrap="" width="25%"><a href="/advanced_search?hl=ja&amp;authuser=0">�����I�v�V����</a><a href="/language_tools?hl=ja&amp;authuser=0">����c�[��</a></td></tr></table><input id="gbv" name="gbv" type="hidden" value="1"></form><div id="gac_scont"></div><div style="font-size:83%;min-height:3.5em"><br></div><span id="footer"><div style="font-size:10pt"><div style="margin:19px auto;text-align:center" id="fll"><a href="/intl/ja/ads/">�L���f��</a><a href="http://www.google.co.jp/intl/ja/services/">�r�W�l�X �\�����[�V����</a><a href="https://plus.google.com/115899767381375908215" rel="publisher">+Google</a><a href="/intl/ja/about.html">Google �ɂ‚���</a><a href="https://www.google.co.jp/setprefdomain?prefdom=US&amp;sig=__NSwOcr0nRFmauaxJWrHJmztdkTc%3D" id="fehl">Google.com</a></div></div><p style="color:#767676;font-size:8pt">&copy; 2017 - <a href="/intl/ja/policies/privacy/">�v���C�o�V�[</a> - <a href="/intl/ja/policies/terms/">�K��</a></p></span></center><script>(function(){window.google.cdo={height:0,width:0};(function(){var a=window.innerWidth,b=window.innerHeight;if(!a||!b)var c=window.document,d="CSS1Compat"==c.compatMode?c.documentElement:c.body,a=d.clientWidth,b=d.clientHeight;a&&b&&(a!=google.cdo.width||b!=google.cdo.height)&&google.log("","","/client_204?&atyp=i&biw="+a+"&bih="+b+"&ei="+google.kEI);}).call(this);})();</script><div id="xjsd"></div><div id="xjsi"><script>(function(){function c(b){window.setTimeout(function(){var a=document.createElement("script");a.src=b;document.getElementById("xjsd").appendChild(a)},0)}google.dljp=function(b,a){google.xjsu=b;c(a)};google.dlj=c;}).call(this);(function(){window.google.xjsrm=[];})();if(google.y)google.y.first=[];if(!google.xjs){window._=window._||{};window._._DumpException=function(e){throw e};if(google.timers&&google.timers.load.t){google.timers.load.t.xjsls=new Date().getTime();}google.dljp('/xjs/_/js/k\x3dxjs.hp.en_US.usfcb5N0rIw.O/m\x3dsb_he,d/rt\x3dj/d\x3d1/t\x3dzcms/rs\x3dACT90oH_6o1ZdJ1OdBerX9LppN-xEd11Eg','/xjs/_/js/k\x3dxjs.hp.en_US.usfcb5N0rIw.O/m\x3dsb_he,d/rt\x3dj/d\x3d1/t\x3dzcms/rs\x3dACT90oH_6o1ZdJ1OdBerX9LppN-xEd11Eg');google.xjs=1;}google.pmc={"sb_he":{"agen":true,"cgen":true,"client":"heirloom-hp","dh":true,"dhqt":true,"ds":"","fl":true,"host":"google.co.jp","isbh":28,"jam":0,"jsonp":true,"msgs":{"cibl":"�������N���A","dym":"����������:","lcky":"I\u0026#39;m Feeling Lucky","lml":"�ڍ�","oskt":"���̓c�[��","psrc":"���̌����L�[���[�h��\u003Ca href=\"/history\"\u003E�E�F�u����\u003C/a\u003E����폜����܂���","psrl":"�폜","sbit":"�摜�Ō���","srch":"Google ����"},"nds":true,"ovr":{},"pq":"","refpd":true,"refspre":true,"rfs":[],"scd":10,"sce":5,"stok":"WXDdTX_0YGr0J9JRNcHRvk23BlI"},"d":{}};google.y.first.push(function(){if(google.med){google.med('init');google.initHistory();google.med('history');}});if(google.j&&google.j.en&&google.j.xi){window.setTimeout(google.j.xi,0);}
6
+ </script></div></body></html>
@@ -0,0 +1,6 @@
1
+ <!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="世界中のあらゆる情報を検索するためのツールを提供しています。さまざまな検索機能を活用して、お探しの情報を見つけてください。" name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script>(function(){window.google={kEI:'716VWJL3JYq18QWo_qzoAg',kEXPI:'750722,1351903,1352241,1352381,3700253,3700347,4028875,4029815,4032677,4038012,4043492,4045839,4048347,4062666,4065787,4068816,4069773,4069838,4069840,4070138,4072773,4073405,4073726,4073959,4076096,4076931,4076999,4077777,4078438,4079081,4079105,4079894,4081038,4081485,4082194,4082201,4082298,4082619,4083044,4083476,4084343,4084673,4085336,4085412,4085683,4086011,4089003,4089144,4089183,4089427,4089538,4089913,4090414,4090547,4090549,4090598,4090657,4090806,4090893,4091966,4092028,4092182,4092218,4092474,4092478,4092598,4092864,4092867,4092875,4092897,4092934,4093073,4093948,4094169,4094250,4094769,4094987,4094997,4095554,4095771,4095907,4095998,8300096,8300272,8507380,8507419,8507861,8507940,8508624,8510023,10200083,13500022,13500024',authuser:0,kscs:'c9c918f0_24'};google.kHL='ja';})();(function(){google.lc=[];google.li=0;google.getEI=function(a){for(var b;a&&(!a.getAttribute||!(b=a.getAttribute("eid")));)a=a.parentNode;return b||google.kEI};google.getLEI=function(a){for(var b=null;a&&(!a.getAttribute||!(b=a.getAttribute("leid")));)a=a.parentNode;return b};google.https=function(){return"https:"==window.location.protocol};google.ml=function(){return null};google.wl=function(a,b){try{google.ml(Error(a),!1,b)}catch(c){}};google.time=function(){return(new Date).getTime()};google.log=function(a,b,c,d,g){a=google.logUrl(a,b,c,d,g);if(""!=a){b=new Image;var e=google.lc,f=google.li;e[f]=b;b.onerror=b.onload=b.onabort=function(){delete e[f]};window.google&&window.google.vel&&window.google.vel.lu&&window.google.vel.lu(a);b.src=a;google.li=f+1}};google.logUrl=function(a,b,c,d,g){var e="",f=google.ls||"";c||-1!=b.search("&ei=")||(e="&ei="+google.getEI(d),-1==b.search("&lei=")&&(d=google.getLEI(d))&&(e+="&lei="+d));a=c||"/"+(g||"gen_204")+"?atyp=i&ct="+a+"&cad="+b+e+f+"&zx="+google.time();/^http:/i.test(a)&&google.https()&&(google.ml(Error("a"),!1,{src:a,glmm:1}),a="");return a};google.y={};google.x=function(a,b){google.y[a.id]=[a,b];return!1};google.lq=[];google.load=function(a,b,c){google.lq.push([[a],b,c])};google.loadAll=function(a,b){google.lq.push([a,b])};}).call(this);var a=window.location,b=a.href.indexOf("#");if(0<=b){var c=a.href.substring(b+1);/(^|&)q=/.test(c)&&-1==c.indexOf("#")&&a.replace("/search?"+c.replace(/(^|&)fp=[^&]*/g,"")+"&cad=h")};</script><style>#gbar,#guser{font-size:13px;padding-top:1px !important;}#gbar{height:22px}#guser{padding-bottom:7px !important;text-align:right}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}@media all{.gb1{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb4{text-decoration:underline !important}a.gb1,a.gb4{color:#00c !important}.gbi .gb4{color:#dd8e27 !important}.gbf .gb4{color:#900 !important}
2
+ </style><style>body,td,a,p,.h{font-family:arial,sans-serif}body{margin:0;overflow-y:scroll}#gog{padding:3px 8px 0}td{line-height:.8em}.gac_m td{line-height:17px}form{margin-bottom:20px}.h{color:#36c}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{height:25px;width:496px}.gsfi,.lst{font:18px arial,sans-serif}.gsfs{font:17px arial,sans-serif}.ds{display:inline-box;display:inline-block;margin:3px 0 4px;margin-left:4px}input{font-family:inherit}a.gb1,a.gb2,a.gb3,a.gb4{color:#11c !important}body{background:#fff;color:black}a{color:#11c;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#36c}a:visited{color:#551a8b}a.gb1,a.gb4{text-decoration:underline}a.gb3:hover{text-decoration:none}#ghead a.gb2:hover{color:#fff !important}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px}.lsbb{background:#eee;border:solid 1px;border-color:#ccc #999 #999 #ccc;height:30px}.lsbb{display:block}.ftl,#fll a{display:inline-block;margin:0 12px}.lsb{background:url(/images/nav_logo229.png) 0 -261px repeat-x;border:none;color:#000;cursor:pointer;height:30px;margin:0;outline:0;font:15px arial,sans-serif;vertical-align:top}.lsb:active{background:#ccc}.lst:focus{outline:none}</style><script></script><link href="/images/branding/product/ico/googleg_lodp.ico" rel="shortcut icon"></head><body bgcolor="#fff"><script>(function(){var src='/images/nav_logo229.png';var iesg=false;document.body.onload = function(){window.n && window.n();if (document.images){new Image().src=src;}
3
+ if (!iesg){document.f&&document.f.q.focus();document.gbqf&&document.gbqf.q.focus();}
4
+ }
5
+ })();</script><div id="mngb"> <div id=gbar><nobr><b class=gb1>検索</b> <a class=gb1 href="https://www.google.co.jp/imghp?hl=ja&tab=wi">画像</a> <a class=gb1 href="https://maps.google.co.jp/maps?hl=ja&tab=wl">マップ</a> <a class=gb1 href="https://play.google.com/?hl=ja&tab=w8">Play</a> <a class=gb1 href="https://www.youtube.com/?gl=JP&tab=w1">YouTube</a> <a class=gb1 href="https://news.google.co.jp/nwshp?hl=ja&tab=wn">ニュース</a> <a class=gb1 href="https://mail.google.com/mail/?tab=wm">Gmail</a> <a class=gb1 href="https://drive.google.com/?tab=wo">ドライブ</a> <a class=gb1 style="text-decoration:none" href="https://www.google.co.jp/intl/ja/options/"><u>もっと見る</u> &raquo;</a></nobr></div><div id=guser width=100%><nobr><span id=gbn class=gbi></span><span id=gbf class=gbf></span><span id=gbe></span><a href="http://www.google.co.jp/history/optout?hl=ja" class=gb4>ウェブ履歴</a> | <a href="/preferences?hl=ja" class=gb4>設定</a> | <a target=_top id=gb_70 href="https://accounts.google.com/ServiceLogin?hl=ja&passive=true&continue=https://www.google.co.jp/" class=gb4>ログイン</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div> </div><center><br clear="all" id="lgpd"><div id="lga"><div style="padding:28px 0 3px"><div style="height:110px;width:276px;background:url(/images/branding/googlelogo/1x/googlelogo_white_background_color_272x92dp.png) no-repeat" title="Google" align="left" id="hplogo" onload="window.lol&&lol()"><div style="color:#777;font-size:16px;font-weight:bold;position:relative;top:70px;left:218px" nowrap="">日本</div></div></div><br></div><form action="/search" name="f"><table cellpadding="0" cellspacing="0"><tr valign="top"><td width="25%">&nbsp;</td><td align="center" nowrap=""><input name="ie" value="Shift_JIS" type="hidden"><input value="ja" name="hl" type="hidden"><input name="source" type="hidden" value="hp"><input name="biw" type="hidden"><input name="bih" type="hidden"><div class="ds" style="height:32px;margin:4px 0"><input style="color:#000;margin:0;padding:5px 8px 0 6px;vertical-align:top" autocomplete="off" class="lst" value="" title="Google 検索" maxlength="2048" name="q" size="57"></div><br style="line-height:0"><span class="ds"><span class="lsbb"><input class="lsb" value="Google 検索" name="btnG" type="submit"></span></span><span class="ds"><span class="lsbb"><input class="lsb" value="I'm Feeling Lucky" name="btnI" onclick="if(this.form.q.value)this.checked=1; else top.location='/doodles/'" type="submit"></span></span></td><td class="fl sblc" align="left" nowrap="" width="25%"><a href="/advanced_search?hl=ja&amp;authuser=0">検索オプション</a><a href="/language_tools?hl=ja&amp;authuser=0">言語ツール</a></td></tr></table><input id="gbv" name="gbv" type="hidden" value="1"></form><div id="gac_scont"></div><div style="font-size:83%;min-height:3.5em"><br></div><span id="footer"><div style="font-size:10pt"><div style="margin:19px auto;text-align:center" id="fll"><a href="/intl/ja/ads/">広告掲載</a><a href="http://www.google.co.jp/intl/ja/services/">ビジネス ソリューション</a><a href="https://plus.google.com/115899767381375908215" rel="publisher">+Google</a><a href="/intl/ja/about.html">Google について</a><a href="https://www.google.co.jp/setprefdomain?prefdom=US&amp;sig=__NSwOcr0nRFmauaxJWrHJmztdkTc%3D" id="fehl">Google.com</a></div></div><p style="color:#767676;font-size:8pt">&copy; 2017 - <a href="/intl/ja/policies/privacy/">プライバシー</a> - <a href="/intl/ja/policies/terms/">規約</a></p></span></center><script>(function(){window.google.cdo={height:0,width:0};(function(){var a=window.innerWidth,b=window.innerHeight;if(!a||!b)var c=window.document,d="CSS1Compat"==c.compatMode?c.documentElement:c.body,a=d.clientWidth,b=d.clientHeight;a&&b&&(a!=google.cdo.width||b!=google.cdo.height)&&google.log("","","/client_204?&atyp=i&biw="+a+"&bih="+b+"&ei="+google.kEI);}).call(this);})();</script><div id="xjsd"></div><div id="xjsi"><script>(function(){function c(b){window.setTimeout(function(){var a=document.createElement("script");a.src=b;document.getElementById("xjsd").appendChild(a)},0)}google.dljp=function(b,a){google.xjsu=b;c(a)};google.dlj=c;}).call(this);(function(){window.google.xjsrm=[];})();if(google.y)google.y.first=[];if(!google.xjs){window._=window._||{};window._._DumpException=function(e){throw e};if(google.timers&&google.timers.load.t){google.timers.load.t.xjsls=new Date().getTime();}google.dljp('/xjs/_/js/k\x3dxjs.hp.en_US.usfcb5N0rIw.O/m\x3dsb_he,d/rt\x3dj/d\x3d1/t\x3dzcms/rs\x3dACT90oH_6o1ZdJ1OdBerX9LppN-xEd11Eg','/xjs/_/js/k\x3dxjs.hp.en_US.usfcb5N0rIw.O/m\x3dsb_he,d/rt\x3dj/d\x3d1/t\x3dzcms/rs\x3dACT90oH_6o1ZdJ1OdBerX9LppN-xEd11Eg');google.xjs=1;}google.pmc={"sb_he":{"agen":true,"cgen":true,"client":"heirloom-hp","dh":true,"dhqt":true,"ds":"","fl":true,"host":"google.co.jp","isbh":28,"jam":0,"jsonp":true,"msgs":{"cibl":"検索をクリア","dym":"もしかして:","lcky":"I\u0026#39;m Feeling Lucky","lml":"詳細","oskt":"入力ツール","psrc":"この検索キーワードは\u003Ca href=\"/history\"\u003Eウェブ履歴\u003C/a\u003Eから削除されました","psrl":"削除","sbit":"画像で検索","srch":"Google 検索"},"nds":true,"ovr":{},"pq":"","refpd":true,"refspre":true,"rfs":[],"scd":10,"sce":5,"stok":"WXDdTX_0YGr0J9JRNcHRvk23BlI"},"d":{}};google.y.first.push(function(){if(google.med){google.med('init');google.initHistory();google.med('history');}});if(google.j&&google.j.en&&google.j.xi){window.setTimeout(google.j.xi,0);}
6
+ </script></div></body></html>
data/spec/grader_spec.rb CHANGED
@@ -15,7 +15,7 @@ describe LinkThumbnailer::Grader do
15
15
  let(:action) { instance.call }
16
16
 
17
17
  before do
18
- instance.stub(:graders).and_return(graders)
18
+ allow(instance).to receive(:graders).and_return(graders)
19
19
  end
20
20
 
21
21
  it { expect(action).to eq((0.5 * 0.5) ** weight) }
@@ -12,7 +12,7 @@ describe LinkThumbnailer::Graders::HtmlAttribute do
12
12
  context 'when current node does not match attribute' do
13
13
 
14
14
  before do
15
- instance.stub(:attribute?).and_return(false)
15
+ allow(instance).to receive(:attribute?).and_return(false)
16
16
  end
17
17
 
18
18
  it { expect(action).to eq(1.0) }
@@ -22,9 +22,9 @@ describe LinkThumbnailer::Graders::HtmlAttribute do
22
22
  context 'when current node has a negative attribute' do
23
23
 
24
24
  before do
25
- instance.stub(:attribute?).and_return(true)
26
- instance.stub(:negative?).and_return(true)
27
- instance.stub(:positive?).and_return(false)
25
+ allow(instance).to receive(:attribute?).and_return(true)
26
+ allow(instance).to receive(:negative?).and_return(true)
27
+ allow(instance).to receive(:positive?).and_return(false)
28
28
  end
29
29
 
30
30
  it { expect(action).to eq(0.0) }
@@ -34,9 +34,9 @@ describe LinkThumbnailer::Graders::HtmlAttribute do
34
34
  context 'when current node has a positive attribute' do
35
35
 
36
36
  before do
37
- instance.stub(:attribute?).and_return(true)
38
- instance.stub(:negative?).and_return(false)
39
- instance.stub(:positive?).and_return(true)
37
+ allow(instance).to receive(:attribute?).and_return(true)
38
+ allow(instance).to receive(:negative?).and_return(false)
39
+ allow(instance).to receive(:positive?).and_return(true)
40
40
  end
41
41
 
42
42
  it { expect(action).to eq(1.0) }
@@ -7,7 +7,7 @@ describe LinkThumbnailer::Graders::Length do
7
7
  let(:instance) { described_class.new(description) }
8
8
 
9
9
  before do
10
- instance.stub(:config).and_return(config)
10
+ allow(instance).to receive(:config).and_return(config)
11
11
  end
12
12
 
13
13
  describe '#call' do
@@ -17,7 +17,7 @@ describe LinkThumbnailer::Graders::Length do
17
17
  context 'when text is too short' do
18
18
 
19
19
  before do
20
- instance.stub(:too_short?).and_return(true)
20
+ allow(instance).to receive(:too_short?).and_return(true)
21
21
  end
22
22
 
23
23
  it { expect(action).to eq(0.0) }
@@ -27,8 +27,8 @@ describe LinkThumbnailer::Graders::Length do
27
27
  context 'when text is not too short' do
28
28
 
29
29
  before do
30
- instance.stub(:too_short?).and_return(false)
31
- instance.stub(:text).and_return(text)
30
+ allow(instance).to receive(:too_short?).and_return(false)
31
+ allow(instance).to receive(:text).and_return(text)
32
32
  end
33
33
 
34
34
  context 'when text length is 120' do
@@ -62,10 +62,12 @@ describe LinkThumbnailer::Graders::Length do
62
62
  describe '#too_short?' do
63
63
 
64
64
  let(:action) { instance.send(:too_short?) }
65
+ let(:config) { double }
65
66
 
66
67
  before do
67
- instance.stub_chain(:config, :description_min_length).and_return(10)
68
- instance.stub(:text).and_return(text)
68
+ allow(instance).to receive(:config).and_return(config)
69
+ allow(config).to receive(:description_min_length).and_return(10)
70
+ allow(instance).to receive(:text).and_return(text)
69
71
  end
70
72
 
71
73
  context 'when true' do
@@ -10,8 +10,8 @@ describe LinkThumbnailer::Graders::LinkDensity do
10
10
  let(:action) { instance.call }
11
11
 
12
12
  before do
13
- instance.stub(:text).and_return(text)
14
- instance.stub(:links).and_return(links)
13
+ allow(instance).to receive(:text).and_return(text)
14
+ allow(instance).to receive(:links).and_return(links)
15
15
  end
16
16
 
17
17
  context 'when text length is 0' do
@@ -12,8 +12,8 @@ describe LinkThumbnailer::Graders::Position do
12
12
  context 'when position is 0' do
13
13
 
14
14
  before do
15
- description.stub(:position).and_return(0)
16
- description.stub(:candidates_number).and_return(1)
15
+ allow(description).to receive(:position).and_return(0)
16
+ allow(description).to receive(:candidates_number).and_return(1)
17
17
  end
18
18
 
19
19
  it { expect(action).to eq(1.0) }
@@ -23,8 +23,8 @@ describe LinkThumbnailer::Graders::Position do
23
23
  context 'when position is 1 over 1 candidates' do
24
24
 
25
25
  before do
26
- description.stub(:position).and_return(1)
27
- description.stub(:candidates_number).and_return(1)
26
+ allow(description).to receive(:position).and_return(1)
27
+ allow(description).to receive(:candidates_number).and_return(1)
28
28
  end
29
29
 
30
30
  it { expect(action).to eq(0.0) }
@@ -34,8 +34,8 @@ describe LinkThumbnailer::Graders::Position do
34
34
  context 'when position is 1 over more than 1 candidates' do
35
35
 
36
36
  before do
37
- description.stub(:position).and_return(1)
38
- description.stub(:candidates_number).and_return(2)
37
+ allow(description).to receive(:position).and_return(1)
38
+ allow(description).to receive(:candidates_number).and_return(2)
39
39
  end
40
40
 
41
41
  it { expect(action).to eq(0.5) }
@@ -11,7 +11,7 @@ describe LinkThumbnailer::ImageValidator do
11
11
  let(:action) { instance.call }
12
12
 
13
13
  before do
14
- instance.stub(:blacklist_urls).and_return(blacklist_urls)
14
+ allow(instance).to receive(:blacklist_urls).and_return(blacklist_urls)
15
15
  end
16
16
 
17
17
  context 'when image url is blacklisted' do
@@ -8,7 +8,7 @@ describe LinkThumbnailer::Models::Description do
8
8
  let(:instance) { described_class.new(node, text) }
9
9
 
10
10
  before do
11
- ::LinkThumbnailer::Grader.should_receive(:new).at_least(1).and_return(grader)
11
+ expect(LinkThumbnailer::Grader).to receive(:new).at_least(1).times.and_return(grader)
12
12
  end
13
13
 
14
14
  describe '#to_s' do
@@ -23,7 +23,7 @@ describe LinkThumbnailer::Models::Image do
23
23
  let(:action) { instance <=> other }
24
24
 
25
25
  before do
26
- instance.stub(:size).and_return([20, 20])
26
+ allow(instance).to receive(:size).and_return([20, 20])
27
27
  end
28
28
 
29
29
  context 'when other has a smaller image' do
@@ -58,7 +58,7 @@ describe LinkThumbnailer::Models::Image do
58
58
  let(:action) { instance.valid? }
59
59
 
60
60
  before do
61
- instance.stub(:validator).and_return(validator)
61
+ allow(instance).to receive(:validator).and_return(validator)
62
62
  end
63
63
 
64
64
  it 'calls validator public method' do
@@ -82,8 +82,8 @@ describe LinkThumbnailer::Models::Image do
82
82
  }
83
83
 
84
84
  before do
85
- instance.stub(:size).and_return(size)
86
- instance.stub(:type).and_return(type)
85
+ allow(instance).to receive(:size).and_return(size)
86
+ allow(instance).to receive(:type).and_return(type)
87
87
  end
88
88
 
89
89
  it { expect(action).to eq(result) }
@@ -33,11 +33,11 @@ describe LinkThumbnailer::Models::Video do
33
33
  }
34
34
 
35
35
  before do
36
- instance.stub(:id).and_return(id)
37
- instance.stub(:size).and_return(size)
38
- instance.stub(:duration).and_return(duration)
39
- instance.stub(:provider).and_return(provider)
40
- instance.stub(:embed_code).and_return(embed_code)
36
+ allow(instance).to receive(:id).and_return(id)
37
+ allow(instance).to receive(:size).and_return(size)
38
+ allow(instance).to receive(:duration).and_return(duration)
39
+ allow(instance).to receive(:provider).and_return(provider)
40
+ allow(instance).to receive(:embed_code).and_return(embed_code)
41
41
  end
42
42
 
43
43
  it { expect(action).to eq(result) }
@@ -12,7 +12,7 @@ describe LinkThumbnailer::Models::Website do
12
12
  let(:action) { instance.image = image }
13
13
 
14
14
  before do
15
- image.stub(:valid?).and_return(true)
15
+ allow(image).to receive(:valid?).and_return(true)
16
16
  end
17
17
 
18
18
  it { expect { action }.to change { instance.images.size }.by(1) }
@@ -27,7 +27,7 @@ describe LinkThumbnailer::Models::Website do
27
27
  context 'when image is valid' do
28
28
 
29
29
  before do
30
- image.stub(:valid?).and_return(true)
30
+ allow(image).to receive(:valid?).and_return(true)
31
31
  end
32
32
 
33
33
  it { expect { action }.to change { instance.images.size }.by(1) }
@@ -37,7 +37,7 @@ describe LinkThumbnailer::Models::Website do
37
37
  context 'when image is not valid' do
38
38
 
39
39
  before do
40
- image.stub(:valid?).and_return(false)
40
+ allow(image).to receive(:valid?).and_return(false)
41
41
  end
42
42
 
43
43
  it { expect { action }.to_not change { instance.images.size } }
@@ -7,7 +7,7 @@ describe LinkThumbnailer::Processor do
7
7
  let(:url) { 'http://foo.com' }
8
8
 
9
9
  before do
10
- LinkThumbnailer.stub(:page).and_return(page)
10
+ allow(LinkThumbnailer).to receive(:page).and_return(page)
11
11
  end
12
12
 
13
13
  describe '#call' do
@@ -81,7 +81,7 @@ describe LinkThumbnailer::Processor do
81
81
  context 'when valid' do
82
82
 
83
83
  before do
84
- instance.stub(:valid_url_format?).and_return(true)
84
+ allow(instance).to receive(:valid_url_format?).and_return(true)
85
85
  end
86
86
 
87
87
  it 'yields' do
@@ -94,7 +94,7 @@ describe LinkThumbnailer::Processor do
94
94
  context 'when not valid' do
95
95
 
96
96
  before do
97
- instance.stub(:valid_url_format?).and_return(false)
97
+ allow(instance).to receive(:valid_url_format?).and_return(false)
98
98
  end
99
99
 
100
100
  it { expect { instance.send(:with_valid_url) }.to raise_error(LinkThumbnailer::BadUriFormat) }
@@ -110,7 +110,7 @@ describe LinkThumbnailer::Processor do
110
110
  let(:action) { instance.send(:set_http_headers) }
111
111
 
112
112
  before do
113
- instance.stub(:user_agent).and_return(user_agent)
113
+ allow(instance).to receive(:user_agent).and_return(user_agent)
114
114
  action
115
115
  end
116
116
 
@@ -128,7 +128,7 @@ describe LinkThumbnailer::Processor do
128
128
  context 'when verify_ssl is true' do
129
129
 
130
130
  before do
131
- instance.stub(:ssl_required?).and_return(true)
131
+ allow(instance).to receive(:ssl_required?).and_return(true)
132
132
  action
133
133
  end
134
134
 
@@ -139,7 +139,7 @@ describe LinkThumbnailer::Processor do
139
139
  context 'when verify_ssl is not true' do
140
140
 
141
141
  before do
142
- instance.stub(:ssl_required?).and_return(false)
142
+ allow(instance).to receive(:ssl_required?).and_return(false)
143
143
  action
144
144
  end
145
145
 
@@ -154,7 +154,7 @@ describe LinkThumbnailer::Processor do
154
154
  let(:http_open_timeout) { 1 }
155
155
 
156
156
  before do
157
- instance.stub(:http_open_timeout).and_return(http_open_timeout)
157
+ allow(instance).to receive(:http_open_timeout).and_return(http_open_timeout)
158
158
  action
159
159
  end
160
160
 
@@ -167,7 +167,7 @@ describe LinkThumbnailer::Processor do
167
167
  let(:http_read_timeout) { 1 }
168
168
 
169
169
  before do
170
- instance.stub(:http_read_timeout).and_return(http_read_timeout)
170
+ allow(instance).to receive(:http_read_timeout).and_return(http_read_timeout)
171
171
  action
172
172
  end
173
173
 
@@ -179,9 +179,11 @@ describe LinkThumbnailer::Processor do
179
179
  describe '#perform_request' do
180
180
 
181
181
  let(:action) { instance.send(:perform_request) }
182
+ let(:http) { double }
182
183
 
183
184
  before do
184
- instance.stub_chain(:http, :request).and_return(response)
185
+ allow(instance).to receive(:http).and_return(http)
186
+ allow(http).to receive(:request).and_return(response)
185
187
  end
186
188
 
187
189
  context 'when http success' do
@@ -191,13 +193,40 @@ describe LinkThumbnailer::Processor do
191
193
  let(:response) { ::Net::HTTPSuccess.new('', code, body) }
192
194
 
193
195
  before do
194
- response.stub(:body).and_return(body)
196
+ allow(response).to receive(:body).and_return(body)
195
197
  end
196
198
 
197
199
  it { expect(action).to eq(body) }
198
200
 
199
201
  end
200
202
 
203
+ context 'when access non-utf8-encoding website' do
204
+ let(:code) { 200 }
205
+ let(:body_shift_jis) do
206
+ File.read(File.expand_path('fixtures/google_shift_jis.html', File.dirname(__FILE__)))
207
+ end
208
+ let(:body_utf8) do
209
+ File.read(File.expand_path('fixtures/google_utf8.html', File.dirname(__FILE__)))
210
+ end
211
+ let(:response) do
212
+ r = ::Net::HTTPSuccess.new('', code, body_shift_jis)
213
+ r['Content-Type'] = 'text/html'
214
+ r.body = body_shift_jis
215
+ r.instance_variable_set(:@read, true)
216
+ r
217
+ end
218
+
219
+ context 'when http success with valid charset provided in Content-Type' do
220
+ before { response['Content-Type'] = 'text/html; charset=Shift_JIS' }
221
+ it { expect(action).to eq body_utf8 }
222
+ end
223
+
224
+ context 'when http success with invalid charset provided in Content-Type' do
225
+ before { response['Content-Type'] = 'text/html; charset=Shift-JIS' }
226
+ it { expect(action).to eq body_shift_jis }
227
+ end
228
+ end
229
+
201
230
  context 'when http redirection' do
202
231
 
203
232
  let(:code) { 200 }
@@ -206,8 +235,8 @@ describe LinkThumbnailer::Processor do
206
235
  let(:new_url) { 'http://foo.com/bar' }
207
236
 
208
237
  before do
209
- instance.stub(:redirect_count).and_return(0)
210
- instance.stub(:resolve_relative_url).and_return(new_url)
238
+ allow(instance).to receive(:redirect_count).and_return(0)
239
+ allow(instance).to receive(:resolve_relative_url).and_return(new_url)
211
240
  end
212
241
 
213
242
  it 'calls call method' do
@@ -229,7 +258,7 @@ describe LinkThumbnailer::Processor do
229
258
  let(:action) { instance.send(:build_absolute_url_for, relative_url).to_s }
230
259
 
231
260
  before do
232
- instance.stub(:url).and_return(url)
261
+ allow(instance).to receive(:url).and_return(url)
233
262
  end
234
263
 
235
264
  it { expect(action).to eq("#{scheme}://#{host}#{relative_url}") }
@@ -308,7 +337,7 @@ describe LinkThumbnailer::Processor do
308
337
  context 'when bad format' do
309
338
 
310
339
  before do
311
- instance.stub(:url).and_return("http://foo.com")
340
+ allow(instance).to receive(:url).and_return("http://foo.com")
312
341
  end
313
342
 
314
343
  it { expect(action).to be_falsey }
@@ -318,7 +347,7 @@ describe LinkThumbnailer::Processor do
318
347
  context 'when valid format' do
319
348
 
320
349
  before do
321
- instance.stub(:url).and_return(URI("http://foo.com"))
350
+ allow(instance).to receive(:url).and_return(URI("http://foo.com"))
322
351
  end
323
352
 
324
353
  it { expect(action).to be_truthy }
@@ -334,8 +363,8 @@ describe LinkThumbnailer::Processor do
334
363
  context 'when redirect count is greater than redirect limit' do
335
364
 
336
365
  before do
337
- instance.stub(:redirect_count).and_return(5)
338
- instance.stub(:redirect_limit).and_return(4)
366
+ allow(instance).to receive(:redirect_count).and_return(5)
367
+ allow(instance).to receive(:redirect_limit).and_return(4)
339
368
  end
340
369
 
341
370
  it { expect(action).to be_truthy }
@@ -345,8 +374,8 @@ describe LinkThumbnailer::Processor do
345
374
  context 'when redirect count is less than redirect limit' do
346
375
 
347
376
  before do
348
- instance.stub(:redirect_count).and_return(4)
349
- instance.stub(:redirect_limit).and_return(5)
377
+ allow(instance).to receive(:redirect_count).and_return(4)
378
+ allow(instance).to receive(:redirect_limit).and_return(5)
350
379
  end
351
380
 
352
381
  it { expect(action).to be_falsey }
@@ -356,8 +385,8 @@ describe LinkThumbnailer::Processor do
356
385
  context 'when redirect count is equal to redirect limit' do
357
386
 
358
387
  before do
359
- instance.stub(:redirect_count).and_return(5)
360
- instance.stub(:redirect_limit).and_return(5)
388
+ allow(instance).to receive(:redirect_count).and_return(5)
389
+ allow(instance).to receive(:redirect_limit).and_return(5)
361
390
  end
362
391
 
363
392
  it { expect(action).to be_falsey }
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe LinkThumbnailer::Response do
4
+ let(:url) { 'https://www.google.co.jp' }
5
+ let(:page) { ::LinkThumbnailer::Page.new(url, {}) }
6
+
7
+ let(:response) do
8
+ r = ::Net::HTTPSuccess.new('', 200, body_shift_jis)
9
+ r['Content-Type'] = 'text/html'
10
+ r.body = body_shift_jis
11
+ r.instance_variable_set(:@read, true)
12
+ r
13
+ end
14
+
15
+ let(:instance) { described_class.new(response) }
16
+
17
+ let(:body_shift_jis) do
18
+ File.read(File.expand_path('fixtures/google_shift_jis.html', File.dirname(__FILE__)))
19
+ end
20
+
21
+ let(:body_utf8) do
22
+ File.read(File.expand_path('fixtures/google_utf8.html', File.dirname(__FILE__)))
23
+ end
24
+
25
+ before do
26
+ allow(LinkThumbnailer).to receive(:page).and_return(page)
27
+ end
28
+
29
+ describe '#charset' do
30
+ context 'when charset provided in content-type' do
31
+ before do
32
+ response['Content-Type'] = 'text/html; charset=Shift_JIS'
33
+ end
34
+
35
+ it { expect(instance.charset).to eq 'Shift_JIS' }
36
+ end
37
+
38
+ context 'when no charset available in content-type' do
39
+ it { expect(instance.charset).to eq '' }
40
+ end
41
+ end
42
+
43
+ describe '#body' do
44
+ context 'when provide valid charset' do
45
+ before do
46
+ response['Content-Type'] = 'text/html; charset=Shift_JIS'
47
+ end
48
+
49
+ it { expect(instance.body).to eq body_utf8 }
50
+ end
51
+
52
+ context 'when provide invalid charset' do
53
+ before do
54
+ response['Content-Type'] = 'text/html; charset=Shift-JIS'
55
+ end
56
+
57
+ it { expect(instance.body).to eq body_shift_jis }
58
+ end
59
+ end
60
+ end
data/spec/scraper_spec.rb CHANGED
@@ -9,8 +9,8 @@ describe LinkThumbnailer::Scraper do
9
9
  let(:instance) { described_class.new(source, url) }
10
10
 
11
11
  before do
12
- instance.stub(:document).and_return(document)
13
- instance.stub(:website).and_return(website)
12
+ allow(instance).to receive(:document).and_return(document)
13
+ allow(instance).to receive(:website).and_return(website)
14
14
  end
15
15
 
16
16
  describe '#call' do
@@ -22,10 +22,10 @@ describe LinkThumbnailer::Scraper do
22
22
  let(:attributes) { [:bar] }
23
23
  let(:scrapers) { [prefix_1, prefix_2] }
24
24
  let(:action) { instance.call }
25
+ let(:config) { double(attributes: attributes, scrapers: scrapers) }
25
26
 
26
27
  before do
27
- instance.stub_chain(:config, :attributes).and_return(attributes)
28
- instance.stub_chain(:config, :scrapers).and_return(scrapers)
28
+ allow(instance).to receive(:config).and_return(config)
29
29
  end
30
30
 
31
31
  context 'when first one return a result' do
@@ -13,7 +13,7 @@ describe LinkThumbnailer::Scrapers::Base do
13
13
  let(:action) { instance.call(attr) }
14
14
 
15
15
  before do
16
- instance.stub(:value).and_return(value)
16
+ allow(instance).to receive(:value).and_return(value)
17
17
  end
18
18
 
19
19
  it { expect { action }.to change { website.title }.from(nil).to(value) }
@@ -25,7 +25,7 @@ describe LinkThumbnailer::Scrapers::Base do
25
25
  let(:action) { instance.send(:model_class) }
26
26
 
27
27
  before do
28
- instance.stub(:attribute_name).and_return(attr)
28
+ allow(instance).to receive(:attribute_name).and_return(attr)
29
29
  end
30
30
 
31
31
  context 'when internal class exists' do
@@ -40,7 +40,7 @@ describe LinkThumbnailer::Scrapers::Base do
40
40
 
41
41
  let(:attr) { :foo }
42
42
 
43
- it { expect { action }.to raise_exception }
43
+ it { expect { action }.to raise_error(NameError) }
44
44
 
45
45
  end
46
46
 
@@ -54,7 +54,7 @@ describe LinkThumbnailer::Scrapers::Base do
54
54
  let(:action) { instance.send(:modelize, node, text) }
55
55
 
56
56
  before do
57
- instance.stub(:model_class).and_return(model_class)
57
+ allow(instance).to receive(:model_class).and_return(model_class)
58
58
  end
59
59
 
60
60
  it 'instantiates a new model' do
@@ -12,13 +12,13 @@ describe LinkThumbnailer::Scrapers::Opengraph::Base do
12
12
  let(:action) { instance.applicable? }
13
13
 
14
14
  before do
15
- instance.stub(:meta).and_return(meta)
15
+ allow(instance).to receive(:meta).and_return(meta)
16
16
  end
17
17
 
18
18
  context 'when all node is an opengraph' do
19
19
 
20
20
  before do
21
- instance.stub(:opengraph_node?).and_return(true, true)
21
+ allow(instance).to receive(:opengraph_node?).and_return(true, true)
22
22
  end
23
23
 
24
24
  it { expect(action).to be_truthy }
@@ -28,7 +28,7 @@ describe LinkThumbnailer::Scrapers::Opengraph::Base do
28
28
  context 'when any node is an opengraph' do
29
29
 
30
30
  before do
31
- instance.stub(:opengraph_node?).and_return(true, false)
31
+ allow(instance).to receive(:opengraph_node?).and_return(true, false)
32
32
  end
33
33
 
34
34
  it { expect(action).to be_truthy }
@@ -38,7 +38,7 @@ describe LinkThumbnailer::Scrapers::Opengraph::Base do
38
38
  context 'when no node is an opengraph' do
39
39
 
40
40
  before do
41
- instance.stub(:opengraph_node?).and_return(false, false)
41
+ allow(instance).to receive(:opengraph_node?).and_return(false, false)
42
42
  end
43
43
 
44
44
  it { expect(action).to be_falsey }
@@ -52,7 +52,7 @@ describe LinkThumbnailer::Scrapers::Opengraph::Base do
52
52
  let(:action) { instance.send(:opengraph_node?, node) }
53
53
 
54
54
  before do
55
- node.stub(:attribute).with('name').and_return(attribute_from_name)
55
+ allow(node).to receive(:attribute).with('name').and_return(attribute_from_name)
56
56
  end
57
57
 
58
58
  context 'with attribute from name valid' do
@@ -68,7 +68,7 @@ describe LinkThumbnailer::Scrapers::Opengraph::Base do
68
68
  let(:attribute_from_name) { 'foo' }
69
69
 
70
70
  before do
71
- node.stub(:attribute).with('property').and_return(attribute_from_property)
71
+ allow(node).to receive(:attribute).with('property').and_return(attribute_from_property)
72
72
  end
73
73
 
74
74
  context 'and attribute from property valid' do
data/spec/uri_spec.rb CHANGED
@@ -12,7 +12,7 @@ describe LinkThumbnailer::URI do
12
12
  context 'when bad format' do
13
13
 
14
14
  before do
15
- instance.stub(:attribute).and_return("/invalid/path")
15
+ allow(instance).to receive(:attribute).and_return("/invalid/path")
16
16
  end
17
17
 
18
18
  it { expect(action).to be_falsey }
@@ -22,7 +22,7 @@ describe LinkThumbnailer::URI do
22
22
  context 'when valid format' do
23
23
 
24
24
  before do
25
- instance.stub(:attribute).and_return("http://foo.com")
25
+ allow(instance).to receive(:attribute).and_return("http://foo.com")
26
26
  end
27
27
 
28
28
  it { expect(action).to be_truthy }
@@ -8,7 +8,7 @@ describe LinkThumbnailer::VideoParser do
8
8
  let(:instance) { described_class.new(video) }
9
9
 
10
10
  before do
11
- instance.stub(:parser).and_return(parser)
11
+ allow(instance).to receive(:parser).and_return(parser)
12
12
  end
13
13
 
14
14
  describe '#id' do
@@ -18,7 +18,7 @@ describe LinkThumbnailer::VideoParser do
18
18
  context 'when respond to video_id' do
19
19
 
20
20
  before do
21
- parser.stub(:video_id).and_return(1)
21
+ allow(parser).to receive(:video_id).and_return(1)
22
22
  end
23
23
 
24
24
  it { expect(action).to eq(parser.video_id) }
@@ -28,7 +28,7 @@ describe LinkThumbnailer::VideoParser do
28
28
  context 'when do not respond to video_id' do
29
29
 
30
30
  before do
31
- parser.stub(:video_id).and_raise(NoMethodError)
31
+ allow(parser).to receive(:video_id).and_raise(NoMethodError)
32
32
  end
33
33
 
34
34
  it { expect(action).to be_nil }
@@ -44,8 +44,8 @@ describe LinkThumbnailer::VideoParser do
44
44
  context 'when respond to width and height' do
45
45
 
46
46
  before do
47
- parser.stub(:width).and_return(1)
48
- parser.stub(:height).and_return(1)
47
+ allow(parser).to receive(:width).and_return(1)
48
+ allow(parser).to receive(:height).and_return(1)
49
49
  end
50
50
 
51
51
  it { expect(action).to eq([parser.width, parser.height]) }
@@ -55,8 +55,8 @@ describe LinkThumbnailer::VideoParser do
55
55
  context 'when do not respond to width and height' do
56
56
 
57
57
  before do
58
- parser.stub(:width).and_raise(NoMethodError)
59
- parser.stub(:height).and_raise(NoMethodError)
58
+ allow(parser).to receive(:width).and_raise(NoMethodError)
59
+ allow(parser).to receive(:height).and_raise(NoMethodError)
60
60
  end
61
61
 
62
62
  it { expect(action).to be_empty }
@@ -72,7 +72,7 @@ describe LinkThumbnailer::VideoParser do
72
72
  context 'when respond to duration' do
73
73
 
74
74
  before do
75
- parser.stub(:duration).and_return(1)
75
+ allow(parser).to receive(:duration).and_return(1)
76
76
  end
77
77
 
78
78
  it { expect(action).to eq(parser.duration) }
@@ -82,7 +82,7 @@ describe LinkThumbnailer::VideoParser do
82
82
  context 'when do not respond to duration' do
83
83
 
84
84
  before do
85
- parser.stub(:duration).and_raise(NoMethodError)
85
+ allow(parser).to receive(:duration).and_raise(NoMethodError)
86
86
  end
87
87
 
88
88
  it { expect(action).to be_nil }
@@ -98,7 +98,7 @@ describe LinkThumbnailer::VideoParser do
98
98
  context 'when respond to provider' do
99
99
 
100
100
  before do
101
- parser.stub(:provider).and_return(1)
101
+ allow(parser).to receive(:provider).and_return(1)
102
102
  end
103
103
 
104
104
  it { expect(action).to eq(parser.provider) }
@@ -108,7 +108,7 @@ describe LinkThumbnailer::VideoParser do
108
108
  context 'when do not respond to provider' do
109
109
 
110
110
  before do
111
- parser.stub(:provider).and_raise(NoMethodError)
111
+ allow(parser).to receive(:provider).and_raise(NoMethodError)
112
112
  end
113
113
 
114
114
  it { expect(action).to be_nil }
@@ -124,7 +124,7 @@ describe LinkThumbnailer::VideoParser do
124
124
  context 'when respond to embed_code' do
125
125
 
126
126
  before do
127
- parser.stub(:embed_code).and_return('')
127
+ allow(parser).to receive(:embed_code).and_return('')
128
128
  end
129
129
 
130
130
  it { expect(action).to eq(parser.embed_code) }
@@ -134,7 +134,7 @@ describe LinkThumbnailer::VideoParser do
134
134
  context 'when do not respond to embed_code' do
135
135
 
136
136
  before do
137
- parser.stub(:embed_code).and_raise(NoMethodError)
137
+ allow(parser).to receive(:embed_code).and_raise(NoMethodError)
138
138
  end
139
139
 
140
140
  it { expect(action).to be_nil }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: link_thumbnailer
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pierre-Louis Gottfrois
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-27 00:00:00.000000000 Z
11
+ date: 2017-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -28,22 +28,16 @@ dependencies:
28
28
  name: json
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.7.7
34
31
  - - "~>"
35
32
  - !ruby/object:Gem::Version
36
- version: '1.8'
33
+ version: '2.1'
37
34
  type: :runtime
38
35
  prerelease: false
39
36
  version_requirements: !ruby/object:Gem::Requirement
40
37
  requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: 1.7.7
44
38
  - - "~>"
45
39
  - !ruby/object:Gem::Version
46
- version: '1.8'
40
+ version: '2.1'
47
41
  - !ruby/object:Gem::Dependency
48
42
  name: rake
49
43
  requirement: !ruby/object:Gem::Requirement
@@ -64,56 +58,56 @@ dependencies:
64
58
  requirements:
65
59
  - - "~>"
66
60
  - !ruby/object:Gem::Version
67
- version: '1.6'
61
+ version: '1.7'
68
62
  type: :runtime
69
63
  prerelease: false
70
64
  version_requirements: !ruby/object:Gem::Requirement
71
65
  requirements:
72
66
  - - "~>"
73
67
  - !ruby/object:Gem::Version
74
- version: '1.6'
68
+ version: '1.7'
75
69
  - !ruby/object:Gem::Dependency
76
70
  name: net-http-persistent
77
71
  requirement: !ruby/object:Gem::Requirement
78
72
  requirements:
79
73
  - - "~>"
80
74
  - !ruby/object:Gem::Version
81
- version: '2.9'
75
+ version: '3.0'
82
76
  type: :runtime
83
77
  prerelease: false
84
78
  version_requirements: !ruby/object:Gem::Requirement
85
79
  requirements:
86
80
  - - "~>"
87
81
  - !ruby/object:Gem::Version
88
- version: '2.9'
82
+ version: '3.0'
89
83
  - !ruby/object:Gem::Dependency
90
84
  name: video_info
91
85
  requirement: !ruby/object:Gem::Requirement
92
86
  requirements:
93
87
  - - "~>"
94
88
  - !ruby/object:Gem::Version
95
- version: '2.6'
89
+ version: '2.7'
96
90
  type: :runtime
97
91
  prerelease: false
98
92
  version_requirements: !ruby/object:Gem::Requirement
99
93
  requirements:
100
94
  - - "~>"
101
95
  - !ruby/object:Gem::Version
102
- version: '2.6'
96
+ version: '2.7'
103
97
  - !ruby/object:Gem::Dependency
104
98
  name: image_info
105
99
  requirement: !ruby/object:Gem::Requirement
106
100
  requirements:
107
101
  - - "~>"
108
102
  - !ruby/object:Gem::Version
109
- version: '1.0'
103
+ version: '1.1'
110
104
  type: :runtime
111
105
  prerelease: false
112
106
  version_requirements: !ruby/object:Gem::Requirement
113
107
  requirements:
114
108
  - - "~>"
115
109
  - !ruby/object:Gem::Version
116
- version: '1.0'
110
+ version: '1.1'
117
111
  description: Ruby gem generating thumbnail images from a given URL.
118
112
  email:
119
113
  - pierrelouis.gottfrois@gmail.com
@@ -123,6 +117,7 @@ extra_rdoc_files: []
123
117
  files:
124
118
  - ".gitignore"
125
119
  - ".rspec"
120
+ - ".ruby-version"
126
121
  - ".travis.yml"
127
122
  - CHANGELOG.md
128
123
  - Gemfile
@@ -156,6 +151,7 @@ files:
156
151
  - lib/link_thumbnailer/parser.rb
157
152
  - lib/link_thumbnailer/processor.rb
158
153
  - lib/link_thumbnailer/railtie.rb
154
+ - lib/link_thumbnailer/response.rb
159
155
  - lib/link_thumbnailer/scraper.rb
160
156
  - lib/link_thumbnailer/scrapers/base.rb
161
157
  - lib/link_thumbnailer/scrapers/default/base.rb
@@ -182,6 +178,8 @@ files:
182
178
  - spec/fixtures/default_from_body.html
183
179
  - spec/fixtures/default_from_meta.html
184
180
  - spec/fixtures/foo.png
181
+ - spec/fixtures/google_shift_jis.html
182
+ - spec/fixtures/google_utf8.html
185
183
  - spec/fixtures/og_not_valid_example.html
186
184
  - spec/fixtures/og_valid_example.html
187
185
  - spec/fixtures/og_valid_multi_image_example.html
@@ -203,6 +201,7 @@ files:
203
201
  - spec/models/website_spec.rb
204
202
  - spec/page_spec.rb
205
203
  - spec/processor_spec.rb
204
+ - spec/response_spec.rb
206
205
  - spec/scraper_spec.rb
207
206
  - spec/scrapers/base_spec.rb
208
207
  - spec/scrapers/opengraph/base_spec.rb
@@ -228,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
228
227
  version: '0'
229
228
  requirements: []
230
229
  rubyforge_project:
231
- rubygems_version: 2.5.1
230
+ rubygems_version: 2.6.10
232
231
  signing_key:
233
232
  specification_version: 4
234
233
  summary: Ruby gem ranking images from a given URL returning an object containing images
@@ -240,6 +239,8 @@ test_files:
240
239
  - spec/fixtures/default_from_body.html
241
240
  - spec/fixtures/default_from_meta.html
242
241
  - spec/fixtures/foo.png
242
+ - spec/fixtures/google_shift_jis.html
243
+ - spec/fixtures/google_utf8.html
243
244
  - spec/fixtures/og_not_valid_example.html
244
245
  - spec/fixtures/og_valid_example.html
245
246
  - spec/fixtures/og_valid_multi_image_example.html
@@ -261,6 +262,7 @@ test_files:
261
262
  - spec/models/website_spec.rb
262
263
  - spec/page_spec.rb
263
264
  - spec/processor_spec.rb
265
+ - spec/response_spec.rb
264
266
  - spec/scraper_spec.rb
265
267
  - spec/scrapers/base_spec.rb
266
268
  - spec/scrapers/opengraph/base_spec.rb